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

Criando mecanismos de autenticação seguros

Criando mecanismos de autenticação seguros

Uma das partes mais básicas de um sistema é seu processo de login. E por ser algo que não agrega valor direto ao negócio, acabamos não gastando o tempo necessário para criar um fluxo realmente seguro, fazendo com que ele se torne o principal vetor de ataques de nossa aplicação. Iremos aprender como criar mecanismos seguros de autenticação, utilizando CSRF de forma correta, CAPTCHA, duplo fator de autenticação, prevenção à enumeração de usuários e autenticação em APIs. Veremos também diversas dicas de como implementar as arriscadas (mas muitas vezes necessárias) funções 'Permanecer logado' e 'Esqueci a senha'.

Vinícius Campitelli

October 19, 2019
Tweet

More Decks by Vinícius Campitelli

Other Decks in Technology

Transcript

  1. QUEM SOU EU? QUEM SOU EU? Vinícius Campitelli Membro do

    Sócio-fundador do GitHub/Twitter: Slides: PHPSP Curseduca @vcampitelli viniciuscampitelli.com 2
  2. AGENDA AGENDA Protegendo CSRF de forma correta; CAPTCHA; Duplo fator

    de autenticação; Prevenção à enumeração de usuários; Funcionalidade "Permanecer logado"; Funcionalidade "Esqueci a senha". Login via terceiros; Autenticação em APIs. 3
  3. O QUE É NA PRÁTICA? O QUE É NA PRÁTICA?

    Imagine que você esteja logado em um site site1.com 4 . 2
  4. O QUE É NA PRÁTICA? O QUE É NA PRÁTICA?

    Imagine que você esteja logado em um site site1.com Então acessa o site site2.com 4 . 2
  5. O QUE É NA PRÁTICA? O QUE É NA PRÁTICA?

    Imagine que você esteja logado em um site site1.com Então acessa o site site2.com E no site site2.com, há uma requisição POST site1.com/transferir? conta=1234&valor=1000 4 . 2
  6. O QUE É NA PRÁTICA? O QUE É NA PRÁTICA?

    Imagine que você esteja logado em um site site1.com Então acessa o site site2.com E no site site2.com, há uma requisição POST site1.com/transferir? conta=1234&valor=1000 Como você está autenticado no site1, essa requisição será válida 4 . 2
  7. O QUE É NA PRÁTICA? O QUE É NA PRÁTICA?

    Imagine que você esteja logado em um site site1.com Então acessa o site site2.com E no site site2.com, há uma requisição POST site1.com/transferir? conta=1234&valor=1000 Como você está autenticado no site1, essa requisição será válida E você irá perder seu precioso dinheiro! 4 . 2
  8. Para garantir que um atacante não faça um usuário passar-se

    por ele Mas por que eu preciso disso na tela de login? 4 . 3
  9. COMO SE PROTEGER? COMO SE PROTEGER? Crie uma sessão "falsa"

    Gere um token para ele e guarde-o nessa sessão 4 . 4
  10. COMO SE PROTEGER? COMO SE PROTEGER? Crie uma sessão "falsa"

    Gere um token para ele e guarde-o nessa sessão Coloque esse token junto da requisição (em campos do formulário ou cabeçalhos do AJAX) 4 . 4
  11. COMO SE PROTEGER? COMO SE PROTEGER? Crie uma sessão "falsa"

    Gere um token para ele e guarde-o nessa sessão Coloque esse token junto da requisição (em campos do formulário ou cabeçalhos do AJAX) Na página que recebe a ação de login, verifique se o token enviado é o mesmo da sessão 4 . 4
  12. COMO SE PROTEGER? COMO SE PROTEGER? Crie uma sessão "falsa"

    Gere um token para ele e guarde-o nessa sessão Coloque esse token junto da requisição (em campos do formulário ou cabeçalhos do AJAX) Na página que recebe a ação de login, verifique se o token enviado é o mesmo da sessão Se quiser, verifique também o cabeçalho Referer (ou Origin) da requisição para garantir que a origem é do seu site 4 . 4
  13. PREMISSAS E RECOMENDAÇÕES PREMISSAS E RECOMENDAÇÕES O token não pode

    se repetir entre usuários diferentes, então é importante utilizar um (Cryptographically Secure Pseudo-Random Number Generator) CSPRNG 4 . 5
  14. PREMISSAS E RECOMENDAÇÕES PREMISSAS E RECOMENDAÇÕES O token não pode

    se repetir entre usuários diferentes, então é importante utilizar um (Cryptographically Secure Pseudo-Random Number Generator) Não pode ser muito pequeno (para evitar brute force) CSPRNG 4 . 5
  15. PREMISSAS E RECOMENDAÇÕES PREMISSAS E RECOMENDAÇÕES O token não pode

    se repetir entre usuários diferentes, então é importante utilizar um (Cryptographically Secure Pseudo-Random Number Generator) Não pode ser muito pequeno (para evitar brute force) Não pode aparecer nos logs do servidor CSPRNG 4 . 5
  16. PREMISSAS E RECOMENDAÇÕES PREMISSAS E RECOMENDAÇÕES O token não pode

    se repetir entre usuários diferentes, então é importante utilizar um (Cryptographically Secure Pseudo-Random Number Generator) Não pode ser muito pequeno (para evitar brute force) Não pode aparecer nos logs do servidor Não pode estar na URL CSPRNG 4 . 5
  17. PREMISSAS E RECOMENDAÇÕES PREMISSAS E RECOMENDAÇÕES (CONTINUAÇÃO) (CONTINUAÇÃO) Você pode

    gerar tokens a cada requisição ao invés de um por sessão, mas isso interfere na usabilidade do sistema (por exemplo, o botão "Voltar" do navegador irá causar uma falha de CSRF) 4 . 6
  18. PREMISSAS E RECOMENDAÇÕES PREMISSAS E RECOMENDAÇÕES (CONTINUAÇÃO) (CONTINUAÇÃO) Você pode

    gerar tokens a cada requisição ao invés de um por sessão, mas isso interfere na usabilidade do sistema (por exemplo, o botão "Voltar" do navegador irá causar uma falha de CSRF) Se você quiser uma abordagem stateless, pode gerar um token criptografado com o Session ID do usuário e um timestamp, por exemplo 4 . 6
  19. REFERÊNCIAS REFERÊNCIAS BIBLIOTECAS BIBLIOTECAS OWASP CheatSheet de prevenção de CSRF

    Paper "Robust Defenses for Cross-Site Request Forgery" de Stanford symfony/security-csrf paragonie/anti-csrf 4 . 7
  20. HOTP HOTP é um algoritmo baseado em que gera uma

    senha a partir de uma chave HMAC-based One-Time Password HMAC 6 . 2
  21. HOTP HOTP é um algoritmo baseado em que gera uma

    senha a partir de uma chave Para garantir a unicidade (afinal, há One-Time no nome), é incrementado um contador a cada geração/checagem do valor HMAC-based One-Time Password HMAC 6 . 2
  22. TOTP TOTP é uma extensão do HOTP, que utiliza o

    horário atual ao invés do contador para a unicidade Time-based One-Time Password 6 . 3
  23. TOTP TOTP é uma extensão do HOTP, que utiliza o

    horário atual ao invés do contador para a unicidade Geralmente, há uma janela de 30 segundos de validade da senha Time-based One-Time Password 6 . 3
  24. public function __construct() { $this->authenticator = new \Sonata\GoogleAuthenticator\G $this->secret =

    getAuthenticatorSecretFromSomewhere(); } public function check(string $code) : bool { return $this->authenticator->checkCode($this->secret, $c } public fuction generateSecret() : string { return $this->authenticator->generateSecret() 6 . 5
  25. BLOQUEIE O USUÁRIO APÓS ALGUMAS TENTATIVAS BLOQUEIE O USUÁRIO APÓS

    ALGUMAS TENTATIVAS INVÁLIDAS DO TOKEN DO 2FA! INVÁLIDAS DO TOKEN DO 2FA! 6 . 6
  26. Tokens de 6 dígitos possuem 1.000.000 de combinações (000000 -

    999999) Se um atacante fizer 1 requisição por segundo ao seu sistema, ele irá demorar 1 milhão de segundos para testar todas as combinações possíveis 6 . 7
  27. Tokens de 6 dígitos possuem 1.000.000 de combinações (000000 -

    999999) Se um atacante fizer 1 requisição por segundo ao seu sistema, ele irá demorar 1 milhão de segundos para testar todas as combinações possíveis 1000000 / 86400 = 11.574074074 6 . 7
  28. Tokens de 6 dígitos possuem 1.000.000 de combinações (000000 -

    999999) Se um atacante fizer 1 requisição por segundo ao seu sistema, ele irá demorar 1 milhão de segundos para testar todas as combinações possíveis 1000000 / 86400 = 11.574074074 Ou seja, o token será quebrado em menos de 12 dias 6 . 7
  29. Tokens de 6 dígitos possuem 1.000.000 de combinações (000000 -

    999999) Se um atacante fizer 1 requisição por segundo ao seu sistema, ele irá demorar 1 milhão de segundos para testar todas as combinações possíveis 1000000 / 86400 = 11.574074074 Ou seja, o token será quebrado em menos de 12 dias Mas que atacante só faz 1 requisição por segundo? 6 . 7
  30. REFERÊNCIAS, BIBLIOTECAS E SOLUÇÕES REFERÊNCIAS, BIBLIOTECAS E SOLUÇÕES Why You

    Don't Need 2 Factor Authentication SMS-based two-factor authentication is not safe sonata-project/google-authenticator twilio/authy-php Twilio SMS Nexmo SMS 6 . 8
  31. O que um sistema que rode o código a seguir

    pode dar de informação a um atacante? 7 . 2
  32. public function login(string $username, string $password) : { $user =

    $this->findByUsername($username); if (! $user) { return false; } return $this->verifyPassword($password, $user->getPasswo } 7 . 3
  33. É possível saber que usuários existem em sua aplicação através

    de timing attack Modifique o código para que a custosa função verifyPassword seja sempre invocada! 7 . 4
  34. public function login(string $username, string $password) : { $storedPassword =

    $this->generateFakePassword(); $user = $this->findByUsername($username); if ($user) { $storedPassword = $user->getPassword(); } return ($this->verifyPassword($password, $storedPassword && ($user !== null); } 7 . 5
  35. Será que não estamos exagerando? É realmente possível ver essa

    diferença? Vamos testar, então! Executando os scripts login-user-enumeration.php e login-user-enumeration-fixed.php 7 . 6
  36. SOLUÇÃO MAIS SIMPLES SOLUÇÃO MAIS SIMPLES Gerar um token único

    Guardá-lo no cookie do browser do usuário 8 . 2
  37. SOLUÇÃO MAIS SIMPLES SOLUÇÃO MAIS SIMPLES Gerar um token único

    Guardá-lo no cookie do browser do usuário Salvar esse token em um banco de dados relacionando ao usuário 8 . 2
  38. SOLUÇÃO MAIS SIMPLES SOLUÇÃO MAIS SIMPLES Gerar um token único

    Guardá-lo no cookie do browser do usuário Salvar esse token em um banco de dados relacionando ao usuário Sempre que é feito o acesso à tela de login, comparar os tokens 8 . 2
  39. CUIDADOS CUIDADOS Garanta que o token será único para o

    usuário e não previsível (novamente, use ) CSPRNG 8 . 3
  40. CUIDADOS CUIDADOS Garanta que o token será único para o

    usuário e não previsível (novamente, use ) Faça comparações que tenham tempo fixo para prevenir timing attacks (por exemplo, hash_equals()) CSPRNG 8 . 3
  41. CUIDADOS CUIDADOS Garanta que o token será único para o

    usuário e não previsível (novamente, use ) Faça comparações que tenham tempo fixo para prevenir timing attacks (por exemplo, hash_equals()) Precisa ser eficiente, para não permitir CSPRNG DoS 8 . 3
  42. 1. Prefixe o token com um identificador (NÃO use diretamente

    o ID do usuário) $identifier = hash('sha256', $userId); // 64 bytes $token = bin2hex(random_bytes(32)); // 64 bytes $cookie = $identifier . $token; 8 . 5
  43. 2. Crie uma tabela no banco de dados com o

    identificador acima e somente o hash do token ao invés dele CREATE TABLE `rememberme_tokens` ( `id` int unsigned AUTO_INCREMENT, `identifier` char(64) NOT NULL, `token_hash` char(128) NOT NULL, PRIMARY KEY (`id`) ) $hashedToken = hash('sha512', $token); $pdo->prepare('INSERT INTO rememberme_tokens (NULL, ?, ?)') ->execute([$identifier, $hashedToken]); 8 . 6
  44. 3. Ao consultar o banco, utilize apenas o identificador $query

    = $pdo->prepare( 'SELECT `token_hash` FROM `rememberme_tokens` WHERE `identifier` = ? LIMIT 1' ); $hashFromDatabase = $query->fetch(PDO::FETCH_COLUMN); 8 . 7
  45. 4. Faça o hash do token informado no cookie do

    usuário e compare-o com o que está no banco (com hash_equals()) $hashedToken = hash('sha512', substr($cookie, 64)); if (hash_equals($hashedToken, $hashFromDatabase)) { redirectToHome(); } else { redirectToLogin(); } 8 . 8
  46. REFERÊNCIA E BIBLIOTECA REFERÊNCIA E BIBLIOTECA "Remember Me" - Long-Term

    Persistent Authentication (Paragon IE) psecio/gatekeeper 8 . 9
  47. PRECAUÇÕES PRECAUÇÕES Perguntas secretas estão cada vez menos secretas por

    causa das redes sociais Emails não são sempre encriptados 9 . 2
  48. PRECAUÇÕES PRECAUÇÕES Perguntas secretas estão cada vez menos secretas por

    causa das redes sociais Emails não são sempre encriptados Emails podem não chegar 9 . 2
  49. PRECAUÇÕES PRECAUÇÕES Perguntas secretas estão cada vez menos secretas por

    causa das redes sociais Emails não são sempre encriptados Emails podem não chegar SMS não são confiáveis 9 . 2
  50. PREPARE-SE! PREPARE-SE! Realmente avalie se seu sistema precisa dessa funcionalidade

    automática NÃO crie uma nova senha e envie por email 9 . 3
  51. PREPARE-SE! PREPARE-SE! Realmente avalie se seu sistema precisa dessa funcionalidade

    automática NÃO crie uma nova senha e envie por email NÃO mande a senha em texto plano por email 9 . 3
  52. PREPARE-SE! PREPARE-SE! Realmente avalie se seu sistema precisa dessa funcionalidade

    automática NÃO crie uma nova senha e envie por email NÃO mande a senha em texto plano por email (o quêêê?????) 9 . 3
  53. PREPARE-SE! PREPARE-SE! Realmente avalie se seu sistema precisa dessa funcionalidade

    automática NÃO crie uma nova senha e envie por email NÃO mande a senha em texto plano por email (o quêêê?????) Se for fornecido um usuário que não existe na base, não o avise! 9 . 3
  54. TENTATIVA DE TENTATIVA DE SOLUÇÃO SOLUÇÃO Utilize a do token

    descrita no slide de "Permanecer logado" mesma abordagem 9 . 4
  55. TENTATIVA DE TENTATIVA DE SOLUÇÃO SOLUÇÃO Utilize a do token

    descrita no slide de "Permanecer logado" Coloque um tempo limite para expiração do token mesma abordagem 9 . 4
  56. TENTATIVA DE TENTATIVA DE SOLUÇÃO SOLUÇÃO Utilize a do token

    descrita no slide de "Permanecer logado" Coloque um tempo limite para expiração do token Envie o código para o usuário (se for por email, criptografe!) mesma abordagem 9 . 4
  57. REFERÊNCIAS E BIBLIOTECA REFERÊNCIAS E BIBLIOTECA Account Recovery (Paragon IE)

    Untangling the Forget-Me Knot: Secure Account Recovery Made Simple paragonie/gpg-mailer 9 . 5
  58. REFERÊNCIAS E BIBLIOTECAS REFERÊNCIAS E BIBLIOTECAS Facebook SDK - Login

    Google Login TwitterOAuth Login GitHub Login openid/php-openid Auth0 10 . 3
  59. DICAS DICAS Use HTTPS sempre (♥ ) Não crie seu

    próprio sistema de autenticação, utilize um protocolo já conhecido ( , , entre outros) Let's Encrypt OpenID OAuth 2.0 11 . 2
  60. DICAS DICAS Use HTTPS sempre (♥ ) Não crie seu

    próprio sistema de autenticação, utilize um protocolo já conhecido ( , , entre outros) Para geração dos identificadores do usuário (por exemplo, client secret no OAuth 2) utilize Let's Encrypt OpenID OAuth 2.0 CSPRNG 11 . 2
  61. DICAS DICAS (CONTINUAÇÃO) (CONTINUAÇÃO) Para tokens, utilize ou Se for

    usar JWT, garanta que seu sistema não permita um algorithm=none JWT Paseto 11 . 3
  62. DICAS DICAS (CONTINUAÇÃO) (CONTINUAÇÃO) Para tokens, utilize ou Se for

    usar JWT, garanta que seu sistema não permita um algorithm=none Mesmo se usar um , não deixe seus microserviços sem autenticação. Repasse o token para todos! JWT Paseto API Gateway 11 . 3
  63. REFERÊNCIAS REFERÊNCIAS BIBLIOTECAS BIBLIOTECAS Critical vulnerabilities in JSON Web Token

    libraries Token Based Authentication Made Easy lcobucci/jwt thephpleague/oauth2-server 11 . 4