SQL Injection
Vulnerabilidade que permite ao atacante manipular códigos SQL passados da aplicação para o banco de dados, com objetivo de extrair, alterar ou até mesmo causar danos.
Consiste em influenciar o que é encaminhado ao banco de dados, explorando sintaxe e funcionalidades da linguagem SQL ou vulnerabilidades do banco de dados.
Os principais bancos de dados relacionais, como: MySQL, Oracle, SQL Server e DB2, utilizam o linguagem SQL para manipular os dados e estruturas.
A maioria das aplicações precisa de algum modo guardar as informações e para isso fazem uso de sistemas de banco de dados. O atacante aproveita do mau uso do banco de dados feito pelas aplicações para explorar vulnerabilidades com a técnica SQL Injection.
Exemplo 1
Queremos consultar livros por título e temos a seguinte consulta SQL:
Essa consulta obtém todos os livros que apresentam no título o texto '%Harry Potter%'
. Os sinais de %
indicam que pode haver mais texto antes ou depois do texto Harry Potter.
Podemos permitir que o usuário informe qual o texto que deve conter no título:
Então, temos uma variável texto
que é informada pelo usuário e concatenada na consulta SQL.
O que ocorre se o usuário informar no texto " '; DELETE FROM Livro; "
?
Teremos a seguinte consulta SQL:
Essa instrução SQL diz para consultar todos os livros que possuem um espaço em branco e depois apagar a tabela Livro inteira.
Existem outras técnicas para explorar a base de dados para encontrar todas as tabelas, mas quem quer causar problemas pode muito bem explorar essa vulnerabilidade até apagar todo o banco de dados.
Exemplo 2
Realizando a autenticação de um usuário, se a consulta retornar o login é porque é um usuário válido:
Um usuário correto poderia informar dados corretos como: var1 = "anderson"
e var2 = "coordenador"
.
Mas um usuário mal intencionado, poderia passar informações que o fizessem ter acesso indevido, como var1 = "%A%"
e var2 = "sqlinjection' or '2'= '2"
.
Essa consulta vai retornar todos os usuários com a letra A
no login, ignorando a senha porque a condição or '2' = '2'
sempre será verdadeira.
Como encontrar SQL Injection na aplicação
Para verificar se a aplicação possui a vulnerabilidade SQL Injection, duas formas simples de verificar são:
-
Procure por concatenação de SQL com conteúdos informados pelos usuários.
-
Procure todas variáveis que seu conteúdo são informados pelo usuário, e verifique quais variáveis não são validadas.
Previnindo a vulnerabilidade SQL Injection
Cinco pontos para você
- Definir tamanho mínimo e máximo para cada campo informado pelo usuário.
- Validar o conteúdo informado pelo usuário. Essa validação deve ocorrer tanto no front (nas telas) como no back-end (acesso ao banco de dados ou outros pontos de uso da informação) da aplicação.
- Não concatenar diretamente o conteúdo informado com o SQL, a seguir mostro como fazer isso na aplicação Java.
- O usuário de banco de dados que é utilizado pela aplicação precisa ter controle de nível de acesso. Verifique quais permissões são necessárias para executar a aplicação, na maioria das vezes não deveria ter permissão para deletar uma tabela por exemplo.
- Auditoria do código-fonte regularmente. Revise o código regularmente, procure sempre pelos quatro pontos mencionados anteriormente e divulgue entre os desenvolvedores essa vulnerabilidade.
Como evitar o uso incorreto do banco de dados no Java
Na aplicação Java quando usamos JDBC para acessar o banco de dados, encontramos a opção de fazer isso usando a classe Statement
:
Mas nessa abordagem temos o problema de concatencar os dados informados pelo usuário com as instruções SQL. Uma forma simples de resolver isso é usando a classe PreparedStatement
do JDBC:
Note como usamos o ?
no lugar das variáveis e depois usamos o método apropriado como pstm.setString(1, var1)
para definir os valores que serão informados. Essa abordagem é muito melhor que a anterior, porque o PreparedStatemet
vai adicionar escape nos caracteres que são sensíveis nas instruções SQL.
Se a aplicação usa o JPA, evite criar query nativa, como essa:
Porque voltamos ao problema original de concatenar dados com instruções SQL. Prefira usar NamedQuery
ou Criteria
, nesse post explico como usar queries no JPA.
Na NamedQuery
definimos uma consulta usando o JPAQL que é muito similar ao SQL, mas na passagem parâmetros não precisamos concatenar diretamente os valores informados pelo usuário:
E quando usamos essa NamedQuery
passamos os parâmetros e o JPA vai adicionar escape nos caracteres que são sensíveis nas instruções SQL.
Conteúdos relacionados
- Conhecendo e previnindo a vulnerabilidade Cross-site scripting
- Introdução a criptografia
- Criptografia simétrica utilizando chave privada
- Criptografia assimétrica utilizando um par de chaves pública/privada