Autenticação de sites com PHP e MySQL

Neste artigo pretendo mostrar uma maneira fácil, simples e segura de fazer um sistema de autenticação em PHP com MySQL. Todas as sessões são registradas em um banco de dados com o IP, data e hora de acesso, deixando um enorme histórico excelente para futuras auditorias. Procurarei detalhar o máximo possível para facilitar a compreensão do artigo.

[ Hits: 53.096 ]

Por: Djair Dutra C. Jr. em 08/12/2010


Finalizando (Dicas e maiores detalhes sobre o artigo)



Para melhorar a segurança, aconselho a colocação dos arquivos em php em pastas separadas, diferentes da pasta raiz do servidor web. Como o PHP é uma linguagem server-side, ou seja, que roda no servidor, ele lê a árvore de diretórios na visão do servidor e não na visão que o apache mostra ao navegador.

O apache mostra no navegador apenas o que tem acima da pasta /var/www, obviamente para ninguém ter acesso às demais pastas a arquivos através do browser. Já com o php é diferente, pois ele enxerga todo o servidor.

Portanto, podemos colocar arquivos php fora da área do servidor web, como em /etc ou em /var e "chamar" estes arquivos através do comando include ou require.

Esta é uma forma segura, pois na pasta raiz do servidor web (/var/www) colocaríamos apenas um arquivo e os demais seriam chamados através do comando include.

Neste artigo, me desfiz deste método para facilitar as explicações e as localizações dos arquivos, mas não é aconselhável desenvolver um site assim.

Melhorando o código

Para diminuir ainda mais este artigo, também não criei avisos ou caixas informativas quando ocorrem erros, mas é extremamente recomendável que um bom sistema avise e informe o usuário quando ocorrerem erros, de autenticação. Um bom exemplo, seria usar um alert em javascript para informar ao usuário que login ou senha não conferem.

Outro recurso simples que pode dar uma melhorada no seu site é colocar o foco do teclado no campo de login. Geralmente o navegador não dá esse foco no primeiro campo da página e o usuário sempre tem que clicar no campo para começar a digitar.

Para resolver este problema coloque o código abaixo entre as tags <body></body> do arquivo login.php. Lembrando que o campo texto "cara" deve ter uma id= "cara" para que o JavaScript possa achar este campo.

<script language="JavaScript" type="text/JavaScript">
document.getElementById('cara').focus()
</script>

Gerenciando usuários

Visando a simplicidade do artigo também tirei um recurso importante para um bom site, que é uma página para gerenciamento de usuários, no qual o administrador do site não precisa usar o phpmyadmin para inserir dados "manualmente" no banco de dados.

Nesta página tanto é feito a adição de novos usuários como a edição e exclusão, sem contar que o processo de gerar senha com MD5 pode ser automatizado, sem ter que recorrer todo tempo ao arquivo senha.php.

Num bom sistema é importante que cada usuário tenha acesso a alterar apenas sua própria senha. É importante também que esta função seja inserida em um sistema.

Restrições por acesso

Dependendo do tamanho do seu sistema, talvez surja a necessidade de criar níveis diferentes de usuários e liberar a cada um apenas uma parte do sistema. Os mesmos métodos para "expulsar" um usuário de uma página sem autenticação podem ser usados também neste tipo de restrição. Basta usar a criatividade.

Num grande sistema, por exemplo, um usuário deve ter acesso apenas aos relatórios financeiros, mas não pode mexer nas movimentações do caixa. Já outro usuário deve controlar o cadastro de clientes, mas não pode ter acesso aos relatórios.

No exemplo deste artigo, ao cadastrar o usuário "djair" coloquei a palavra "ADMIN" no campo de nome "privilegio". Apesar deste campo ser irrelevante nos códigos que exemplifiquei, esta é uma forma de identificar que tipo de usuário está acessando o sistema e fazer possíveis redirecionamentos baseados nesta informação.

Eu poderia, por exemplo, fazer uma verificação para redirecionar os ADMIN para uma página e os COMUNS para outras. Poderia ainda fazer verificações no ato de excluir um registro. Se o cliente for ADMIN pode excluir, caso contrário isso será negado a ele.

Existem várias maneiras de manipular usuários autenticados. Esta é apenas uma.

Dica de segurança

Apesar de existirem outras formas de redirecionamento em outras linguagens, como JavaScript, optei por usar o redirecionamento do php porque ele funcionou em todos os navegadores, inclusive em downloads, com o wget. Os redirecionadores feitos em JavaScript dependem deste recurso ativado no browser e em testes que fiz, tive acesso ao conteúdo que deveria ser bloqueado.

Sobre a conexão com banco de dados

Também visando uma explicação mais enxuta usei um esquema de conexão no qual o código com usuário e senha do banco de dados está presente dentro dos arquivos login.php, sessoes.php e logoff.php, mas esta não é a forma aconselhável de fazer isso.

Um site com sistema de login deve planejar-se em relação a isso e criar um só arquivo responsável por fazer a autenticação e em cada página fazer uma "chamada" a este arquivo através de códigos include ou require. Desta forma não teríamos as senhas que dão acesso ao banco de dados espalhadas por vários arquivos.

É também importante citar que fiz os códigos "propositalmente" usando o usuário root para que no final pudesse falar sobre isso separadamente. É extremamente recomendável (quase obrigatório) que você crie um usuário do mysql específico para acessar seu sistema com autenticação e jamais usar o root.

Criando um usuário específico, você pode definir somente as tabelas que ele terá acesso, definirá se ele pode excluir, adicionar etc. Se sua necessidade é um usuário que tenha acesso a tudo, faça isso dando todos os privilégios a um novo usuário, mas não use o root dentro de sues códigos php. Não confunda! Estou falando de um usuário do MySQL e não de um usuário do seu sistema de login.

Sobre os sistemas de autenticação

Neste artigo decidi mostrar uma alternativa de autenticação em php eficaz apenas para sites ou sistemas no qual a necessidade seja proteger apenas os arquivos php. Como informado no início, todos os outros arquivos que não sejam php estarão disponíveis a qualquer pessoa, mesmo que esta não esteja autenticada.

Existem várias outras alternativas disponíveis para autenticação, inclusive com restrição para outros tipos de arquivos que não sejam php. O intuito deste artigo foi mostrar apenas um método.

Cabe ao desenvolvedor fazer um projeto minucioso de como será seu site, avaliar as necessidades, o tipo de dados do sistema e só depois se decidir por uma das diversas alternativas disponíveis.

Considerações finais

Espero sinceramente que este artigo possa ajudar alguém como uma alternativa para o desenvolvimento de um site com autenticação. Procurei resumir cada detalhe importante da maneira mais fácil possível e até repeti alguns assuntos e algumas explicações buscando reafirmar o conhecimento ou dar ênfase a algo relevante para o artigo.

Agradeço a quem puder contribuir com alguma dica, informar falhas do código, questionar, ou sugerir alguma coisa que possa facilitar ou melhorar seu desempenho e segurança.

Página anterior    

Páginas do artigo
   1. Entendendo como as coisas funcionam
   2. Criando o banco de dados e as tabelas necessárias
   3. Criando os primeiros arquivos em PHP
   4. Protegendo cada arquivo individualmente
   5. Criando o arquivo sessoes.php
   6. Como inserir este código nos demais arquivos do sistema?
   7. Finalizando (Dicas e maiores detalhes sobre o artigo)
Outros artigos deste autor

O poder do SSH

O que ainda falta pra você abandonar o Windows de vez?

Controle de clientes e acessos no Squid

Estamos mais "INGNORANTES"?

Esqueça tudo e venha para o Linux!

Leitura recomendada

PHP: Programando com segurança

Dicas básicas de segurança no PHP

XSS - Um exemplo de ataque

Introdução a manipulação de erros em PHP

Criptografia do método GET no PHP

  
Comentários
[1] Comentário enviado por marcrock em 09/12/2010 - 01:52h

Ótimo artigo !!!

Quanto aos arquivos com outras estensões que não php, não existe uma opção que faça o php processar todo e qualquer tipo de arquivo ? Seria meio que um disfarce para o arquivo onde o php intercepta o carregamento e faz todas as verificações como se quele fosse um arquivo php real.

Até mais.

[2] Comentário enviado por sergiogurgel em 09/12/2010 - 11:34h

Não consegui executar. Ele não sai da tela de login Posso lhe enviar o meu projeto para você verificar o por que de não funcionar?

Obrigado.

[3] Comentário enviado por malacker em 09/12/2010 - 13:20h

Caro marcrock,

Existe uma maneira de impedir que certos arquivos sejam visualizados pelo apache. No arquivo de configuração do apache, você pode inserir a regra abaixo, mas como trata-se de um remédio para uma doença que pode ser evitada, acho melhor prevenir (usando só arquivos .php) do que ter que tomar o remédio.
Mas se seu caso exige que seja feita esta medida, espero que este código possa ajudar:

# Impedindo a visualização de arquivos .inc
<Files *.inc>
Order deny,allow
deny from all
</Files>

Se deseja, pode colocar vários arquivos simultaneamente na mesma regra.

# Impedindo a visualização de vários arquivos simultaneamente.
<FilesMatch "\.(gif|jpe?g|bmp|png)$">
Order deny,allow
deny from all
</FilesMatch>

[4] Comentário enviado por reyfernandes em 09/12/2010 - 18:29h

Vou fazer um comentário sem ler completamente seu artigo, li apenas o código do login.php.
Parece que você está com o register_globals no php.ini ligado, fazendo com que qualquer variável enviada por post ou get se torne uma variável no script, ficando fácil burlar o sistema.

pelo que li, talvez acessando:
http://seusite.com.br/login.php?codcliente=1&consulta_email=teste@email.com&cara=teste@email.com&con...
você consiga autorização para sua sessão, podendo navegar em qualquer página php.

Se puder testar e comentar se conseguiu acesso.

[5] Comentário enviado por mago_dos_chats em 09/12/2010 - 20:30h

Bom la vai meu comentario, na página de login você fez a verificação se as variaveis que o cara esta enviando de user e passwd estão em branco, mais se o cara fizer um sql injection?
Pelo jeito que esta seu sistema simplesmente vai bugar e mostrar a estrutura do banco toda.
Sugiro que você valide melhor seu formulário porque como ja dizia aquele ditado de programação .." se entrar lixo, sai lixo.".
Blz.. abraço cara

[6] Comentário enviado por malacker em 10/12/2010 - 12:03h

Não acredito que seja tão fácil burlar este login atravé de técnicas de sql injection porque o php criptografa (MD5) a variável recebida como senha e só depois a insere no banco de dados. Desta forma, qualquer coisa digitada no campo senha não será inserido literalmente no banco de dados, assim como a maioria das técnicas de sql injection.
Depois ele verifica se encontrou apenas só um cliente e só se isso for verdadeiro é que ele "loga" o cara.
O código ainda pode ser melhorado, sim (coisa que eu não fiz). Podemos colocar um "else" após o "if" que verifica se foi encontrado um só registro. Desta forma, dentro desse else, poderíamos zerar a variável $codcliente. Se o cara tentar um ataque por GET ou POST definindo um número para a variável $codcliente, o "if" trataria de zerar esta variável. É uma boa medida de segurança que deixei passar despercebida. Agradeço a quem contribuir.

[7] Comentário enviado por mago_dos_chats em 10/12/2010 - 18:58h

Sim malacker, com o MD5 o o usuario não vai ver qual a senha salva no banco, mais não acha que seria necessário proteger como seu banco esta estruturado? Legal o script para inicio, vai melhorando ele.

[8] Comentário enviado por Allthe em 10/12/2010 - 19:39h

Olá a todos,

Eu alterei o meu código assim:

exten => xxxx,1,Answer ;
exten => xxxx,n,Set(DB(test/count)=1234)
exten => xxxx,n,Set(COUNT=${DB(test/count)})
exten => xxxx,n,Authenticate(${COUNT}) ;

A questão é a seguinte como carreguei a variável test/count=1234. Como posso agora encontra-la no Mysql de modo a altera-la via Mysql?

Alguém pode dar uma ajuda?

[9] Comentário enviado por reideer em 12/12/2010 - 10:41h

Dicas:
nunca faça o que você fez.
#reyfernandes está corretissímo.
além do que, você trata a senha encriptando ela, porém o email ta passando livre livre para injections.

coisa simples a se fazer, sempre que adicionar uma variável a sentença sql, passe o conteúdo pela função addslashes antes. Não resolve todos os problemas, mas não deixa tão na cara o rombo na segurança. Do jeito que está tá na cara do gol.

[10] Comentário enviado por chinlap em 11/03/2011 - 14:39h

Eu li e re-li esse tutorial, fiz o passo-a-passo mas está dando erros nos arquivos. No arquivo sessoes da erro na linha numero 42, e no arquivo login aparece um erro na linha 24. eu não entendo quase nada de php, estou começando nessa area, como concerto esses arquivos? oq devo fazer? me ajudem por favor amigos.
até mais
OBS: esse script funciona também em php5?
Obrigado.


Contribuir com comentário




Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts