+3

Principais erros de segurança em códigos PHP

criado por Marcos Regis em 12/06/2008 8:17am
- Para areas protegidas, usar sessões ou validar o login o tempo todo.

Existem alguns casos onde programadores irão somente usar algum script login.php para primeiro validar seu nome de usuário e senha (esntrados através de um formulário), testar se ele é um administrador ou usuário válido, e ajustar uma variável através de um cookie, ou ainda escondido em alguma variável oculta.

Então no código, ele checa para ver se ele tem acesso desta forma:

<?php
if ($admin) {
		// Deixe-o entrar 
} else {
		// Chute-o daqui 
}
?>

O código acima faz a presunção fatal de que a variável $admin somente virá de um cookie ou entrada do formulário que um usuário malicioso não tem controle. Contudo, este simplesmentes não é o caso. Com register_globals ativado, injetar entrada designada dentro da variável $admin é tão fácil como chamar o script assim:

script.php?admin=1

Além disso, ainda que você use as superglobais $_COOKIE ou $_POST, um usuário malicioso pode facilmente forjar um cookie ou criar ou seu próprio formulário HTML para postar qualquer informação em seu script.

Existem duas boas soluções para este problema. Uma está em ajustar uma variável $admin, mas desta vez ajustar $admin como uma variável de sessão. Neste caso, ela é armazenada no servidor que e é muito menos sensível a forjas. Em uma chamada subsequente no mesmo script, A informação prévia de seu usuário estará disponível no servidor, e você será capaz de verificar se o usuário é um administrador desta forma:

<?php
if ($_SESSION['admin']) {
}
?>

A segunda solução é somente armazenar seu nome de usuário e senha em um cookie, e a cada chamada so script, validar tais entradas. Você pode ter duas funções – uma chamada validate_login($username,$password) que verifica as informações de login do usuário, e uma chamada is_admin($username) que consulta o banco de dados para ver se o usuário é um administrador. O código pode ser colocar no topo de qualquer script protegido:

<?php
if (!validate_login($_COOKIE['username'], $_COOKIE['password'])) {
    echo "Desculpe,  dados inválido";
    exit;
}
// O login está OK e nó fazemos isto aqui
if(!is_admin($_COOKIE['username'])) {
    echo "Desculpe,  você não tem acesso a esta seção";
    exit;
} 
?>

Pessoalmente eu recomendo o uso de sessões, porque a última solução não é escalável.

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 (~15 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 (~15 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 (~15 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 (~15 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 (~15 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 (~15 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 (~15 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 (~15 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 (~15 anos atrás)

Novo Comentário:

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