Injeção de SQL
Muitos desenvolvedores web não sabem de como consultas SQL podem ser manipuladas, e presumem que uma consulta de SQL é um comando confiável. Significa que consultas SQL são capazes de passar indetectado por controles de acesso, portanto desviando da autenticação padrão e teestes de autorização, e algumas vezes consultas SQL podem permitir acesso à comando em nÃvel do sistema operacional do servidor.
Injeção direta de comandos SQL é uma técnica onde um atacante cria ou alterar comandos SQL existentes para expor dados escondidos, ou sobrescrever dados valiosos, ou ainda executar comandos de sistema perigosos no servidor. Isso é possÃvel se a aplicação pegar a entrada do usuário e combinar com parâmetros estáticos para montar uma consulta SQL. Os exemplos a seguir são baseados em estórias verdadeiras, infelizmente.
Devido a faulta de validação de entrada e conectar ao banco de dados usando o super-usuário ou um usuário que pode criar usuário, o atacante pode criar um super-usuário no seu banco de dados.
Example#1 Dividinto o result set em páginas ... e criando super-usuários (PostgreSQL)
<?php
$offset = $argv[0]; // Cuidado, sem validação de entrada!
$query = "SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET $offset;";
$result = pg_query($conn, $query);
?>
0; insert into pg_shadow(usename,usesysid,usesuper,usecatupd,passwd) select 'crack', usesysid, 't','t','crack' from pg_shadow where usename='postgres'; --
Nota: É uma técnica comum forçar o avaliador de SQL ignorar o resto da consulta escrita pelo desenvolvedor com --, que é o sinal de comentário no SQL.
Uma maneira de ganhar senha é desviar suas páginas de resultado de busca. A única coisa que o atacante precisa fazer é ver se alguma variável enviada é usada em um comando SQL que não é tratado corretamente. Esses filtros podem ser configurados de forma a personalizar cláusulas WHERE, ORDER BY, LIMIT e OFFSET em comandos SELECT Se seu banco de dados suporta a funcionalidade UNION, o atacante pode tentar adicionar uma consulta inteira à consulta original para listar senhas de uma tabela arbitrária. Uso de campos de senha criptografados é fortemente incentivado.
Example#2 Listando artigos ... e algumas senhas (qualquer banco de dados)
<?php
$query = "SELECT id, name, inserted, size FROM products
WHERE size = '$size'
ORDER BY $order LIMIT $limit, $offset;";
$result = odbc_exec($conn, $query);
?>
' union select '1', concat(uname||'-'||passwd) as name, '1971-01-01', '0' from usertable; --
Comandos de UPDATE também são suscetÃveis à ataques. Essas consultas também são ameaçadas por cortes e acréscimos de uma nova consulta. Mas o atacante pode brincar com a cláusula SET. Nesse caso ele precisa estar de posse de alguma informação sobre o esquema para manipular a consulta com sucesso. Isso pode ser conseguido examinando so nomes das variáveis do formulário, ou simplesmente por força bruta. Não existem muitas convensões para campos guardando senhas ou nomes de usuários.
Example#3 De reinicializando uma senha ... para ganhando mais privilégios (qualquer banco de dados)
<?php
$query = "UPDATE usertable SET pwd='$pwd' WHERE uid='$uid';";
?>
<?php
// $uid == ' or uid like'%admin%'; --
$query = "UPDATE usertable SET pwd='...' WHERE uid='' or uid like '%admin%'; --";
// $pwd == "hehehe', admin='yes', trusted=100 "
$query = "UPDATE usertable SET pwd='hehehe', admin='yes', trusted=100 WHERE
...;";
?>
Um exemplo assustado de como comandos do sistema operacional podem ser acessados em alguns bancos de dados.
Example#4 Atacando o sistema operacional do servidor (MSSQL Server)
<?php
$query = "SELECT * FROM products WHERE id LIKE '%$prod%'";
$result = mssql_query($query);
?>
<?php
$query = "SELECT * FROM products
WHERE id LIKE '%a%'
exec master..xp_cmdshell 'net user test testpass /ADD'--";
$result = mssql_query($query);
?>
Nota: Alguns dos exemplos acima estão ligados à bancos especÃficos. Isso não significa que um ataque similar é impossÃvel contra outros produtos. Seu servidor de banco de dados pode ter uma vulnerabilidade similar de outa maneira.
Técnicas para Evitar Ataques
Você pode dizer que o atacante precisa possuir um pouco de informação sobre o esquema de banco de dados na maioria dos exemplo. Você tem razão, mas você nunca sabe quando e como isso pode ser obtido e, se acontecer, seu banco de dados pode ficar exposto. Se você estiver usando um pacote open source publicamente disponÃvel para lidar com banco de deados, que pode pertencer a um sistema de controle de conteúdo ou forum, os invasores facilmente produzem uma cópia de parte de seu código. Também pode ser um risco de segurança se este for for mal desenhado.
Esses ataques se baseam principalmente em explorar falhas no código escrito sem se preocupar com segurança. Nunca confie em nenhum tipo de entrada, especialmente aquela que vem do lado do cliente, mesmo que venha de um combobox, um campo de entrada escondido (hidden) ou um cookie. O primeiro exemplo mostra como uma consulta inocente pode causar desastres.
- Nunca conecte ao banco de dados como um super-usuário ou como o dono do banco de dados. Sem use usuários personalidados com privilégios bem limitados.
- Verifique se uma entrada qualquer tem o tipo de dados experado. O PHP tem um grande número de funções de validação de entrada, desde as mais simples encontrada em Funções de Variáveis e em Funções de Tipo de Caracteres (ex.: is_numeric(), ctype_digit() respectivamente) além de usar o suporte à Expressões Regulares CompatÃvel com Perl.
-
Se a aplicação espera por entradas numéricas, considere verificar os dados com a função is_numeric(), ou silenciosamente mudar o seu tipo usando settype(), ou usar a representação númeria usando a função sprintf().
Example#5 Uma maneira mais segura para compor consultas de paginação
<?php
settype($offset, 'integer');
$query = "SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET $offset;";
// por favor perceba o %d na string de formato, usando %s seria inútil
$query = sprintf("SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET %d;",
$offset);
?> - Adicione aspas para cada valor não numérico especificado pelo usuário que será passado para o banco de dados com as funções de caracteres de escape (ex.: mysql_escape_string(), sql_escape_string(), etc.). Se um mecanismo de escape de caracter especÃfico par ao seu banco de dados não for disponÃvel, as funções addslashes() e str_replace() podem ser úteis (dependendo do tipo de banco de dados). Veja o o primeiro exemplo. Como o exemplo mostra, adicionar aspas para a parte estática da consulta não é suficiente, fazendo com que a consulta seja facilmente atacada.
- Não imprima qualquer informação especÃfica do banco de dados, especialmente sobre o esquema, custe o que custar. Veja também Relatório de Erros e Funções de Tratamento e Relatório de Erros.
- Você pode usar stored procedures e cursores previamente definidas para abstrair acesso aos dados para que os usuário não acessem tabelas ou view diretamente, mas essa solução pode ter outros impactos.
Além disso, você ganha em relatar consultas ou dentro do script ou no próprio banco de dados, se esse suportar. Obviamente, o relatório é para previnir qualquer tentativa danosa, mas pode ser útil para ajudar a rastrar qual aplicação foi atacada. O resitro não é útil em si, mas atráves da informação que ele contem. Mais detalhes geralmente é melhor que menos.