Secure PHP password (Password verification)

Asked

Viewed 1,825 times

0

How do I check if my password is secure or not? I have a code in PHP checking, but I don’t know how to do it password check. She should be:

  1. Have more than 6 characters (Made in HTML);
  2. Contain upper and lower case letters;
  3. Contain Numbers.
<?php
 use PHPMailer\PHPMailer\Exception;
    use PHPMailer\PHPMailer\PHPMailer;

    session_start();

    require '../PHPMailer/src/Exception.php';
    require '../PHPMailer/src/PHPMailer.php';
    require '../PHPMailer/src/SMTP.php';

    $avatar = "images/avatar/default.png";

    $nome = "";
    $email= "";
    $senha = "";
    $SalvarSenha = "";
    $receberEmail = "";

    include ("../../assets/util/conn.php"); // Minha conexao PDO

    //Verificar se foi metodo POST Usado e se o Metodo veido do FORM Registrar
    if($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['Registrar']))
    {
        unset($_SESSION['email']);
        unset($_SESSION['status']);

        $nome = addslashes($_POST['nome']);
        $email = addslashes($_POST['email']);
        $senha = md5(addslashes($_POST['senha']));
        $receberEmail = isset($_POST['termos']) ? 1 : 0;
        $SalvarSenha = $_POST['senha'];

        //Verificar as senhas contem numero e letra ERRADO AINDA
        if (!preg_match('/[A-Za-z]/', $SalvarSenha) || !preg_match('/[0-9]/', $SalvarSenha))
        {
            echo "Senha tem que conter letras e números.";
        }
.
.
.
?>

1 answer

2


The brackets define a character class. When you do [A-Za-z], that means "a letter of a to z or of A to Z". That is, it can be either a lowercase or a uppercase letter.

So if it has a capital letter, but no lower case letter (or vice versa), this regex lets it pass. To oblige you to have at least one of each (you must have a capital letter and a lower case), and also require that you also have a number, and that has at least 6 characters, you have 2 alternatives.

1- check each condition separately

For every condition, we can make a preg_match different. The detail is the criterion "must have at least 6 characters". We already know which letters and numbers are required, but which characters can the password have? Will it allow special characters? Accents? Emojis? And so on. The more options, more difficult is the regex.

Just to simplify, let’s assume that the password can have letters, numbers, _, @ and $. This is just to illustrate, since limiting too many characters allowed decreases the amount of passwords possible, but allowing too much can lead to cases where the user will have difficulties typing again the password, as discussed in this question from Security.SE.

Anyway, for letters, numbers and _ we can use the shortcut \w. Already to @ and $, we can use the characters themselves, then the expression is [\w$@] (again, this is just to simplify the example - add all the characters you need inside the brackets). And for the size, we use {6,}, meaning "6 or more occurrences". That is, it must have at least 6 characters. The code would look like this:

function senhaValida($senha) {
    return preg_match('/[a-z]/', $senha) // tem pelo menos uma letra minúscula
     && preg_match('/[A-Z]/', $senha) // tem pelo menos uma letra maiúscula
     && preg_match('/[0-9]/', $senha) // tem pelo menos um número
     && preg_match('/^[\w$@]{6,}$/', $senha); // tem 6 ou mais caracteres
}

var_dump(senhaValida('aB1@xy$z')); // true
var_dump(senhaValida('aB1')); // false, não tem 6 caracteres
var_dump(senhaValida('AB1@XYZ')); // false, não tem letra minúscula
var_dump(senhaValida('ab1@xyz')); // false, não tem letra maiúscula
var_dump(senhaValida('ABc@xyz')); // false, não tem número

Note that for the size I also used the markers ^ and $, which means respectively the beginning and the end of the string. With this I guarantee that, from start to finish, there are at least 6 occurrences of the characters I defined (and only of these characters).

Other conditions do not require ^ and $, because I’m just checking if the characters exist at any position in the string.

The code prints out bool(true) for the first password, and bool(false) to others.


2-do everything in one regex only

For that, we have to use lookaheads. The idea of Lookahead is to check an expression, and then go back to where it was and proceed with the rest of the regex. It looks like this:

function senhaValida($senha) {
    return preg_match('/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])[\w$@]{6,}$/', $senha);
}

First we have ^ (the beginning of the string). Next we have a Lookahead, that begins with (?=. Within it we have .*[a-z], meaning "zero or more occurrences of any character" (.*), followed by a lowercase letter ([a-z]). That is, this Lookahead checks if there is a lowercase letter in the string.

The trick of Lookahead is that after it checks if the lowercase letter exists, it goes back to where it was (i.e., to the beginning of the string) and checks the rest of the expression. And the rest, we have another Lookahead to check if there is a capital letter, and then another to check if there is a number. If any of lookaheads fail, the regex as a whole also fails.

And then we have the expression that checks for at least 6 characters, followed by the end of the string ($). That is, it does all the checks of the previous example at once.

  • 1

    Thank you so much! It worked!

Browser other questions tagged

You are not signed in. Login or sign up in order to post.