Regex Denail of Service - O que é e como funciona ?
Estava "passeando" na internet quando me deparei com um vídeo: "Ataque com Regex - Negação de serviço usando expressões regulares", achei incríveil o conteúdo, então resolvi apresentar esse problema de segurança para vocês de um modo... um pouco mais simples. Vamos lá!
O que é ReDoS?
ReDoS (Regex Denail of Service), nada mais é do que um simples "erro lógico (ou falta de atenção)" na expressão regular, o que resulta num problema bem grande, podendo até tirar a aplicação do ar.
Como funciona o ReDoS?
Vamos fazer um exemplo prático usando o PHP
. Iremos usar um site muito famoso por nos dar a possibilida de criar e depurar expressões regulares: regex101. Ao acessar o site logo na esquerda vemos algumas linguagens, como dito anteriormente, iremos usar o PHP
, adicionando a seguinte Regex /^([a-z]+)+$/
e testando com uma string
consideravelmente grande com o último caractere inválido, nos deparamos com isso: catastrophic backtracking, mas... o que seria isso, e por que aconteceu?. Se formos para o terminal interativo do php e executar o seguinte código abaixo veremos algo interessante.
var_dump(preg_match('/^([a-z]-)+$/', 'sjsjdjdjjaajyehajajsjdsA'));
O retorno não é um inteiro como diz a documentação, e sim um false
, e quando isso acontence é porque ocorreu um erro; Para fins didáticos vamos ver o erro gerado:
preg_last_error();
Temos a seguinte mensagem: Backtrack limit was exhausted
, isso quer dizer que o limite de backtracking explodiu (passou do limite).
O problema
Quando adionamos esta regex /^([a-z]+)+$/
, estamos dizendo que queremos uma correspondência ou mais, e caso esse grupo seja encontrado, continue a procurar. E é exatamente aí que está o problema... não especificamos a quantidade de caracteres nem grupos que estávamos procurando, e quando passamos uma string
muito grande com um caractere incorreto o tempo de processamento da string
atingiu seu limite. A aplicação precisa verificar cada caractere com os outros, e como o último caractete é inválido, essa busca retornará a posição e tentará com os outros caracteres, nesse bagunça existem inúmeros caminhos a se fazer para encontrar as correspondências, enfim acontece o travamento da aplicação ou do navegador (no caso do Javascript
, que só executa a próxima instrução quando a anterior terminar).
Obs: Algumas linguagens possuem um mecanismo que impede que o teste da string
continue, que é o caso do php, evitando o pior dos problemas, mas... com o JavaScript
que é orientado a eventos isso não acontece, portanto pode ocorrer o travamento do navegador ou da aplicação interna (caso esteja usandi o NodeJS
).
Como resolver?
Essa resolução foi feita para a Regex apresentada neste tópico, mas pode ser consideradas para as outras inúmeras Regex (inválidas).
Para resolvermos é bem simples, primeiramente iremos definir o limite de caracteres que queremos encontrar, depois iremos remover os sinais de +
da Regex para evitar a continuidade.
Outras formas de resolução
Também podemos adicinar mais uma camada de segurança na aplicação, simplesmente verificando a quantidade de caracteres antes de chegar na Regex.
#segurança #boaspraticas
Interessante, então o usuário se quiser, ele pode acabar travando o servidor mandando várias requisições burlando o regex?