Login em PHP – Conceitos e técnicas

Login em PHP – Conceitos e técnicas

3 de maio de 2018 1 Por Ramos de Souza Janones
Powered by Rock Convert

Este artigo trata de conceitos e técnicas de criação de um sistema de login em PHP com MySQL de forma segura. 

Para uma autenticação segura é necessário identificar vários pontos.

Alguns itens que deve tomar cuidado:

  • SQL Injection
  • Criptografia de senha
  • Ataque de força bruta
  • Ataques XSS
  • Ataques CSRF
  • Proteger arquivos de sessão
  • Proteger arquivos de sistemas

1 – Iniciando

Defina um hash que será utilizado por todo seu sistema. um exemplo é

define( 'SECURITY_HASH', 'uma frase qualquer ou letras aleatórias com números e simbolos' )

 

2 – Crie sua tabela no banco de dados

Sugestão de tabela

id
email
username
password
keymaster
last_ip
last_access
active
created_at
uptaded_at

 

3 – Registro de usuário

Ao registrar valide se foi passado um email válido, se o campo de username está no formatado correto, e gere uma hash para o keymaster e utilize essa hash para criptografar a senha.

Para validar o email use

if ( filter_var( $email, FILTER_VALIDATE_EMAIL ) ) {
    echo "This ($email_a) email address is considered valid.";
}

 

Um exemplo de como gerar o Hash

crypt( rand(99999) . time() .  $_SERVER["REMOTE_ADDR"], SECURITY_HASH );

 

Uma forma mais segura de utilizar esta funcão é utilizar alguns $2a$ no inicio do segundo parâmetro para identificar o tipo de criptografia que deverá ser usada. Ficando da seguinte maneira:

crypt( rand(99999) . time() .  $_SERVER["REMOTE_ADDR"], '$2a$07$' . SECURITY_HASH );

 

Onde $2a$ especifica o algoritmo Blowfish e 07$ o custo para gerar o hash.

ou se estiver usando o php 5.5 poderá usar a função password_hash(). Saiba mais em https://br1.php.net/manual/en/function.password-hash.php

$_SERVER["REMOTE_ADDR"] // Obtem o IP do usuário

 

Armazene o IP do usuário e as datas de último acesso, e quando foi criado.

Deixe o usuário inativo (campo active = 0 ) e valide o email cadastrado enviando um email de confirmação.

No email de confirmação você informa um link do tipo

https://www.dominio.com.br/validateuser.php?key={hash do resultado da concatenação do keymaster e SECURITY_HASH}

 

Essa url irá mudar o campo active de 0 para 1, indicando que o usuário foi ativado.

4 – Login

Para o login você deve receber os dados do formulário e validá-los, verificando se está como o esperado.

Busque as informações do usuário no banco, utilizando apenas o username informado.

Com os dados que obteve do banco, criptografe a senha informada pelo formulário utilizando a keymaster do usuário, o mesmo procedimento do registro.

Compare a senha que obteve do banco com a senha que recebeu do formulário criptografada Caso sejam idênticas, inicie a sessão.

5 – Cuidados básicos

Para obter dados passados via POST ou GET, evite utilizar as variáveis globais puras. Para isso utilize filter_input().

Leia sobre na documentação: https://www.php.net/manual/en/function.filter-input.php

Para garantir que os dados enviados via formulário foi realizado de seu servidor, crie uma hash e armazene em sessão. Adicione essa hash em um campo hidden do formulário. Ao receber os valores do formulário, verifique se o hash que veio do formulário existe e está igual ao da sessão.

Curso de PHP ERP com NFe.

Renove o hash sempre que for exibir um formulário.

Neste link tem um exemplo completo sobre prevenção deste tipo de ataque https://www.owasp.org/index.php/PHP_CSRF_Guard

  • Nunca use o register_globals setado com on
  • Não valide seus formulários apenas no javascript, pois se o usuário estiver com o javascript desativado irá passar direto.
  • Utilize o PDO validando todos as variáveis antes de passá-las para uma SQL.
  • Configure no php.ini o seguinte session.cookie_httponly = 1 . Isso informa para o browser não expor cookies para linguagens clients side como o javascript.
  • Nomeie todos os arquivos com a extensão .php nunca com extensão como .inc, .conf, etc.
  • Evite usar md5 como criptografia, utilize bcrypt pois o algoritmo é muito mais seguro.
  • Guarde a sessão no banco de dados
  • Defina um domínio para seu cookie
  • Contabilize as tentativas de login e o tempo entre elas para evitar robos.
  • Em produção deixe o display_errors como off
  • Gere log de erros e envie para seu email, isso facilita identificar tentativas de invasão.
  • Cuidado com as permissões dos seus arquivos no servidor, garanta que apenas o apache tem permissão sobre eles.

Alguns links úteis.

Curso completo de Games, inclusive Realidade Aumentada.Powered by Rock Convert

Alguns itens que devemos tomar cuidado:

  • Cookies são fáceis de roubar informações
  • Ataques via falsificação de solicitação entre site ou Cross-site request forgery
  • Reiniciar a sessão e excluir todos os cookies após alteração de senha, para que tudo possa ser recriado.
  • Mesmo que o usuário permaneça ativo, solicitar sempre a senha quando envolver transações financeiras.
  • Nunca armazenar dados de usuários em cookies, como email, senha, cpf, número de cartões, etc.
  • Não basear a segurança apenas no ID de sessão, pois esse ID tambem pode ser clonado.
  • Não utilize dados voláteis ou transferíveis como IP para validar um usuário.
  • Nunca deixar a validade da autenticação eterna.
  • Forneça uma maneira de o usuário desconectar todos os lugares estiverem com a sessão prolongada.

Pensando nos critérios acima citados, podemos chegar no modelo a seguir e minimizar os riscos.

Gerando o token de autenticação

Precisaremos armazenar tokens da autenticação em nosso servidor, para isso uma tabela semelhante deve ser criada em nosso banco de dados.

 - id           // Um identificador para o token, não utilize auto_increment,
                // pois pode trazer problemas, 
 - user_id      // Relacionamento com as informações do usuário
 - token        // Armazena o token de autenticação
 - browser      // Identifica qual browser foi utilizado para autenticar
 - last_access  // Último acesso (timestamp)
 - created_at   // Data de criação (timestamp)

 

LEIA TAMBÉM:  Conheça os cursos on-line gratuitos oferecidos pelo ITA

Para gerar o id desta tabela, podemos utilizar algo simples do tipo

md5( uniqid( mt_rand(), true ) );

 

Nesta solução iremos armazenar tambem o browser utilizado, para dificultar ainda mais as tentativas de ataques, seja por clonagem de sessão, CSRF, ataques automatizados, etc.

No PHP existem funções que facilitam identificar o browser do usuário, mas caso prefira alguma forma alternativa, existem várias na internet. Não importaremos com a versão do browser para evitar erros devido a atualizações automáticas.

Para armazenar o último acesso do usuário, sempre atualize o campo last_access usando a função time().

Para o campo created_at use tambem a função time().

O Token pode ser gerado de forma aleatória, como por exemplo:

sha1( uniqid( mt_rand() + time(), true ) );

 

Toda vez que o usuário autenticar, iremos gerar um novo e armazenar nesta tabela.

No cookie guardaremos apenas o id do token e o token em si.

$id = md5( uniqid( mt_rand(), true ) );
$token = sha1( uniqid( mt_rand() + time(), true ) );

// Armazenar o token na tabela do banco de dados

$expire = ( time() + ( 30 * 24 * 3600 ) ); // O cookie não deve ser eterno.
$cookieToken = array( 
    'i' => $id,
    't' => $token
);
setcookie( 'auth', json_encode( $cookieToken ), $expire, '/', 'www.dominio.com', isset( $_SERVER["HTTPS"] ), true );

 

Validando o token

No código anterior informamos que o cookie só é válido para determinado domínio, porem isso pode ser alterado. Sendo assim devemos validar de onde está vindo a requisição, e a maneira mais simples de fazer isso é usando a variável $_SERVER['REMOTE_HOST'], o domínio deve ser conhecido.

Após validar a requisição, recupere o cookie, deserialize os dados e valide com o banco de dados.

$tokenData = isset( $_COOKIE['auth'] ) ? json_decode( $_COOKIE['auth'] ) : false;
if( $tokenData !== false ) {
    $id = $tokenData['i'];
    $token = $tokenData['t'];

    // Busque no banco de dados o id e valide o token;
    // Veja tambem a validade do token usando como base o campo 'created_at'
    // e o browser.
    // Se tudo estiver correto, apague este token, gere um novo
    // e inicie a sessão.
}

 

LEIA TAMBÉM:  Slack: Ferramenta que aumenta a produtividade de equipes

Incrementando

Para tornar ainda mais seguro, você pode registrar todos os IPs e SESSION_IDs que usaram um determinado token.

Como toda vez que uma nova sessão é iniciada um novo token é gerado, basta gravar em uma segunda tabela o IP que gerou o token e a SESSION_ID, junto destes dados você irá gravar a ultima interação com o seu sistema e o tempo de conexão.

A tabela ficará assim:

 - ip            // Ip do usuário $_SERVER['REMOTE_ADDRE']
 - token_id      // Id do token que foi gerado quando o usuário iniciou a sessão.
 - session_id    // Id da sessão session_id()
 - user_agent    // Informação completa do browser $_SERVER['HTTP_USER_AGENT']
 - time          // Tempo de conexão
 - created_at    // Quando a conexão foi iniciada
 - updated_at    // Última atualização (função time() para toda atualização)

 

Toda vez que o usuário fizer alguma requisição para nosso servidor com a sessão ativa, iremos atualizar o registro da atual conexão dele, recuperando-a pelo . Se nada for recuperado, a sessão dele é inválida e bloquearemos o acesso.

Para atualizar devemos sempre verificar se o IP e o user_agent são os mesmos, assim como podemos verificar se ele possui o token que foi gerado quando a autenticação foi iniciada.

Para atualizar o tempo de conexão, calcule utilizando o campo created_at

time() - $created_at

 

Sempre verifique se existe mais de um IP utilizando um token ao mesmo tempo. Isso pode ocorrer quando o provedor do usuário troca o IP e a sessão se mantém ativa.

Se um token possuir requisições de IPs diferentes com um tempo muito curto entre elas, devemos invalidar o token, e redirecionar qualquer requisição ligada a ele para a tela de login.

Observações

Esta maneira possui algumas falhas, mas já dificulta bastante as tentativas de roubo de sessão devido ao fato de o token ser constantemente atualizado.

As requisições de inserção e atualização ao banco de dados vai aumentar bastante para esse modelo. Para evitar problemas, este modelo deve ser baseado em bancos não relacionais ou utilizar uma camada de cache como o memcached, que irá receber todas as requisições e de tempos em tempos, atualizar o banco de dados.

Devemos alertar sempre o usuário quando mais de uma sessão com estiver ativa, e fornecer a possibilidade de invalidar todos os tokens, e realizar o login novamente.

Nunca devemos possibilitar a troca de senha sem ter uma maneira de validar a autenticidade de quem está alterando.

É muito importante alertar ao usuário sobre o uso de cookies e ter uma política bem escrita sobre isso.

Num próximo artigo mostrarei como criar um sistema de login com Ionic 3 e PHP.

Outros tutoriais e dicas sobre PHP:

 

Vai gostar também:  Os cursos online de programação e tecnologia mais recomendados para 2019

Subscribe to our mailing list

* indicates required


Além de PHP e MySQL, deseja receber outro tema?

LEIA TAMBÉM:  BITBUCKET – REPOSITÓRIO ON-LINE GRÁTIS

Email Format


React Native Do Zero Ao Profissional: crie apps para Android e IOSPowered by Rock Convert
Siga os bons!

Ramos de Souza Janones

Janones, é um empreendedor brasileiro apaixonado por empreendedorismo e tecnologia. Ao longo dos anos trabalhando com o desenvolvimento de softwares desktop desde a linguagem Clipper, passando pelo Delphi e atualmente com Java.

Optou pela formação de Publicidade e Marketing por sua segunda empresa de tecnologia ter participado do "boom" da internet nos anos 90 e na procura de melhorar seus conhecimentos em negócios.

Em razão da principal formação e profundos conhecimentos em programação e banco de dados, é capaz de realizar o desenvolvimento de aplicativos web, desktop e mobile com maior criatividade e inovação que profissionais de desenvolvimento com uma formação única e mais especifica, dedicada somente ao desenvolvimento de softwares.

Com toda sua experiência com empresas de software, sua formação e paixão por negócios escreveu o livro "Marketing para Empresas e Profissionais de Software", publicado pela editora carioca Ciência Moderna em 2012. Além de outros livros sobre programação.

Últimos posts por Ramos de Souza Janones (exibir todos)

Sumário
Login em PHP - Conceitos e técnicas
Nome do artigo
Login em PHP - Conceitos e técnicas
Descrição
Este artigo trata de conceitos e técnicas de criação de um sistema de login em PHP com MySQL de forma segura. 
Autor
Nome
Ramos da Informática
Logo



Frontend Do Zero Ao Profissional