CodeGym /Cursos /SQL SELF /Proteção contra SQL injection e outros ataques: PREPARE, ...

Proteção contra SQL injection e outros ataques: PREPARE, EXECUTE, parameterized queries

SQL SELF
Nível 48 , Lição 3
Disponível

Então, primeiro vamos entender o que estamos protegendo, ou melhor, de quem. No começo desse nível a gente já falou sobre SQL injection, um dos ataques mais populares e destrutivos contra bancos de dados. O ataque funciona assim: o malandro manda código SQL malicioso no seu query pra tentar "enganar" e acessar dados que ele não deveria. Agora bora ver isso mais de perto.

Exemplo de SQL injection

Imagina que você tem um app web com um campo simples de usuário e senha. O backend faz um query SQL pra checar se o usuário existe no banco:

SELECT * FROM users WHERE username = 'admin' AND password = 'password123';

Esse query parece beleza... enquanto o usuário coloca dados certos. Mas o que acontece se alguém digitar:

  • Nome de usuário: admin' --
  • Senha: (deixa esse campo vazio)

No final, o query vira algo assim:

SELECT * FROM users WHERE username = 'admin' -- AND password = 'password123';

Repara nos --, que no SQL marcam o começo de um comentário. Tudo que vem depois é ignorado. Resultado: a checagem da senha é pulada e o malandro entra como admin!

Consequências potenciais do SQL injection

SQL injection pode causar uns problemas cabulosos:

  1. Acesso não autorizado aos dados. Por exemplo, o cara pode pegar dados confidenciais tipo senhas dos usuários.
  2. Deletar ou modificar dados. Alguém pode apagar uma tabela inteira ou bagunçar tudo.
  3. Executar qualquer código SQL. Imagina o cara rodando DROP DATABASE... É pesadelo na certa.

Mas a gente não é de se assustar fácil! O PostgreSQL tem várias ferramentas pra ajudar a proteger contra esses ataques.

Como se proteger? Métodos pra evitar SQL injection

  1. Usar prepared statements (PREPARE e EXECUTE)

Prepared statements são tipo uma receita testada pro seu código SQL. Funciona assim: você "prepara" o query uma vez e depois manda os dados separados. Isso impede que código malicioso seja injetado.

Olha um exemplo do jeito certo:

Prepare o query usando PREPARE.

PREPARE user_login (text, text) AS
SELECT * 
FROM users 
WHERE username = $1 AND password = $2;

O query com dois parâmetros $1 e $2 espera que os valores reais sejam passados depois.

Use EXECUTE pra rodar o query.

EXECUTE user_login('admin', 'password123');

Nesse esquema, o PostgreSQL escapa tudo que é dado do usuário automaticamente, bloqueando SQL malicioso.

Vantagens desse jeito:

  • Não tem como fazer SQL injection, porque os parâmetros são tratados só como dados, não como parte do código SQL.
  • Os queries ficam mais seguros e rápidos, porque o plano de execução é cacheado.
  1. Parameterized queries

Esse método é bem comum em apps feitos em linguagens tipo Python ou Java. Em vez de mexer manualmente com PREPARE e EXECUTE, você pode usar libs ou ORM que já cuidam dos parâmetros pra você.

Exemplo com Python e a lib psycopg2:

import psycopg2

connection = psycopg2.connect(
    dbname="your_db",
    user="your_user",
    password="your_password",
    host="localhost",
    port="5432"
)

cursor = connection.cursor()

# Usando parameterized query
username = "admin"
password = "password123"
query = "SELECT * FROM users WHERE username = %s AND password = %s"
cursor.execute(query, (username, password))

# Seus dados estão totalmente seguros!
result = cursor.fetchall()
print(result)

Repara no %s no query SQL — é ali que o parâmetro entra. A lib psycopg2 cuida de passar os dados de forma segura.

  1. Validação dos dados de entrada

Se você tá passando dados que o usuário digitou, garante que eles estão do jeito que você espera. Por exemplo:

  • Pra dados de texto, usa regex pra garantir que não tem caracteres proibidos.
  • Pra dados numéricos, garante que são realmente números.

Exemplo em Python:

import re

username = input("Digite o nome de usuário: ")

# Só permite letras, números e underline
if re.match(r"^\w+$", username):
    print("Nome de usuário está ok")
else:
    print("Nome de usuário perigoso!")
  1. Usar privilégios mínimos

Garante que as roles usadas pra rodar queries tenham só os privilégios necessários. Por exemplo, não dá permissão pra DROP TABLE ou ALTER TABLE se não precisar.

  1. Logar ações suspeitas

Você pode usar parâmetros do PostgreSQL pra monitorar a atividade dos usuários:

  • log_statement = 'all' — loga todos os queries.
  • log_connections = on — loga todas as conexões no banco.

Esses parâmetros ajudam a identificar ações suspeitas.

Exemplos de implementação

Exemplo 1: Usando prepared statement via SQL

-- Vamos criar um prepared statement
PREPARE check_credentials (text, text) AS
SELECT * FROM users WHERE username = $1 AND password = $2;

-- Executa o query com parâmetros seguros
EXECUTE check_credentials('admin', 'password123');

Exemplo 2: Parameterized query em Python

query = "UPDATE users SET last_login = NOW() WHERE username = %s"
username = "admin"
cursor.execute(query, (username,))

Dicas de segurança

Sempre valide os dados de entrada. Nunca confie nos dados que vêm do usuário.

Use só prepared statements ou parameterized queries. Esses métodos são sua principal defesa contra SQL injection.

Dê privilégios mínimos pras roles. Assim, se alguém invadir, o estrago é menor.

Configure o log e revise os logs com frequência. Fique ligado no que tá rolando no seu banco.

SQL injection é um bicho feio, mas usando prepared statements, parameterized queries e boas práticas, você protege seu banco e dorme tranquilo, sem medo de alguém "sem querer" apagar todas as suas tabelas. O PostgreSQL te dá todas as ferramentas pra isso, então bora pra cima!

Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION