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.077 ]

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


Criando o arquivo sessoes.php



Antes, uma breve explicação sobre as sessões dos navegadores

Cada vez que você abre seu navegador, é criada uma sessão única, que trata-se de uma string com 32 caracteres, contendo letras e números. Exemplo: d5598f5a83a466e00bd0df58167d1994. As sessões mudam quando você fecha o navegador, mas não quando fecham apenas a página e continua com o navegador aberto, com outras abas.

Aquela linha <? session_start(); ?> que tem no início da página login.php e que também está presente na primeira linha do arquivo sessoes.php são responsáveis por iniciar as sessões.

É importante informar que quando uma sessão é criada, por mais que você entre numa página que tem o código para criá-la novamente, ela não mudará de número. Ou seja, se ela já existe, continua como está. Estas sessões são a base para a autenticação das outras páginas que devem ter acesso restrito.

Criando o arquivo sessoes.php:

Lembra que, quando o usuário faz o login com sucesso, é criado um registro na tabela sessoes, onde são guardados seu login, data, hora e principalmente o número da sessão? Pois estes dados são fundamentais para o acesso às outras páginas. Eles funcionam como uma credencial, ou um crachá que pode ser mostrado em todas as portarias internas e dar-lhe acesso aos setores internos, afinal se "porteiro" o permitiu entrar é porque trata-se de alguém de confiança.

O que este arquivo faz é pegar o número da sessão atual, verificar se existe algum registro no banco de dados referente a ela. Se houver um registro, ele ainda verifica se trata-se de uma sessão ativa ou se já foi encerrada pelo usuário.

Caso a sessão exista e esteja ativa, o php pega apenas duas variáveis chamadas "sessao" e "usuario" que respectivamente levam o número da sessão e o login do usuário que estão na tabela sessoes.

Caso não exista, as variáveis "sessao" ou "usuario" ficarão vazias e o comando "if" destruirá as sessões e jogará o usuário para a tela de login novamente.

Em resumo, este arquivo verifica se há uma sessão dando permissão ao usuário e se não houver ela redireciona-o para a tela de login. Veja o código completo do arquivo sessoes.php.

<? # Inicia uma sessão
session_start();
?>

<? # Pega o número da sessão criada e grava numa variável
$sessid = session_id();
?>

<?
# Inicia uma conexão com o banco de dados
$conexao = mysql_connect('localhost', 'root', 'minhasenha');
mysql_select_db('nome_do_bd', $conexao);

# Faz uma consulta para encontrar registros de sessões ativas (com status ABERTA)
# que coincidam com a sessão atual do usuário.
$consulta = mysql_query("SELECT * FROM sessoes where sessao='$sessid' and status='ABERTA'", $conexao);

# Pega a quantidade de linhas encontradas na busca
$linhas = mysql_num_rows($consulta);

# Se há mais de uma linha encontrada, grava sessão e login em duas variáveis
if ($linhas >= 1){;
$sessao = mysql_result($consulta,0,"sessao");
$usuario = mysql_result($consulta,0,"usuario");
};

#Finaliza a conexão com o banco de dados
mysql_close($conexao);

# Confere se a variável "sessao" não é diferente da sessão atual do usuário;
# Confere se a variável "sessao" não é vazia;
# Confere se a variável "usuario" não é vazia.
if ($sessao != $sessid or $sessao == "" or $usuario == ""){;

   # Se alguma das verificações acima for verdadeira, executa os códigos abaixo

# Destrói a sessão atual
session_unset();
session_destroy();

# Redireciona para a página de login.php
header("Location: login.php");
};
?>

Página anterior     Próxima página

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 que ainda falta pra você abandonar o Windows de vez?

Conhecimento x Soberba

Estamos mais "INGNORANTES"?

Por que eu pago por 10 megas, mas só faço download a 1 mega?

Solução para provedores - Receber aviso no celular quando ocorrer perda de pacote, hosts parados ou pacotes duplicados

Leitura recomendada

Segurança: Autenticando o PHP com HTTP (Authentication Required)

Pentesting on PHP apps: XSS

Dicas básicas de segurança no PHP

PHP: Programando com segurança

Instalações PHP não seguras

  
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