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.