Dicas mínimas para um site mais seguro - Parte 1 - PHP

Sobre essa série sobre segurança

Irei fazer uma série de posts sobre segurança na internet. Cobrirei segurança no site em si e no servidor que o contém. Em cada post irei cobrir um pouco das minhas "neuras" com segurança. Espero que seja útil!

Neste primeiro falarei sobre algumas atitudes que podem fazer seu código em PHP lhe poupar algumas dores de cabeça.

Começando

Fazer códigos em PHP é fácil. Sabendo um pouco de lógica de programação, com meia hora de google, você já está fazendo coisas simples, mas úteis. Porém, essa facilidade em qualquer um conseguir fazer ferramentas web traz alguns problemas com ela. Como tem muitos "fazedores de site" por aí, e vários são adeptos da cultura do "Ctrl+c, Ctrl+v", não é difícil achar sistemas web que tenham algumas falhas de segurança graves, ou se comportem de maneira imprevisível se alguma entrada incomum for feita.

Não quero me adentrar demais no assunto dos "fazedores de site", pois é uma questão que vai muito além do escopo do que quero passar hoje. Mas, gostaria apenas de dizer que nada tenho contra quem não tem tanto conhecimento técnico e ganha vida fazendo sistemas web, pois afinal, todos nós já fomos assim um dia. Gostaria também de alertá-los para algumas práticas simples que podem lhes poupar de dores de cabeça e prejuízos. Vamos lá.

O código fazer o que você quer que ele faça não é tudo

Bom, você pode ler esse subtítulo e se perguntar "se faz tudo que eu quero, não faz tudo então??". A resposta é simples: não. Um sistema web está exposto (como vários outros sistemas computacionais), a usuários mal-intencionados. Não vou entrar muito em detalhes sobre o que esses "usuários do mal" do seu site podem querer, mas eles podem desejar assumir seu site para ter uma base para enviar spam, disseminar vírus, entre outras malfeitorias que incluem também apagar seu banco de dados só por diversão. "Quem iria querer fazer isso com o meu site???" você pode se perguntar. Bom, existem pessoas mal-intencionadas em qualquer lugar, a vida real já deve ter te mostrado exemplos de maldade gratuita, e novamente, não irei me aprofundar nesse viés do ser humano.

O fato é: uma aplicação web deve se preocupar em se comportar corretamente recebendo as entradas corretas. Mas mais importante, deve se preocupar em "aguentar" uma certa dose de entradas incorretas (isso se chama robustez). Seu banco de dados de usuários cadastrados pode parecer de baixo valor para você, mas se você perdê-lo e não tiver backup, você provavelmente vai sentir muitas saudades dele :P Sim, backup é importante também, faça muito backup (farei um tópico sobre isso um dia desses). Mas ter o site fora do ar, por ter perdido sua base de dados faz você perder visitas, e isso custa dinheiro, seja pra você (se você for o dono do site), seja para o seu cliente (se você for o "fazedor de sites"), o que faz você perder dinheiro também. Eu poderia gastar parágrafos e parágrafos explicando sobre os problemas que falhas de segurança trariam, mas meu objetivo aqui é apenas dar umas dicas mínimas para ter um sistema web seguro, pois, afinal, se você está lendo isso, já está sensibilizado que segurança é importante. Pra quem não está, e continua fazendo sites, digo que o mundo é uma selva, e rola uma seleção natural, projetos grandes trazem mais dinheiro, e projetos grandes são só pra quem dá conta de matar mamutes grandes ;) E pra quem continua pagando pelo desenvolvimento de sites sem medidas de segurança, digo "Boa sorte", por que é o que vocês vão precisar, pois é a única coisa que protege o negócio de vocês. E espero que estejam pagando bem barato pelo serviço.

Feito esse desvio filosófico no assunto, vou continuar. Entre as entradas incorretas que seu sistema pode receber, faço a seguinte distinção:

Existem diversas soluções para lidar com esse problema. Eu particularmente gosto da seguinte abordagem:

Talvez agora você esteja se sentindo um pouco desolado em saber dessa selvageria que pode ser feita no seu site. Talvez você não tenha se importado muito com isso, mas tenho fé que você se preocupa com a segurança do seu sistema web (ou do seu cliente), pois como disse antes, você está lendo isso aqui. Não sei se isso serve de conforto, mas eu conheço uma série de sites com falhas de segurança desastrosas. Logicamente não irei listar quais são, mas não são poucos e não é exclusividade de sites pequenos. Bom, então você não está sozinho no mundo dos sites "escancarados", mas recomendo que você venha para o time dos "menos escancarados". Não posso chamar meu time dos sites seguros, porque minhas convicções me proíbem de aceitar que algo com 0's e 1's seja 100% seguro.

Muita conversa e pouca ação até agora... Vamos listar agora algumas atitudes mais concretas para melhorar a segurança do seu site.

Defendendo-se de ataques de Form Injection

Existe como você verificar de que página veio uma requisição para seu script PHP, então você pode pensar "oba! esqueça a validação server-side, é só eu olhar isso então e boa!". Pelo meu sarcasmo, você já deve ter sacado que não é por aí né? De fato existe como você verificar esse tal referer. O problema é que isso pode ser burlável facilmente, e aí, pior do que não ter segurança, você vai ter uma falsa sensação de segurança. Então, minha recomendação é, valide os campos do lado do servidor. Como você já validou com JavaScript no seu formulário legítimo (conforme discutido anteriormente), sugiro jogar fora todos os campos que vieram dessa requisição, boa coisa não devem ser. Atente que o problema pode ser no seu validador JavaScript, então garanta que ele funciona realmente, antes de jogar fora as coisas no server-side. Podem existir outras políticas para lidar com isso, mas, essa é a minha, e no meu ver ela é suficientemente adequada.

Outra coisa importante, para campos numéricos. Se o campo é puramente numérico (id's por exemplo), cheque no lado do servidor se ele é realmente numérico. E cheque também se ele está dentro do intervalo de valores válidos.

Os campos de texto são olhados com mais afinco na próxima seção, pois eles são mais delicados e levam a ataques mais pesados.

Defendendo-se de ataques de SQL Injection

Bom, esse é um dos ataques mais comuns e mais perigosos. Também, é um dos ataques mais fáceis de se previnir. Chega a me deixar preocupado como algo tão simples de se corrigir seja tão ignorado. Já tive acesso a muitas áreas restritas de sites com um simples

' or '1'='1

no campo usuário e senha. Alguns podem me condenar por ter ensinado como fazer um ataque de SQL Injection, mas tenho 2 coisas a dizer para essas pessoas:

Vou explicar brevemente porque essa simples entrada dá acesso à área restrita do seu site. Vamos supor que você receba o usuário e senha através de um POST, e faz a seguinte query ao seu banco de dados.

$usuario = $_POST['usuario'];
$senha = $_POST['senha'];
$resultado = mysql_query("SELECT * FROM
 cadastro WHERE usuario='$usuario' AND senha = '$senha'");
if(mysql_num_rows($resultado) > 0){
   //codigo para dizer que o usuario foi autenticado no sistema
}
//resto do codigo vem aqui.

Com aquela entrada mostrada anteriormente, essa query chegaria aoSGBD da seguinte forma (para verificar por você mesmo, copie a entrada e cole-a nos lugares exatos das variáveis PHP):

SELECT * FROM cadastro WHERE usuario='' or '1'='1' AND senha = '' or '1'='1';

Isso retornaria um resultado com mais de um resultado, e lhe daria acesso a alguma coisa que você não deveria ter acesso. Tá, você pode dizer que fazer aquele ">0" foi exagero, que você na verdade faz "==1" no seu código. Eu só precisaria saber um usuário válido para fazer a mesma coisa com seu código. E fora que eu conseguiria apagar seu código inteiro com um DROP.

Como contornar isso? Existem alguns meios, mas o que eu acho mais recomendado é usar funções próprias do PHP para lidar com isso. É um pouco razoável você rejeitar todas as entradas que tenham a famigerada aspas simples ( ' ), com uma função feita por você mesmo. Você atingiria algum nível de segurança, mas o usuário Eduardo Sama'an ficaria muito chateado e confuso em não conseguir se cadastrar em seu sistema (um abraço para meu amigo Sama'an! iraquiano safado!). O jeito mais elegante, simples e correto, no meu ponto de vista, de tratar as entradas para o banco é usar a função mysql_real_escape_strings(). O link explica como utilizá-la. O mais impressionante é que para aquele código inseguro ficar bem mais seguro, só precisaria ser feito:

$usuario = mysql_real_escape_strings($_POST['usuario'],$variavel_da_conexao_do_BD);
$senha =  mysql_real_escape_strings($_POST['senha'],$variavel_da_conexao_do_BD);
$resultado = mysql_query("SELECT * FROM cadastro WHERE usuario='$usuario' AND senha = '$senha'");
if(mysql_num_rows($resultado) > 0){
   //codigo para dizer que o usuario foi autenticado no sistema
}
//resto do codigo vem aqui.

Sobre isso, cabe uma nota. Existe uma opção do PHP que permite um nível de segurança parecido, é a chamada magic quotes gpc. Sugiro que você clique nesse link para ver porque ele não é uma boa idéia. Se você ficou com preguiça de clicar, ou de ler aquele tanto de texto (Delgado, você tá lendo isso aqui também???), saiba que essa política deixa o programador mal-acostumado, torna o código dependente da configuração do servidor e gasta muito processamento inutilmente, pois nem todas as requisições precisam ser escapadas. Tanto foi execrada que a partir do PHP 6.0.0, ela foi removida. E ainda devo dizer que existem jeitos de burlá-la, mas para evitar mais protestos, não irei ensinar como, o google está aí pra isso (e já fiz mal de dizer que tem jeito de atravessar essa segurança) :)

Existem mais coisas entre o céu e a terra do que julgam nossa vã filosofia

O que fiz aqui foi ilustrar 2 problemas sérios conhecidos mas que recebem pouca atenção por programadores inexperientes. Existem inúmeras outras maneiras de se fazer coisas erradas em seu site, mas pelo menos agora você tem 2 problemas a menos para se preocupar :) E ainda está mais sensibilizado sobre segurança, e acredito que passará a dar mais atenção a isso. Se você tiver sugestões para próximos posts, sou todo ouvidos :) Se você tiver reclamações e/ou quiser comentar algo que falei, sou todo ouvidos também! Se você se sentiu ofendido pelo meu tratamento aos "fazedores de site" (ou sobrinhos, pronto, falei!), bom... Tá, pode discutir isso comigo também... hehehe

[]'s

Sahb,.