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. 1

  2. 3

  3. 4 What is a password? Basic authentication flows Cooking with

    salt Cooking with pepper Socially distant passwords Further resources and study
  4. 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.
  5. 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!
  6. 7

  7. 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.
  8. 10

  9. 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.
  10. 12 $hash = password_hash(/** ... **/, PASSWORD_DEFAULT); /** ... **/

    if (password_verify(/** ... **/, $hash) { // ... }
  11. 13

  12. 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'] ); }
  13. 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(''); }
  14. 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('...');
  15. 17

  16. 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.
  17. 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) ];
  18. 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);
  19. 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; }
  20. 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);
  21. 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;
  22. 24

  23. 25

  24. 26

  25. 27

  26. 28