Reconheça os riscos comuns na web
Mantenha os dados separados do código: consultas parametrizadas, codificação da saída e allowlists.
- Explicar por que misturar dados não confiáveis ao código causa injection
- Usar consultas parametrizadas e allowlists
- Codificar a saída para o contexto em que ela aparece
As aplicações web cruzam fronteiras de confiança o tempo todo: um texto digitado num navegador viaja até um servidor, entra numa consulta ao banco de dados e volta para uma página HTML. A raiz de toda uma família de bugs - injection (OWASP A05:2025) e cross-site scripting - é a mesma: dados não confiáveis são tratados como código.
Se um programa monta uma consulta ao banco colando a entrada do usuário no texto SQL, uma entrada bem escolhida pode mudar o significado da consulta, e não só os valores dela. A correção é nunca misturar os dois: mande a consulta e os valores separadamente.
1# Unsafe: the input becomes part of the SQL text
2cursor.execute("SELECT * FROM users WHERE name = '" + name + "'")
3
4# Safe: the query and the value travel separately
5cursor.execute("SELECT * FROM users WHERE name = ?", (name,))Com uma consulta parametrizada (também chamada de prepared statement), o banco de dados recebe o SQL com marcadores (?, %s ou :name) e os valores à parte. Um valor pode conter aspas, palavras-chave ou qualquer outra coisa - ele só vai ser comparado como dado. Toda biblioteca de banco de dados popular suporta isso; os ORMs fazem isso por você.
Algumas partes de uma consulta não podem ser parâmetros - nomes de tabelas, nomes de colunas, direção da ordenação. Para essas, use uma allowlist (lista de permissões): aceite só valores de uma lista fixa escrita por você e, caso contrário, use um padrão seguro.
Prática: ataque um formulário de login
Experimente
Até 15 XPInvada um aplicativo simulado com SQL injection
Veja a consulta mudar enquanto você digita. Primeiro, entre normalmente com o usuário ana e a senha blue-kettle-42. Depois experimente uma aspa simples no nome de usuário e veja o que o erro conta para um atacante.
Agora cumpra os objetivos. Use as dicas se travar.
Uma simulação: nenhum banco de dados ou rede real está envolvido.
SELECT * FROM users WHERE username = '' AND password = ''
- Entrar como admin sem a senha
- Fazer a consulta encontrar todos os usuários
- Ativar os parâmetros e ver um ataque falhar
Experimente
Até 15 XPSeguro ou inseguro?
Decida se cada trecho mantém os dados não confiáveis separados do código.
“cursor.execute("SELECT * FROM users WHERE email = %s", (email,))”
“cursor.execute(f"SELECT * FROM users WHERE email = '{email}'")”
“order = sort if sort in {"name", "price"} else "name"”
“os.system("convert " + uploaded_filename + " out.png")”
“subprocess.run(["convert", uploaded_filename, "out.png"])”
“element.innerHTML = "Hello " + username”
Codificando a saída
A mesma ideia vale ao mostrar dados numa página: para exibir um comentário como texto, os caracteres que significam algo em HTML (<, >, &, aspas) precisam ser convertidos em entidades como <. Motores de template como Jinja, React e a maioria dos outros fazem isso automaticamente - o perigo vem de desligar isso (|safe, dangerouslySetInnerHTML, innerHTML).
Principais conclusões
O injection acontece quando dados não confiáveis são interpretados como código.
Use consultas parametrizadas, listas de argumentos e allowlists para manter o código e os dados separados.
Codifique a saída para o contexto dela; mantenha ligada a codificação automática do framework.
Quiz da aula
7 perguntas · aprovação com 5 acertos · até 50 XP
Ao passar, você conclui a aula e mantém sua sequência. As perguntas erradas voltarão em sessões de revisão.
Pratique: escreva código em Python
Escreva código Python no editor e execute os testes com exemplos. O Python roda localmente no navegador usando WebAssembly.
Use uma allowlist para a coluna de ordenação
Nomes de colunas não podem ser parâmetros da consulta. Cada linha da entrada é column direction, pedida por um usuário. Imprima ORDER BY COLUMN DIRECTION, em que a coluna precisa ser name, price ou created_at (caso contrário, use created_at) e a direção ASC ou DESC, sem diferenciar maiúsculas de minúsculas (caso contrário, DESC).
- Pedidos válidos e inválidos
O Python é executado em um ambiente isolado no navegador, com limite de 60 segundos. O runtime é carregado pelo CDN do Pyodide; seu código permanece neste navegador.
Dúvidas sobre esta lição
Travou em algum ponto? Pergunte. Descobriu algo? Compartilhe. Explicar também é uma ótima forma de aprender.
Carregando publicações…