Tratamento de dados fornecidos pelo usuário: projetando sistemas com mais segurança

De uns tempos para cá comecei a notar que mais gente está programando e conseqüentemente mais gente está entrando no mercado de trabalho precocemente. Estão iniciando sua viagem pelo maravilhoso mundo do desenvolvimento web muito inocentemente, no entanto não sabem eles - os desenvolvedores newbies ou negligentes - que existem usuários maliciosos olho no seu sistema.

[ Hits: 88.100 ]

Por: Ragen Dazs em 07/04/2004 | Blog: http://www.orkut.com


O que são casts



Como já vimos nos exemplos anteriores, os códigos arbitrários podem nos causar uma grande dor de cabeça. Mas poucas pessoas conhecem os benditos casts e, é claro, conseqüentemente nem sabem como sua rotina de trabalho poderia ser facilitada com o seu uso.

De grosso modo os casts são moldes de dados, ou seja, ele modela o tipo de dado que cada variável irá aceitar/conter.

Como o PHP não requer (ou suporta) a definição de tipo explicita na declaração de variáveis: o tipo de uma variável é determinado pelo contexto em que a variável é utilizada. Isto significa que, se você setar um valor string para a variável $var, $var se torna uma string. Se você então setar um valor inteiro para $var, ela se torna um inteiro.

Então devido a esse tipo de assimilação ou identificação automática de tipos de dados nas variáveis do PHP, muitas vezes nos descuidamos e abrimos brechas para códigos os arbitrários.

Usando casts


Você pode forçar uma expressão a ser de um determinado tipo usando um cast. A forma genérica de um cast tanto em PHP como C é:

(tipo) expressão

Onde tipo é qualquer tipo de dados *válido em PHP/C. Vejam alguns exemplos em PHP abaixo:

<?php
                        // Saídas:
var_dump(25/7);         //   float(3.5714285714286)
var_dump((int) (25/7)); //   int(3)
var_dump(round(25/7));  //   float(4)
?>

* Os tipos de dados válidos nos casts ou nas "moldagens" são:
  • (int), (integer) - molde para inteiro
  • (bool), (boolean) - molde para booleano
  • (float), (double), (real) - molde para número de ponto flutuante
  • (string) - molde para string
  • (array) - molde para array
  • (object) - molde para objeto

Basicamente quando vamos usar banco de dados escrevemos muitas funções utilizando ID`s de chaves primárias ou chaves estrangeiras como base da nossa função. Se vocês sabem que os ID`s dos banco de dados são inteiros e seqüencialmente incrementados existe algum motivo para deixar uma string passar como argumento pelas nossas funções?

Se alguém passar uma string pela nossa função sem o uso de um tratamento de dados devido o banco e dados pode nos retornar erros ou ainda aceitar códigos arbitrários, como dito anteriormente. Se nos casos de SQL injection tivéssemos usado um molde do tipo inteiro na query " OR 1=1 " (dos exemplos anteriores) o valor de retorno do molde inteiro nesse código seria falso, ou seja, na nossa query ele seria interpretado como 0 (zero), veja um exemplo:

<?php
$_GET['id'] = (int) $_GET['id'];
$sql = "DELETE FROM cadastros WHERE id_cadastro=" . $_GET['id'];
?>

http://www.teste.com.br/script.php?id=1+OR+1;

Usando esse tipo de tratamento de dados, absolutamente nada aconteceria pois $_GET['id'] valeria 0 (zero) e usando a propriedade de `auto incremento` no seu banco de dados a numeração das células da sua tabela se iniciariam em 1 (um), diferentemente da numeração vetorial em C/PHP por exemplo.

A função sprintf


A função sprintf nada mas faz que retornar uma string formatada, em outras palavras, retorna uma string produzida de acordo com a string de formatação `format`:

Descrição - sprintf ( string format [, mixed args])
  • % - Um caracter porcento. Não é requerido nenhum argumento.
  • b - O argumento é tratado como um inteiro, e mostrado como um binário.
  • c - O argumento é tratado como um inteiro, e mostrado como o caracter ASCII correspondente.
  • d - O argumento é tratado como um inteiro, e mostrado como um número decimal com sinal.
  • u - O argumento é tratado como um inteiro, e mostrado como um número decimal sem sinal.
  • f - O argumento é tratado como um float, e mostrado como um número de ponto flutuante.
  • o - O argumento é tratado como um inteiro, e mostrado como um número octal.
  • s - O argumento é tratado e mostrado como uma string.
  • x - O argumento é tratado como um inteiro, e mostrado como um número hexadecimal (com as letras minúsculas). letters).
  • X - O argumento é tratado como um inteiro, e mostrado como um número hexadecimal (com as letras maiúsculas).

Exemplo de seu uso:

<?php
$_GET['id'] = sprinf("%d",$_GET['id']);
$sql = "DELETE FROM cadastros WHERE id_cadastro=" . $_GET['id'];
?>

Mas pra que complicar se um simples molde de inteiro resolveria a situação?
Simplesmente por que se nós moldássemos uma fração desconhecida para inteiro ela poderia nos fornecer resultados inesperados as vezes. Veja o exemplo abaixo:

<?php
echo (int) ( (0.1+0.7) * 10 ); // imprime 7!
?>

Moral da história: é mais aconselhável usar a função sprintf que os moldes clássicos.

Reflexão sobre aceitação de dados de forma incorreta


Saiba você que a sua paranóia em segurança por maior que seja não é e nem deve ser o seu limite para homologar um código como seguro, afinal de contas por mais inteligente e por mais conhecimento que você tenha uma aplicação escrita por você só será 100% segura pra você ou para alguém com o mesmo nível de conhecimento seu. Sempre que puder promova pen-tests (testes de penetração) em seus códigos. Enfim... Mostre a outras pessoas o que você está fazendo e por que está fazendo daquela forma - Pois como já dizia um ditado da comunidade Open Source:

"Milhões de mentes abertas não podem estar erradas".

Página anterior     Próxima página

Páginas do artigo
   1. Início
   2. Descrição do ambiente
   3. Tratando dados
   4. O que são códigos arbitrários
   5. O que é SQL injection
   6. Escapando strings
   7. Coringas e meta caracteres
   8. Escapando argumentos em shell
   9. O que são casts
   10. Denial of Service em sua página
   11. Cross site script
   12. Explorando falhas locais
   13. Agradecimentos
Outros artigos deste autor

Instalando o Allegro

O perigo no gerenciador de uploads do PHP

Projeto Icecream (parte 1)

Entendendo um pouco sobre os daemons

Sejamos todos filhos da p***

Leitura recomendada

Criptografia assimétrica com o RSA

Squid 3 - Instalação no Debian/Ubuntu

Snort - The Open Source Network Intrusion Detection System

Prey Project - Localizando seu notebook roubado

Servidor de DNS com DNS reverso, DHCP3 e wpad.dat

  
Comentários
[1] Comentário enviado por gustavo_marcon em 07/04/2004 - 19:19h

Cara, muito legal mesmo teu artigo, só achei que vc poderia ter dado uns toques de comandos que podem ser usados pra evitar por exemplo o SQL Injection, mas no mais, tá 10 mesmo. Parabéns.

[2] Comentário enviado por Ragen em 08/04/2004 - 00:31h

Olá Gustavo,

Note que logo abaixo de "O que é SQL injection" tem o que você quer "Escapando Strings", nessa parte é abordado como evitar os bendidos códigos maliciosos...

Só queria fazer mais um pequeno comentário:

Na parte onde eu falo sobre netcat eu fiz algumas pequenas mudanças desde a data de publicação do arquivo, por que eu deixo o assunto muito vago e sem nenhum exemplo concreto do seu uso....

Esse mesmo artigo pode ser encontrado em http://www.florecultura.com.br/bkp/artigo_tratamento.txt

[]`s

Ragen

[3] Comentário enviado por fabio em 11/04/2004 - 14:39h

Putz, acabou que com uma dica sua resolvi de forma trivial um problema que tinha no sistema de busca interno do site. Por exemplo, se você digitasse "sites celular" nada era encontrado. Daí mandei o sistema substituir espaços por %, agora buscas com palavras compostas funcionam. :)

Valeu pela dica!!!


Contribuir com comentário




Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts