Validação, sanitização e prevenção de ataques de injeção

Aprende como a validação e a sanitização de dados protegem os formulários de ataques de injeção e o que torna os dados de um formulário seguros.

Rascunho

Quando os atacantes visam formulários, não os preenchem como toda a gente. Em vez disso, enviam código pensado para entrar nos teus sistemas ou roubar dados. Podem submeter JavaScript para correr nos navegadores dos visitantes, comandos SQL para danificar a tua base de dados ou conteúdo malicioso para causar estragos. A validação e a sanitização de dados são as defesas que travam estes ataques.

O que vais aprender: o que são a validação e a sanitização, em que diferem, como funcionam os ataques de injeção, que proteções servem para cada tipo de dados e como aplicá-las nos teus formulários.

O que é a validação de dados?

A validação é o processo de verificar se os dados submetidos no teu formulário estão no formato esperado e cumprem os teus requisitos. É a primeira linha de defesa contra dados maliciosos.

A validação responde a perguntas como: isto é um endereço de email ou texto aleatório? É um número ou uma palavra? Este campo está vazio quando não devia estar? O visitante escreveu algo que faz sentido para este campo ou algo suspeito?

Exemplos do que a validação verifica:

  • Um campo de email deve conter um símbolo @ e um domínio
  • Um campo de número de telefone deve conter apenas dígitos e hífenes
  • Um campo numérico não deve conter letras
  • Um campo obrigatório não deve estar vazio
  • Um campo de palavra-passe deve cumprir o comprimento mínimo

A validação acontece em dois sítios. No dispositivo do visitante, chama-se validação no cliente. No teu servidor, chama-se validação no servidor. A validação no cliente dá feedback imediato ao visitante se este se enganar. A validação no servidor é a que protege mesmo contra ataques, porque os atacantes conseguem contornar as verificações no cliente.

O que é a sanitização de dados?

A sanitização é o processo de remover ou neutralizar tudo o que é perigoso nos dados introduzidos pelo utilizador antes de os guardares ou tratares. Mesmo que os dados passem na validação, ainda podem conter código ou caracteres pensados para causar danos.

Exemplos do que a sanitização faz:

  • Remove etiquetas HTML como `<script>` e `<img>` dos campos de texto
  • Remove caracteres especiais de SQL que podiam ser usados para entrar nas bases de dados
  • Faz o escape de caracteres especiais para que sejam tratados como texto e não como código
  • Limita o comprimento dos dados para evitar ataques de buffer overflow

A validação e a sanitização funcionam em conjunto, mas servem propósitos diferentes. A validação verifica se os dados estão no formato certo. A sanitização remove tudo o que é perigoso, mesmo que o formato esteja tecnicamente correto.

Como funcionam os ataques de injeção

Injeção de SQL

Um ataque de injeção de SQL acontece quando um atacante coloca código SQL num campo do formulário. Se o código do teu formulário não sanitizar estes dados, o código SQL é executado na tua base de dados.

Exemplo: um formulário de início de sessão pede um endereço de email. Em vez de submeter o email, um atacante submete:

' OR '1'='1

Se o teu formulário não sanitizar isto, o teu código pode executar uma consulta SQL como:

SELECT * FROM users WHERE email = '' OR '1'='1'

A parte `OR '1'='1'` faz com que a condição seja sempre verdadeira, por isso a consulta devolve todos os utilizadores em vez de apenas aquele com esse email. O atacante contornou assim o sistema de início de sessão.

Cross-Site Scripting (XSS)

Um ataque XSS acontece quando um atacante submete código JavaScript num campo do formulário. Se o formulário não sanitizar este código e o guardar, o JavaScript corre nos navegadores de quem ver esses dados mais tarde.

Exemplo: um formulário de comentários aceita comentários de utilizadores. Um atacante submete:

<script>alert('hacked')</script>

Se isto não for sanitizado e ficar guardado na base de dados, quando alguém abrir a secção de comentários o JavaScript corre e mostra um alerta. Uma versão mais perigosa podia roubar cookies, redirecionar visitantes para uma página de phishing ou extrair dados de formulários.

Injeção de comandos

Se os dados do teu formulário forem usados em comandos do sistema (o que acontece em alguns sistemas de backend), um atacante pode injetar comandos do sistema operativo.

Exemplo: um campo do formulário é usado num comando como:

ffmpeg -i $filename output.mp4

Se `$filename` não for sanitizado e um atacante submeter `;rm -rf /`, o comando passa a ser:

ffmpeg -i ;rm -rf / output.mp4

O comando `rm -rf /` é executado e apaga ficheiros do sistema. É por isso que os comandos do sistema nunca devem receber dados de utilizadores sem sanitização.

Validação e sanitização para diferentes tipos de dados

Endereços de email

Validação: verifica se o texto corresponde a um padrão de email (algo como texto@dominio.extensao). Confirma que tem apenas caracteres permitidos.

Sanitização: remove etiquetas HTML e caracteres especiais. Mantém apenas caracteres alfanuméricos, pontos, hífenes e o símbolo @.

Números de telefone

Validação: verifica se contém apenas dígitos, hífenes, parênteses e espaços. Confirma que o comprimento está certo para o país esperado.

Sanitização: remove todos os caracteres não numéricos, exceto hífenes e parênteses. Retira zeros ou espaços à esquerda, se for preciso.

Campos de texto (comentários, nomes, moradas)

Validação: verifica se o campo não está vazio e se o comprimento é razoável (não milhões de caracteres).

Sanitização: remove ou faz o escape de etiquetas HTML, JavaScript e caracteres especiais de SQL. Mantém apenas texto simples e pontuação básica.

Números e montantes

Validação: verifica se o valor é um número. Para preços ou quantidades, verifica se é um número positivo.

Sanitização: remove todos os caracteres não numéricos. Se for preciso, arredonda para o número certo de casas decimais.

Palavras-passe

Validação: verifica o comprimento mínimo (pelo menos 8 caracteres) e, se quiseres, exige uma mistura de maiúsculas, minúsculas, números e símbolos.

Sanitização: não removas nem alteres palavras-passe. Devem ser guardadas exatamente como estão (com hash, nunca em texto simples). Se retirares caracteres a uma palavra-passe, os utilizadores deixam de conseguir iniciar sessão.

Carregamento de ficheiros

Validação: verifica se o tipo de ficheiro é o esperado (por exemplo, apenas ficheiros PDF, apenas imagens). Verifica se o tamanho do ficheiro não é demasiado grande.

Sanitização: muda o nome do ficheiro para que os atacantes não possam usar nomes especiais. Analisa o ficheiro à procura de malware. Guarda-o fora da raiz web para que não possa ser executado como código.

Como aplicar a validação e a sanitização

No cliente (no navegador)

Usa os atributos de validação do HTML5 para dar feedback imediato aos visitantes:

<input type="email" name="email" required> <input type="tel" name="phone" pattern="[0-9]{10}"> <input type="number" name="age" min="0" max="120">

Isto apanha os erros óbvios e melhora a experiência do utilizador. No entanto, a validação no cliente pode ser contornada, por isso não é, por si só, uma medida de segurança.

No servidor (no teu servidor)

É aqui que a segurança acontece. O teu código de backend tem de validar e sanitizar cada dado:

// Pseudo-code example if (email does not match email pattern) { reject the submission } // Remove HTML tags sanitized_comment = remove_html_tags(comment_text) // Escape special characters for database safe_name = escape_sql_characters(user_name) // Only then store the data store_in_database(safe_name, sanitized_comment)

Usa consultas parametrizadas nas bases de dados

A melhor defesa contra a injeção de SQL são as consultas parametrizadas (também chamadas prepared statements). Em vez de pôr os dados do utilizador diretamente numa consulta SQL, usas marcadores de posição e passas os dados em separado:

// Bad (vulnerable): query = "SELECT * FROM users WHERE email = '" + email + "'" // Good (safe): query = "SELECT * FROM users WHERE email = ?" execute(query, [email])

Com consultas parametrizadas, o analisador de SQL sabe que o que o utilizador escreveu são dados e não código. Mesmo que um atacante submeta código SQL, ele é tratado como texto simples.

Usa bibliotecas e frameworks

Não escrevas código de sanitização de raiz. Usa bibliotecas consolidadas, criadas para este fim. Em PHP, usa htmlspecialchars() ou uma biblioteca como o HTML Purifier. Em Python, usa o módulo `html` ou uma biblioteca como o bleach. Em Node.js, usa o `express-validator` ou algo semelhante. Estas bibliotecas foram testadas e são atualizadas para lidar com novos tipos de ataque.

Erros comuns de validação e sanitização

Validar apenas no cliente. A validação no cliente serve a experiência do utilizador, não a segurança. Um atacante consegue contorná-la. Tens de validar também no servidor.

Bloquear caracteres perigosos em vez de permitir só os seguros. Se tentares travar a injeção de SQL removendo ponto e vírgula e aspas, os atacantes vão encontrar formas de a contornar. Em vez disso, permite apenas os caracteres que esperas (num número de telefone, só dígitos e hífenes) e rejeita tudo o resto.

Confiar no tipo de dados do campo do formulário. Se tens um campo numérico, o navegador envia texto que parece um número. O teu servidor tem de verificar na mesma que é mesmo um número antes de o usar. Nunca presumas que o tipo de dados está correto.

Esquecer-te de sanitizar os dados que são mostrados. Mesmo que os dados estejam guardados em segurança, se os mostrares numa página web sem fazer o escape do HTML, os atacantes podem injetar código que corre nos navegadores dos visitantes quando virem esses dados.

Sanitizar pela ordem errada. Valida primeiro (isto está no formato certo?) e só depois sanitiza (isto é seguro?). Se sanitizares e depois validares, podes rejeitar dados que afinal eram seguros.

O que o WEMASY faz pela validação de dados

O WEMASY valida os campos do formulário automaticamente, consoante o tipo de campo que escolheres. Os campos de email são verificados quanto ao formato de email válido. Os campos numéricos são verificados quanto a valores numéricos. Os campos obrigatórios são verificados quanto a conteúdo antes do envio. No servidor, o WEMASY sanitiza todos os dados para remover HTML, JavaScript e outro código perigoso antes de guardar os envios. Tu defines que campos recolher, e o WEMASY trata da validação e da sanitização nos bastidores.

Vê que funcionalidades de formulários estão incluídas no teu plano na página de preços.

Perguntas frequentes

Posso usar uma WAF (Web Application Firewall) em vez da validação?
Uma WAF pode travar alguns ataques de injeção antes de chegarem ao teu formulário, o que ajuda. No entanto, não substitui a validação e a sanitização. Uma WAF é uma segunda linha de defesa. O código do teu formulário tem de continuar a validar e a sanitizar os dados. Usar a WAF e a validação de dados em conjunto dá-te várias camadas de proteção.
E se um visitante precisar mesmo de submeter caracteres especiais?
Caracteres especiais como apóstrofos, hífenes e "e comerciais" são seguros se sanitizares bem. Por exemplo, alguém pode ter um nome como "O'Brien" ou "Mary-Jane". Podes aceitá-los em segurança se fizeres o escape correto para a base de dados (com consultas parametrizadas) e ao mostrá-los (com escape de HTML). O segredo é uma sanitização correta, não bloquear os caracteres.
Devo validar no cliente e no servidor?
Sim. A validação no cliente dá feedback imediato aos visitantes e melhora a experiência (sabem que se enganaram a escrever antes de enviar). A validação no servidor é a que protege mesmo contra ataques. Usa as duas camadas. O cliente serve a experiência do utilizador. O servidor serve a segurança.
Qual é a diferença entre escape e sanitização?
O escape converte caracteres perigosos para que sejam tratados como texto simples (por exemplo, transformar < em <). A sanitização remove o conteúdo perigoso por completo (por exemplo, retirar todas as etiquetas HTML). O escape mantém os dados; a sanitização remove a ameaça. Na maioria dos dados de formulários, a sanitização (remover as etiquetas por completo) é mais segura do que o escape (convertê-las).
Tenho de me preocupar com ataques de injeção em formulários só de leitura?
Se um formulário só mostra informação (não submete nada), não tem vulnerabilidade de injeção. No entanto, se esse formulário alguma vez mostrar dados submetidos por utilizadores, continuas a ter de sanitizar. Um atacante pode ter submetido código malicioso antes e, quando o mostrares, esse código corre. Sanitiza sempre os dados submetidos por utilizadores antes de os mostrares, seja qual for o tipo de formulário.

Põe isto em prática
no teu próprio site.

Começa grátis com a WEMASY e cria o teu site em poucos minutos.