PHP: implementare l'autenticazione a due fattori

PHP: implementare l'autenticazione a due fattori

In questo articolo mostreremo come implementare l'autenticazione a due fattori con PHP.

Useremo l'approccio procedurale in modo da evidenziare al massimo i vari passaggi logici.

Per il database MySQL abbiamo bisogno di due tabelle, una per gli utenti ed una per i codici di autenticazione. La tabella con i codici avrà un campo user_id per il collegamento con la tabella utenti ed un campo created_at che ci permetterà di capire se il codice è scaduto.

Nell'autenticazione a due fattori l'utente deve superare due verifiche. La prima riguarda le sue credenziali, come nome utente e password, che verranno validate subito.

session_start();

require_once 'lib/connection.php';
include_once 'lib/config.php';

global $db;

if(isset($_SESSION['error'])) {
    unset($_SESSION['error']);
}

$username = trim($_POST['username']);
$password = md5(trim($_POST['password']));

$login_results = $db->getResults("SELECT * FROM users WHERE email = '$username' AND password = '$password'");

if(count($login_results) === 0) {
    $_SESSION['error'] = 'Invalid login.';
    $redirect = BASE_URL;
    header("Location: $redirect");
    exit;
}

$_SESSION['user'] = $login_results[0]['id'];
$redirect = BASE_URL . 'second-step.php';
header("Location: $redirect");
exit;

Se l'utente ha inserito credenziali non valide, non può proseguire oltre e viene reindirizzato alla pagina iniziale di login con un messaggio di errore salvato nella sessione. Usiamo la sessione per i messaggi onde evitare di dover inserire query string negli URL di redirect.

A questo punto abbiamo un utente valido, quindi salviamo il suo ID nella sessione e lo reindirizziamo al secondo step, dove viene generato e salvato il codice di autenticazione e tale codice viene inviato via e-mail all'utente.

session_start();
require_once 'lib/connection.php';
include_once 'lib/config.php';

global $db;

if(!isset($_SESSION['user'])) {
    $_SESSION['error'] = 'Invalid login.';
    $redirect = BASE_URL;
    header("Location: $redirect");
    exit;
}

if(!isset($_SESSION['auth-error'])) {

    $user_id = (int)$_SESSION['user'];
    $auth_code = strval(mt_rand(100000, 999999));
    $user_email_results = $db->getResults("SELECT email FROM users WHERE id = $user_id");
    $query = "INSERT INTO auth_codes (value, user_id) VALUES ('$auth_code',$user_id)";

    $db->query($query);
    mail($user_email_results[0]['email'], 'Your Auth Code', "Your Auth Code is: $auth_code", "From: PHP Tutorial <noreply@phptutorial.it>\r\n");

}

Ora non ci resta che verificare se il codice che l'utente andrà ad inserire è valido, ossia è 1) presente nel database e 2) non è scaduto. In ogni caso il codice verrà cancellato a verifiche concluse. Se non ci sono errori, l'utente verrà reindirizzato sulla sua bacheca.

session_start();
require_once 'lib/connection.php';
include_once 'lib/config.php';

global $db;

if(!isset($_SESSION['user'])) {
    $_SESSION['error'] = 'Invalid login.';
    $redirect = BASE_URL;
    header("Location: $redirect");
    exit;
}

if(isset($_SESSION['auth-error'])) {
    unset($_SESSION['auth-error']);
}

$code = trim($_POST['code']);
$user_id = (int) $_SESSION['user'];
$code_results = $db->getResults("SELECT * FROM auth_codes WHERE value = '$code' AND user_id = $user_id");
$delete_query = "DELETE FROM auth_codes WHERE value = '$code' AND user_id = $user_id";

if(count($code_results) === 0) {
    $_SESSION['auth-error'] = 'Invalid code.';
    $redirect = BASE_URL . 'second-step.php';
    header("Location: $redirect");
    exit;
}

$created_at = strtotime($code_results[0]['created_at']);
$expires = 60 * 15;

if(time() - $created_at > $expires) {
    $_SESSION['auth-error'] = 'Code expired.';
    $redirect = BASE_URL . 'second-step.php';
    $db->query($delete_query);
    header("Location: $redirect");
    exit;
}

$db->query($delete_query);
$redirect = BASE_URL . 'logged-in.php';
header("Location: $redirect");
exit;

Volendo perfezionare l'implementazione, si può usare un gateway esterno come Clickatell per l'invio di un SMS con il codice di autenticazione in luogo dell'e-mail.

Torna su