Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Cooking with Credentials

Eric Mann
January 14, 2021

Cooking with Credentials

There are many different ways to authenticate users to your application in PHP land. This talk will take a deep look into at least three different patterns for user authentication to keep your system secure. Everything we’ll be doing is password-focused, moving from the simplest methods to the most complex. We will only discuss actually-secure PHP authentication, but presenting multiple approaches will give you and your team superb flexibility when you move from theory to implementation.

Eric Mann

January 14, 2021
Tweet

More Decks by Eric Mann

Other Decks in Technology

Transcript

  1. 2
    Hello.
    Eric Mann
    Director of Engineering, Vacasa

    View full-size slide

  2. 4
    What is a password?
    Basic authentication flows
    Cooking with salt
    Cooking with pepper
    Socially distant passwords
    Further resources and study

    View full-size slide

  3. 5
    Something you know that is information kept secret from others
    but which can be used to authenticate your identity to a system
    requiring identity verification and security.

    View full-size slide

  4. 6
    1
    First, you identify yourself to the system. This could be by username, email address,
    account ID, or some other means agreed-upon with the system.
    2
    Next, you have to prove you are who you say you are by confirming some pre-shared,
    secret detail with the system.
    3
    If everything lines up, you’re authenticated and logged in!

    View full-size slide

  5. 8
    Lorem ipsum dolor sit amet,
    consectetur adipiscing elit.
    Fusce elit ex, consequat et
    tincidunt non, pharetra non.
    Lorem ipsum dolor sit amet,
    consectetur adipiscing elit.
    Fusce elit ex, consequat et
    tincidunt non, pharetra non.

    View full-size slide

  6. 11
    Lorem ipsum dolor sit amet,
    consectetur adipiscing elit.
    Fusce elit ex, consequat et
    tincidunt non, pharetra non.
    Lorem ipsum dolor sit amet,
    consectetur adipiscing elit.
    Fusce elit ex, consequat et
    tincidunt non, pharetra non.
    To prevent rainbow table lookup attacks, it’s best to add a unique, random salt to each password
    during hashing. This dramatically slows brute force attacks and further protects your users.

    View full-size slide

  7. 12
    $hash = password_hash(/** ... **/, PASSWORD_DEFAULT);
    /** ... **/
    if (password_verify(/** ... **/, $hash) {
    // ...
    }

    View full-size slide

  8. 14
    Lorem ipsum dolor sit amet,
    consectetur adipiscing elit.
    Fusce elit ex, consequat et
    tincidunt non, pharetra non.
    Lorem ipsum dolor sit amet,
    consectetur adipiscing elit.
    Fusce elit ex, consequat et
    tincidunt non, pharetra non.
    Even with salting, you still send the plaintext of a password over the wire to the server. If the
    server is misconfigured or too chatty in the logs, this plaintext could be inadvertently leaked.
    const pepper = new TextEncoder().encode('...');
    async function getKeyMaterial(password) {
    let encoder = new TextEncoder();
    return window.crypto.subtle.importKey(
    'raw',
    encoder.encode(password),
    'PBKDF2',
    false,
    ['deriveBits']
    );
    }

    View full-size slide

  9. 15
    Lorem ipsum dolor sit amet,
    consectetur adipiscing elit.
    Fusce elit ex, consequat et
    tincidunt non, pharetra non.
    Lorem ipsum dolor sit amet,
    consectetur adipiscing elit.
    Fusce elit ex, consequat et
    tincidunt non, pharetra non.
    async function pepperPassword(password) {
    let keyMaterial = await getKeyMaterial(password);
    let keyBuffer = await window.crypto.subtle.deriveBits(
    {
    'name': 'PBKDF2',
    'salt': pepper,
    'iterations': 100000,
    'hash': 'SHA-256'
    },
    keyMaterial,
    256
    );
    let keyArray = Array.from(new Uint8Array(keyBuffer));
    return keyArray.map(b => b.toString(16).padStart(2, '0')).join('');
    }

    View full-size slide

  10. 16
    Lorem ipsum dolor sit amet,
    consectetur adipiscing elit.
    Fusce elit ex, consequat et
    tincidunt non, pharetra non.
    Lorem ipsum dolor sit amet,
    consectetur adipiscing elit.
    Fusce elit ex, consequat et
    tincidunt non, pharetra non.
    peppered = await pepperPassword('...');

    View full-size slide

  11. 18
    Lorem ipsum dolor sit amet,
    consectetur adipiscing elit.
    Fusce elit ex, consequat et
    tincidunt non, pharetra non.
    Lorem ipsum dolor sit amet,
    consectetur adipiscing elit.
    Fusce elit ex, consequat et
    tincidunt non, pharetra non.

    View full-size slide

  12. 19
    $salt = random_bytes(SODIUM_CRYPTO_PWHASH_SALTBYTES);
    $seed = sodium_crypto_pwhash(/* ... */);
    $keypair = sodium_crypto_kx_seed_keypair($seed);
    $public_key = sodium_crypto_kx_publickey($keypair);
    // POST this data to the server to register
    $registration = [
    'identifier' => $email,
    'salt' => sodium_bin2hex($salt),
    'public_key' => sodium_bin2hex($public_key)
    ];

    View full-size slide

  13. 20
    $user = get_user_from_database($email);
    $keypair = sodium_crypto_kx_keypair();
    $public_key = sodium_crypto_kx_publickey($keypair);
    $keys = sodium_crypto_kx_server_session_keys($keypair, $user->key);
    $client_secret = $keys[1];
    $server_secret = $keys[0];
    $message = random_bytes(32);
    $hash = sodium_crypto_generichash($message, $server_secret);
    $proof = sodium_bin2hex($message . $hash);

    View full-size slide

  14. 21
    $keys = sodium_crypto_kx_server_session_keys($keypair, $server_key);
    $client_secret = $keys[0];
    $server_secret = $keys[1];
    $server_proof = sodium_hex2bin($server_proof);
    $message = substr($server_proof, 0, 32);
    $hash = substr($server_proof, 32);
    if (!hash_equals(
    sodium_crypto_generichash($message, $server_secret), $hash
    )) {
    exit;
    }

    View full-size slide

  15. 22
    $keys = sodium_crypto_kx_server_session_keys($keypair, $server_key);
    $client_secret = $keys[0];
    $server_secret = $keys[1];
    /* ... */
    $message = random_bytes(32);
    $hash = sodium_crypto_generichash($message, $client_secret);
    $proof = sodium_bin2hex($message . $hash);

    View full-size slide

  16. 23
    $client_proof = sodium_hex2bin($proof);
    $message = substr($client_proof, 0, 32);
    $hash = substr($client_proof, 32);
    if (!hash_equals(
    sodium_crypto_generichash($message, $client_secret), $hash
    )) {
    exit;
    }
    // Store the user's email in a session for subsequent requests
    $_SESSION['identifier'] = $email;

    View full-size slide