Segurança e gerenciamento de erros no PHP - como melhorar seu código com set_error_handler e error_log

Existe uma linha de pensamento na comunidade de desenvolvedores que recomenda que para dar maior segurança a um sistema, e assim evitar ataques, deve-se fornecer a menor quantidade possível de informações sobre o mesmo.

Pegando esta ideia como padrão para nossos projetos uma das coisas que podem dar informação valiosa para crackers são as mensagens de erro na execução do sistema.

 Mensagens de erro deveriam ser vistas apenas pelos desenvolvedores, não pelos usuários


Tais mensagens podem informar, por exemplo, caminhos de arquivos e estrutura de diretórios desprotegidos, senhas de acesso a banco de dados e versões de software que podem ser utilizadas como base para busca de brechas de segurança.

Assim não exibir tais erros é fundamental para manter o sistema o mais protegido possível, além de dar uma cara mais profissional ao projeto, afinal é bem feio seu usuário final ver uma mensagem dizendo que o sistema apresentou erro.

Porém devemos lembrar também que para os desenvolvedores as mensagens de erro são, obviamente, importantíssimas e por isso não podem simplesmente ser escondidas.

Uma solução interessante é a utilização da função set_error_handler() do PHP, que direciona as mensagens de erro para uma função que nós mesmos podemos definir. Dentro desta função ai sim podemos, por exemplo, gravar o erro em um banco de dados ou em um log no formato texto.

A solução que apresentarei envolve gravar as mensagens em um arquivo .txt de log.

Primeiro vamos provocar nosso erro, algo bem simples como uma variável não declarada:

 <?php  
 echo $var;  




Mais simples que isso impossível!
Agora vamos implementar a função set_error_handler()

 <?php  
 set_error_handler('custom_error');  
 echo $var;  
 function custom_error ($errno,$errstr,$errfile, $errline, $errcontext)  
 {  
 $m = "<strong>Erro {$errno}</strong>: {$errstr}<br/>\n";  
 $m .= "<strong>Arquivo</strong>: {$errfile}<br/>\n";  
 $m .= "<strong>Linha</strong>: {$errline}<br/>\n";  
 $m .= "<strong>Contexto</strong>: <br/><br/>\n<pre>".  
 print_r($errcontext,true)."</pre><br/>\n";  
 print ($m);  
 }  




Vemos que neste caso o erro continua aparecendo para o usuário, mas isso porque dentro da função custom_error() nós explicitamente mandamos exibi-la com o print(), porém ela vem na formatação que nós definimos. Poderíamos não exibir nada simplesmente retirando o print() porém como não fazemos nenhum tipo de arquivamento do erro seria simplesmente inútil. Perceba também que a chamada para nossa função customizada de erro custom_error() é feita logo no início do script.

Para completar nosso exemplo vamos deixar de exibir o conteúdo do erro e registrá-lo em um arquivo de log personalizado:

 <?php  
 set_error_handler('custom_error');  
 echo $var;  
 function custom_error ($errno,$errstr,$errfile, $errline, $errcontext)  
 {  
 $m = "<strong>Erro {$errno}</strong>: {$errstr}<br/>\n";  
 $m .= "<strong>Arquivo</strong>: {$errfile}<br/>\n";  
 $m .= "<strong>Linha</strong>: {$errline}<br/>\n";  
 $m .= "<strong>Contexto</strong>: <br/><br/>\n<pre>".  
 print_r($errcontext,true)."</pre><br/>\n";  
 error_log($m,3,'t.log');  
 }  


Ao executar o script você notará que nenhum erro é apresentado porém se o seu servidor estiver configurado para gerar arquivos por usuários externos verá que surgiu na mesma pasta em que está seu arquivo de testes de erro outro arquivo chamado 't.log'

Ao abri-lo perceberá que o conteúdo é exatamente o mesmo que antes aparecia no navegador.



Quem faz isso é a função error_log() com o código 3 que diz à função que ela deve escrever o conteúdo $m no caminho/arquivo 't.txt'.

O formato de erro apresentado no arquivo pode ser modificado por você pois ele não é o melhor. O ideal é que apenas informações relevantes para 'debugar' problemas sejam registrados ou seu arquivo logo estará 'explodindo' de tão grande.

Abraço a todos e boa sorte!

Comentários

Postagens mais visitadas deste blog

MySQL - Completando quantidades fixas de caracteres com as funções LPAD() e RPAD()

MySQL - Clonando tabelas na linha de comando

PHP - Gerando arquivo em UTF-8 com fwrite() e utf8_encode()