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".