Quais práticas recomendadas devem ser empregadas em um script de login PHP?


27

Desejo reescrever meus scripts de login nos sites dos clientes para torná-los mais seguros. Quero saber quais as melhores práticas que posso implementar nisso. Os painéis de controle protegidos por senha estão em abundância, mas poucos parecem implementar as práticas recomendadas em termos de código, velocidade e segurança.

Eu vou estar usando PHP e um banco de dados MYSQL.

Eu costumava usar o md5, mas vejo que sha256 ou sha512 seria melhor (junto com hash e sal seguros).

Alguns scripts de logon registram o endereço IP durante toda a sessão ou até o agente do usuário, mas quero evitar isso, pois não é compatível com servidores proxy.

Também estou um pouco por trás da melhor prática no uso de sessões no PHP 5 (a última vez que li foi o PHP 4), portanto, algumas práticas recomendadas com isso seriam úteis.

Obrigado.


1
Jogue seu script no codereview.SE!
Chris

A ajuda do Chris CodeReview com clareza de código e afins. Definitivamente, você não deveria procurá-los por segurança. De qualquer forma, eles quase sempre lembram que você não deve rolar sozinho, que é basicamente a mesma resposta que ele terá em qualquer comunidade de programação no SE.
Alternatex

Respostas:


21

O melhor é não reinventar a roda. Mas, eu entendo, no mundo PHP, pode ser difícil encontrar um componente de alta qualidade que já faça isso (mesmo que eu tenha certeza de que as estruturas implementam essas coisas e suas implementações já foram testadas, sólidas, revisadas por código etc.) )

Se, por alguns motivos, você não puder usar uma estrutura, veja algumas sugestões:

Sugestões relacionadas à segurança

  • Use PBKDF2 ou Bcrypt, se puder . Está feito para isso.

    Fundamentação da petição: ambos os algoritmos podem tornar o processo de hash arbitrariamente lento, exatamente o que você deseja ao fazer o hash de senhas (alternativas mais rápidas significam uma força bruta mais fácil). Idealmente, você deve ajustar os parâmetros para que o processo se torne cada vez mais lento no mesmo hardware, enquanto um hardware novo e mais rápido é lançado.

  • Se não puder, pelo menos não use MD5 / SHA1. Nunca. Esqueça . Use SHA512, por exemplo. Use sal também.

    Justificativa: MD5 e SHA1 são muito rápidos. Se o invasor tiver acesso ao seu banco de dados contendo os hashes e possuir uma máquina (nem mesmo particularmente) poderosa, forçar brutalmente uma senha será rápido e fácil. Se não houver sais, as chances de o invasor encontrar a senha real aumentam (o que pode causar danos adicionais se a senha for reutilizada em outro lugar).

  • No PHP 5.5.0 e posterior, use password_hashe password_verify.

    Justificativa: chamar uma função fornecida pela estrutura é fácil, portanto, o risco de cometer um erro é reduzido. Com essas duas funções, você não precisa pensar em parâmetros diferentes, como o hash. A primeira função retorna uma única string que pode ser armazenada no banco de dados. A segunda função usa essa sequência para verificação de senha.

  • Proteja-se da força bruta . Se o usuário enviar uma senha errada quando já tiver enviado outra senha errada há 0,01 segundos, é um bom motivo para bloqueá-la. Embora os seres humanos possam digitar rápido, eles provavelmente não podem ser tão rápidos.

    Outra proteção seria definir um limite de falhas por hora. Se o usuário enviou 3600 senhas erradas em uma hora, uma senha por segundo, é difícil acreditar que seja um usuário legítimo.

    Fundamentação da petição: se suas senhas são divididas de maneira insegura, a força bruta pode ser muito eficaz. Se as senhas forem armazenadas com segurança, a força bruta ainda estará desperdiçando os recursos e a largura de banda da rede do servidor, causando desempenho inferior para usuários legítimos. A detecção de força bruta não é fácil de desenvolver e acertar, mas para qualquer sistema, exceto o minúsculo, vale totalmente a pena.

  • Não peça aos usuários que alterem suas senhas a cada quatro semanas. Isso é extremamente irritante e diminui a segurança, pois incentiva a segurança baseada em post-it.

    Fundamentação da petição: a ideia de que forçar a alteração de senhas a cada n semanas protege o sistema da força bruta está errada. Os ataques de força bruta geralmente são bem-sucedidos em segundos, minutos, horas ou dias, o que torna irrelevantes as alterações mensais da senha. Por outro lado, os usuários são ruins em lembrar senhas. Além disso, se eles precisarem alterá-los, eles tentarão usar senhas muito simples ou apenas anotarão suas senhas em post-its.

  • Audite tudo, sempre. Armazene logons, mas nunca armazene senhas no log de auditoria. Verifique se o log de auditoria não pode ser modificado (ou seja, você pode adicionar dados no final, mas não modificar os dados existentes). Verifique se os logs de auditoria estão sujeitos a backup regular. Idealmente, os logs devem ser armazenados em um servidor dedicado com acessos muito restritivos: se outro servidor for invadido, o invasor não poderá apagar os logs para ocultar sua presença (e o caminho percorrido durante o ataque).

  • Não lembre-se da credencial do usuário nos cookies, a menos que o usuário peça para fazê-lo (a caixa de seleção "Lembrar-me" deve estar desmarcada por padrão para evitar erros humanos).

Sugestões de facilidade de uso

  • Deixe o usuário lembrar a senha, se desejar, mesmo que a maioria dos navegadores já possua esse recurso.
  • Não use a abordagem do Google quando, em vez de solicitar o nome do usuário e a senha, às vezes for solicitado apenas o usuário, pois o nome do usuário já está sendo exibido em a <span/>. Os navegadores não podem preencher o campo de senha nesse caso (pelo menos o Firefox não pode fazer isso), portanto, força o logoff e o logon com um formulário comum preenchido pelo navegador.
  • Não use pop-ups habilitados para JavaScript para fazer logon. Ele quebra os recursos de lembrete de senha dos navegadores (e é uma droga em todos os casos).
  • Deixe o usuário digitar seu nome de usuário ou seu endereço de email . Quando me registro, às vezes o nome de usuário que desejo inserir já está em uso, então devo inventar um novo. Tenho todas as chances de esquecer esse nome em duas horas.
  • Sempre mantenha um link para o recurso "Esqueci minha senha" próximo ao formulário de logon. Não exibi-lo apenas quando o usuário não logou: o usuário que não lembra sua senha não tem idéia de que deve enviar uma senha errada para ver o link "Esqueci minha senha".
  • Não use segurança post-it .
  • Não invente regras estúpidas relacionadas à senha para torná-la mais fraca . Exemplo: "Sua senha deve começar com uma letra minúscula."; "Sua senha não pode conter espaços."

Não se deparar com bcrypt. Qual é o seu raciocínio para recomendar isso? Por que não MD5 / sha1? Obrigado pelo resto das sugestões!
Baritoneuk

O raciocínio é simples: bcrypté feito por pessoas altamente qualificadas. Também é testado, revisado, etc. Portanto, não há razão para implementar a mesma coisa. É como criar seu próprio algoritmo de criptografia para o seu site. * "Por que não md5 / sha1?": Veja por exemplo en.wikipedia.org/wiki/MD5#Security
Arseni Mourzenko

5
O bcrypt é lento e, como mencionado, foi implementado por profissionais. MD5 é um algoritmo de hash, não uma criptografia que não é exatamente a mesma coisa. Hashing rápido de um arquivo é bom, o md5 seria usado aqui ... o hash de uma senha não precisa ser tão rápido, o bcrypt pode ajudar aqui. Razão pela qual digo que isso é que a força bruta se torna mais difícil quando o algoritmo de criptografia é "lento".
Chris

2
@ baritoneuk: o mínimo é legal. Mas não posso contar quantos sites que visitei tiveram restrições, como comprimentos máximos , caracteres não alfanuméricos, etc. , eles estão apenas armazenando-o em seu banco de dados de forma clara.
Carson63000

1
@ Brian Ortiz: nem sempre. Às vezes, é uma boa idéia definir um limite. Se você não fizer isso, você testa se seu aplicativo funciona por algum tempo? Quão? Se você não testá-lo, como pode ter certeza de que está funcionando? Em vez disso, ao definir um limite para um valor razoável, como 100, você pode facilmente testar uma senha de 100 caracteres.
Arseni Mourzenko

6
  1. Seu site deve usar HTTPS. Em nenhum momento você deve apresentar uma página de login ou aceitar logins de uma conexão não criptografada.
  2. Seus cookies devem ser restritos apenas ao HTTP e restritos a conexões seguras se você usar HTTPS.
  3. O processo de login não deve demorar menos de 2 segundos (1 se você acha que 2 segundos é muito longo). Use um hash seguro ao armazenar e verificar senhas e use um sal mais difícil de adivinhar. Use bcryptse possível. Caso contrário, use algum outro tipo de hash iterado.
  4. Nunca nunca compor suas consultas de banco de dados de qualquer forma que requer o uso de funções como mysql_real_escape_string. Nunca use concatenação de strings para criar sua consulta. Use consultas preparadas e parametrizadas. A maioria, se não todos, os drivers de banco de dados para PHP é compatível. Se você não sabe como fazê-lo, passar algum tempo aprendendo como prepare, binde executeusando qualquer DB que você está usando. É a única maneira de se proteger contra a injeção de SQL. A DOP suporta isso.
  5. Incentive seus usuários a não usarem a mesma senha que eles usam em seus emails. Lembre-os de que, se o seu site estiver comprometido e se eles usarem a mesma senha nos dois lugares, alguém poderá invadir o email.

+1 para HTTPS, pois há cada vez mais tráfego nas redes Wi-Fi públicas. Mas eu discordo do ponto 3: 2 segundos é muito longo do ponto de vista dos usuários. 0,5 s. é ótimo, especialmente se outras técnicas de força anti-bruta forem usadas.
Arseni Mourzenko

Estou confuso no ponto número 4. Como você foge da convenção de escape de dados com mysql_real_escape_string? Todos os dados enviados pelo usuário não devem ser confiáveis ​​e filtrados de acordo.
Chrisw #

@chrisw: Sim, todas as entradas do usuário devem ser tratadas como se fossem maliciosas. Mas quando você usa consultas parametrizadas, é, sem nenhuma, a melhor maneira de interromper a injeção de SQL . Se você não estiver usando consultas preparadas e parametrizadas, estará vulnerável à injeção de SQL. mysql_real_escape_stringé falsa segurança - não é uma garantia. Consultas parametrizadas são.
greyfade

Concordo agora depois de fazer algumas leituras adicionais. A função: mysql_real_escape_string geralmente é segura para a maior parte, eu não consideraria uma responsabilidade ENORME, mas posso ver como o uso das instruções preparadas é muito mais eficiente.
Chrisw #

1
Você pode usar o DOP.
Felix G

1

Use um hash salgado de mão única (de preferência o SHA512 usando http://au2.php.net/manual/en/function.hash.php ) ... dessa maneira, se alguém hackear seu banco de dados, mesmo que conheça o sal , eles não podem extrair as senhas (sem uma tabela arco-íris, que seria muito longa para o SHA512).

Use HTTPS.

Não envie confirmações de nome de usuário / senha por e-mail de volta ao usuário quando ele se registrar.

Se você permitir cookies para 'lembrar de mim' - adicione um login extra para acessar as funções de administração e edição de perfil.

Se um usuário errar uma senha, não diga que a senha está errada (digamos que sempre tenha o 'nome de usuário ou senha errado') - dessa forma, menos pistas sobre o que são nomes de usuário válidos.

Tente implementar o nome de tela e o login - dessa forma, menos usuários exibirão seu nome de login nas listas de usuários.


Concordo totalmente com o fato de não enviar e-mails em texto sem formatação por e-mails. Perdi a conta das vezes que os sites fazem isso. Se você tiver 1 senha para todos os sites (o que, felizmente, não tenho), potencialmente todos os sites estarão comprometidos. Esses sites provavelmente também armazenam senhas em texto simples. sigh
baritoneuk

1
  • Nunca use algoritmos de hash MD5 ou SHA1. Atenha-se sempre aos mais novos, como o SHA512
  • Sempre use um sal forte gerado aleatoriamente
  • Nunca envie suas senhas por e-mail aos usuários, mesmo no caso de "Esqueceu a senha"
  • Nunca use as funções mysql_ *. Eles são depreciados há muito tempo. Atenha-se à DOP
  • Nunca armazene senhas em sessões ou cookies

0

Aqui está um conselho: verifique se seus cookies não podem ser acessados ​​com JS para evitar roubo, consulte Protegendo seus cookies: artigo HttpOnly por Jeff Atwood

... Por meio de uma construção inteligente, o URL malformado apenas consegue passar pelo desinfetante. O código renderizado final, quando exibido no navegador, carrega e executa um script desse servidor remoto.

... quem carrega esta página de perfil de usuário injetada de script acaba de transmitir sem querer os cookies do navegador para um servidor remoto maligno!

Como já estabelecemos, uma vez que alguém tenha os cookies do navegador para um determinado site, eles basicamente têm as chaves do reino para sua identidade lá ...

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.