Boas práticas e padrões · Segurança no código · 6 min de leitura
Validação de entrada e injeção (SQL, XSS, comandos)
Todo dado que vem de fora é suspeito. Valide no servidor, nunca monte SQL, HTML ou comandos concatenando texto do usuário — use parâmetros e escape por contexto.
Arraste para o lado para ver o diagrama inteiro.
Injeção
Injeção (A05 no OWASP Top 10:2025) acontece quando um dado é interpretado como código: "SELECT * FROM users WHERE email = '" + email + "'" com o e-mail ' OR '1'='1 devolve todos os usuários. O mesmo vale para HTML (XSS), comandos do sistema, LDAP e caminhos de arquivo (../../).
A defesa não é "limpar caracteres perigosos", é separar dado de código: consultas parametrizadas (ou ORM), APIs que recebem argumentos em lista em vez de uma string de shell, e escape automático do framework de templates.
Validação
- No servidor, sempre. A validação no app ou no navegador é conforto, não segurança: qualquer um chama a API direto.
- Lista do que é permitido (formato, tamanho, intervalo, enum) é melhor que lista do que é proibido.
- Valide com um esquema (Zod, kotlinx.serialization + regras, Codable + checagens) na borda e trabalhe com tipos já válidos por dentro.
XSS
No navegador, nunca coloque texto do usuário em innerHTML; use textContent ou deixe o framework escapar. Se precisar de HTML do usuário, passe por um sanitizador (DOMPurify) e configure uma Content-Security-Policy.
No código: antes e depois
app.get('/usuarios', async (req, res) => {
const email = req.query.email as string;
const rows = await db.query(`SELECT * FROM usuarios WHERE email = '${email}'`); // injeção
res.send(`<h1>Olá, ${rows[0]?.nome}</h1>`); // XSS se o nome tiver <script>
}); import { z } from 'zod';
const Query = z.object({ email: z.string().email().max(254) });
app.get('/usuarios', async (req, res) => {
const parsed = Query.safeParse(req.query);
if (!parsed.success) return res.status(400).json({ erro: 'e-mail inválido' });
// O driver envia o valor separado do SQL: ele nunca é interpretado como código
const rows = await db.query('SELECT nome FROM usuarios WHERE email = $1', [parsed.data.email]);
res.json({ nome: rows[0]?.nome ?? null }); // JSON: o front mostra com textContent
}); Validação na borda, parâmetro $1 no lugar da concatenação e dados devolvidos como JSON em vez de HTML montado à mão.
Em resumo
- Dado de fora nunca vira código.
- Consultas parametrizadas, sempre.
- Valide no servidor, com lista do permitido.
- textContent, não innerHTML.
Perguntar à IA
Monte um prompt pronto sobre Validação de entrada e injeção (SQL, XSS, comandos) na sua linguagem e no seu caso, e abra num chat gratuito.
O prompt vai para o site que você escolher. Não cole senhas, tokens nem dados reais de clientes. Para Gemini e outros, copie e cole.