Como Validar Expressões Regulares de Forma Segura
Descubra o backtracking catastrófico e os ataques ReDoS. Aprenda a validar expressões regulares de forma segura e com padrões de código eficientes.

No desenvolvimento de software moderno, saber validar expressões regulares (comumente chamadas de regex) com segurança tornou-se um pilar fundamental para garantir a estabilidade das aplicações. As expressões regulares são recursos extremamente eficientes para busca e manipulação de padrões de texto. Contudo, se forem escritas sem os devidos cuidados, podem expor os sistemas a graves riscos de segurança.
Um padrão regex mal formulado permite que agentes maliciosos realizem ataques de Negação de Serviço (DoS) ao esgotar os recursos de CPU dos servidores. Esse tipo de vulnerabilidade é conhecido como ReDoS (Regular Expression Denial of Service) e é provocado pelo backtracking catastrófico. Neste guia de segurança, explicaremos o funcionamento dessas vulnerabilidades, como encontrá-las em seu código e como testar e construir padrões de maneira segura.
O que é uma Expressão Regular e por que ela pode ser insegura?
Expressões regulares são sequências de caracteres que estabelecem padrões de pesquisa em textos. Elas são amplamente utilizadas para validar formatos (como e-mails, números de telefone, CEPs) ou para extrair blocos específicos de caracteres de um volume de dados.
A vulnerabilidade das expressões regulares não decorre de falhas de estouro de buffer tradicionais ou injeções de código malicioso direto, mas sim da complexidade algorítmica do motor de execução encarregado de processá-las. A maior parte dos motores de regex usados em linguagens como JavaScript, Python, PHP, Ruby e .NET implementa um algoritmo de busca baseado em Automato Finito Não Determinístico (NFA).
Um motor NFA oferece grande flexibilidade, suportando recursos complexos como referências retroativas (backreferences) e asserções condicionais de busca ao redor (lookarounds). No entanto, essa flexibilidade tem um preço: quando o motor encontra um padrão ambíguo associado a uma cadeia de entrada conflitante, ele precisa testar diversos caminhos de correspondência recursivamente. Se a quantidade de caminhos crescer exponencialmente com o tamanho do texto recebido, o servidor pode travar por completo.
O perigo do backtracking catastrófico e dos ataques ReDoS
O backtracking catastrófico acontece quando o motor regex avalia um texto que não corresponde ao padrão esperado, mas que apresenta grande similaridade inicial. Para encontrar uma correspondência válida, o motor avança caractere por caractere. Ao se deparar com uma incompatibilidade no caminho, ele retorna (backtracks) a um estado anterior para tentar um caminho de análise alternativo.
Quando o padrão regex contém quantificadores de repetição aninhados (por exemplo, *, + ou {n,} inseridos dentro de outros grupos que também se repetem), a quantidade de caminhos alternativos que o autômato é obrigado a verificar multiplica-se de forma exponencial, e não linear.
Um atacante ciente dessa dinâmica pode submeter uma string de tamanho moderado (de 30 a 50 caracteres) formatada para falhar no último caractere do processo. Isso força o motor NFA a calcular bilhões de permutações de backtracking antes de declarar que o texto não atende ao padrão. Essa operação monopoliza a thread do processador, elevando o uso de CPU do servidor para 100% e deixando o serviço inacessível para todos os outros usuários.
O papel das asserções Lookaround na segurança de regex
As asserções lookaround (lookahead e lookbehind) são testes de largura zero que permitem verificar se um padrão existe antes ou depois de outra sequência de texto, sem incluir esses caracteres adicionais no resultado final. Embora úteis para impor regras de complexidade de senhas, elas podem criar vulnerabilidades ReDoS silenciosas se contiverem quantificadores de tamanho variável.
Considere o seguinte exemplo:
(?=\w+)\d+
Quando um bloco lookaround armazena quantificadores de tamanho variável (+, *, {n,}), o motor de busca deve analisar a string adiante repetidas vezes. Caso a verificação externa falhe e retroceda, o lookaround interno será recalculado a cada índice do texto. Essa sobreposição eleva a complexidade de tempo de execução do autômato, facilitando a ocorrência de latência extrema.
Exemplo Prático de Backtracking Catastrófico
Para visualizar na prática como um padrão vulnerável reage, analisemos o seguinte padrão desenvolvido para validar uma cadeia de caracteres específicos seguida por um dígito:
^(a+)+$
Este padrão parece inofensivo: ele busca por uma ou mais letras a, repetidas uma ou mais vezes, desde o início (^) até o final ($) do texto. No entanto, por aninhar o quantificador + dentro de outro +, as formas que o motor NFA tem para organizar os agrupamentos das letras aumentam exponencialmente.
Ao testarmos a string aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa (30 letras a), o motor encontra a correspondência em microssegundos. Contudo, se enviarmos a cadeia aaaaaaaaaaaaaaaaaaaaaaaaaaaaaab (30 letras a seguidas por um b), o cenário muda de forma crítica.
O motor NFA tenta validar os caracteres a com sucesso, mas falha no caractere b. Em vez de encerrar a execução, ele retrocede para verificar cada uma das configurações possíveis de divisão das letras a anteriores para conferir se alguma delas permite a validação da string inteira.
// Simulação de execução de Regex vulnerável no Node.js
function testarRegexVulneravel() {
const padraoVulneravel = /^(a+)+$/;
const entradaMaliciosa = "a".repeat(30) + "b"; // 30 letras 'a' e um 'b'
console.log("Iniciando processamento da string...");
const inicio = performance.now();
// Esta chamada pode congelar a execução do Node.js por vários segundos
const resultado = padraoVulneravel.test(entradaMaliciosa);
const fim = performance.now();
console.log(`Processamento concluído. Compatível?: ${result}`);
console.log(`Tempo total: ${(fim - inicio).toFixed(2)} ms`);
}
testarRegexVulnerable();
Com apenas 30 caracteres na entrada, o tempo de teste deste script pode consumir vários segundos do servidor. Ao subirmos a string para 40 caracteres, a CPU trabalhará de forma contínua por horas ou dias inteiros para finalizar o mesmo processamento.
Práticas Recomendadas para Desenvolver Regex Seguras
Reduzir a incidência de ataques ReDoS e garantir que suas regras de validação permaneçam seguras exige a adoção de hábitos de programação defensiva:
1. Evitar ambiguidade e sobreposições de quantificadores
Certifique-se de que os seus padrões não permitam múltiplos caminhos de agrupamento. Em vez de escrever regras genéricas como (\w+)* ou (\s|\s+)*, estruture expressões mais lineares e bem delimitadas.
2. Implementar tempos limite de processamento (Timeouts)
Ao realizar buscas por regex em servidores de produção (principalmente em ambientes assíncronos como Node.js), configure limites de tempo (timeouts). Se uma avaliação demorar mais do que 50 ou 100 milissegundos, interrompa a execução do processo imediatamente.
3. Utilizar motores de processamento linear (DFA)
Sempre que possível, opte por ferramentas baseadas em Autômatos Finitos Determinísticos (DFA) ou algoritmos de tempo de execução linear, como a biblioteca RE2 do Google. A RE2 assegura tempos de processamento proporcionais ao tamanho da string de entrada ($O(n)$) ao não dar suporte a recursos complexos de backtracking.
Comparativo de Padrões Vulneráveis vs. Padrões Seguros
| Caso de Uso | Padrão Vulnerável (ReDoS) | Alternativa Segura | Explicação Técnica |
|---|---|---|---|
| Validação de Texto Comum | ^(\w+)*$ |
^\w*$ |
Elimina a repetição redundante e o agrupamento aninhado. |
| Listas separadas por vírgula | ^([^,]+,)*[^,]+$ |
^[^,]+(,[^,]+)*$ |
Estrutura a busca sem solapar agrupamentos contínuos. |
| Espaços opcionais em branco | \s*\d+\s* |
\s\d+\s (ou limitado com {1}) |
Evita laços infinitos na varredura de caracteres opcionais. |
Incorporar estes padrões em seu desenvolvimento diário evitará grandes problemas de performance e instabilidade. Para saber mais sobre como projetar software robusto, veja o nosso artigo sobre desenvolvimento web seguro e blindagem OWASP ou leia o nosso guia prático sobre auditoria de código SAST e DAST.
Ferramenta Recomendada: Testador de Regex da TecnoCrypter
Para verificar se as suas expressões regulares contêm falhas latentes de performance ou backtracking catastrófico antes de colocá-las em ambiente produtivo, recomendamos utilizar o nosso Testador de Regex da TecnoCrypter.
Esta ferramenta interativa permite inserir seus padrões, testá-los em tempo real contra diversos formatos de strings e medir o desempenho geral do processamento. Executando testes de estresse simulados e mapeando os caminhos da expressão, o testador ajuda a prevenir loops de execução infinitos e a refinar os seus padrões para garantir alto desempenho e estabilidade.
Conclusão
Validar dados de entrada usando expressões regulares é uma tarefa de rotina no desenvolvimento, mas que requer atenção. Padrões mal planejados são um convite para ataques de ReDoS destrutivos. Ao desenhar expressões mais limpas, estipular tempos limite para análise, preferir bibliotecas lineares como a RE2 e testar previamente cada padrão, você aumentará substancialmente a resiliência de seus servidores.
Proteja sua infraestrutura. Avalie a complexidade de suas expressões regulares no nosso Testador de Regex de maneira rápida, interativa e gratuita.
Fontes e leituras recomendadas:
- OWASP Foundation — Guia Prático contra Ataques Regular Expression Denial of Service (ReDoS).
- CWE-1333 — Vulnerabilidade de Complexidade Ineficiente em Expressões Regulares.
- Google RE2 Engine Repository — Biblioteca de processamento linear de expressões regulares.
- Artigo relacionado na TecnoCrypter: Anatomia da Injeção SQL e Mitigação


