2019 / 08 / 18 - article (#php, #bad-idea-good-idea)

Identification and Authentication

Identification is recognizing that a given user is who he claims to be, whereas authentication is actually confirming that what he’s saying is right.

Those are two strictly different notions.

I’ll take the example of a users table with username and password.

Bad idea: Using passwords for identification

When you have your users table in your database, you have their username in clear text, so you can identify them (find the corresponding row associated to them).

What you musn’t do, however, is to try to identify them based on their password.

Remember: a password is an authentication mechanism, not an identification one.

The following SQL request to try to log in a user is then inherently wrong.

<?php
// $username and $password contains the cleartext username and password
$stmt = $db->prepare("SELECT id FROM users WHERE username = ? AND password = ?");
$stmt->execute([$username, $password]);

Not only it is wrong because it uses the password as an identification mechanism (as opposed to an authentication mechanism), but it also forces the developer to ignore password storing standards, as the stored password will forcibly be stored using an unsuitable, and unsecure, mechanism.

Yes, I’m really hammering the difference between identification and authentication, as it’s a core concept here.

Good idea: Only using the identifier for identification

As we saw, a user is identified by his username in our example above.

The good solution is then to try to find a row identified by this username, and then only to verify the password against the stored secure value.

As an example, the snippet below demonstrates a proper mechanism.

<?php
// $username and $password contains the cleartext username and password
$stmt = $db->prepare("SELECT id, password FROM users WHERE username = ?");
$row = $stmt->execute([$username])->fetch(PDO::FETCH_ASSOC);
$can_log_in = password_verify($password, $row['password']);

The $can_log_in variable will be set to true if the right username/password combination have been entered, and false otherwise.

Note that for the example’s sake, we omit error verification for the request, which obviously shouldn’t be done on a real website.