SQL Injection em ADVPL: Como me proteger?
Aloha!
Nesse meu primeiro texto venho falar de um assunto bem crítico e que possui uma forma bem tranquila de ser tratado: SQL Injection.
O que é SQL Injection?
SQL Injection, ou Injeção SQL, é uma falha onde é possível injetar código SQL dentro de uma consulta que o sistema executa no Banco de Dados.
Para entender melhor vamos imaginar o seguinte cenário:
Temos uma aplicação com uma tela simples de login: Usuário, Senha e um botão de Login. Ao clicar no botão a aplicação pega o valor das variáveis de user e password e monta a consulta para executar no banco da seguinte maneira:
"SELECT *
FROM users
WHERE username = '"+ user +"' AND password = '"+ password + "'"
Supondo que a pessoa digitou meu_usuario e a senha 123, teremos a seguinte consulta:
SELECT *
FROM users
WHERE username = 'meu_usuario' AND password = '123'
Agora vamos supor que uma pessoa má intencionada digite no lugar campo de user o seguinte valor: ‘ OR 1=1 — , parece um texto sem sentido certo?? Mas vamos ver como que ficaria na nossa consulta:
SELECT * FROM users WHERE username = '' OR 1=1--' AND password = '123'
Veja que foi injetado na consulta um OR 1 =1, com isso ela sempre retornará resultados e mesmo sem validar usuário e senha o login será feito! :O
Prepared Statement
Para evitar essa injeção podemos utilizar o conceito de Prepared Statement, onde montamos uma consulta pré-definida, e depois injetamos somente os parâmetros que são alteráveis nela. Com isso os parâmetros são tratados individualmente, evitando a injeção.
Para identificar os parâmetros, substituímos seus valores pelo caractere ‘?’.
Para exemplificar vou mostrar como ficaria nossa consulta:
SELECT * FROM users WHERE username=? AND password=?
Para se beneficiar do Prepared Statement em AdvPL basta utilizar a classe FWPreparedStatement
//Inicializa as variáveis
oStatement := FWPreparedStatement():New()
cQuery := "SELECT * FROM users WHERE username=? AND password=?"
//Define a consulta e os parâmetros
oStatement:SetQuery(cQuery)
oStatement:SetString(1,cUser)
oStatement:SetString(1,cPassword)
//Recupera a consulta já com os parâmetros injetados
cFinalQuery := oStatement:GetFixQuery()
Se passarmos os mesmos parâmetros do exemplo, teremos o seguinte resultado:
SELECT * FROM users WHERE username=''' OR 1=1--' AND password='123'
Obs.: Este é um exemplo bem simples, sabemos que por exemplo senhas não devem ser gravadas diretas no banco. O intuito é apenas demonstrar o uso de Prepared Statement para evitar SQL Injection.
Espero que esse texto tenha sido útil!
Até breve!