Protegendo a entrada do usuário de expressões regulares contra ataques

9

Estou ciente da negação de serviço de expressão regular (ReDoS). Existe alguma maneira razoável de permitir que os usuários criem regexes personalizadas, garantindo que eles não enviem um padrão exponencialmente lento?

icirellik
fonte
Faltam detalhes. Plataforma, uso, etc.
whatsisname 14/06
8
Em vez de tentar evitar que o usuário envie uma regex incorreta, talvez uma solução em que após um certo período de tempo você cancele a execução?
Samuel

Respostas:

8

O problema com expressões regulares não é o próprio regex, mas o mecanismo de regex que possui todos os tipos de recursos "convenientes", como o retorno. Portanto, o uso de um mecanismo regex sem esses recursos evita.

Expressões regulares que o conceito de ciência da computação pode sempre corresponder em tempo linear após serem compiladas em uma máquina de estados finitos. Portanto, um mecanismo regex baseado em máquina de estado não pode ser usado para ReDoS. No entanto, as máquinas de estado necessárias podem se tornar bastante grandes em exemplos patológicos. Porém, limitar a memória disponível tende a ser mais fácil do que limitar o tempo de computação disponível.

O mecanismo RE2 foi desenvolvido especificamente para lidar com regexes não confiáveis ​​e foi projetado para execução em tempo linear.

Outra alternativa é montar as expressões regulares a partir de uma notação simplificada. Por exemplo, você pode permitir que os usuários usem padrões glob (como *.txt). Você pode analisar isso de uma maneira que evite o retorno, por exemplo, impedindo o aninhamento e usando apenas quantificadores gananciosos. Para muitos casos de uso, uma notação de padrão simplificada é completamente suficiente.

amon
fonte
11

Analisar uma expressão regular para ver se ela será lenta ou não, sem que a análise se torne lenta , equivale a resolver o problema de parada. Em outras palavras, não é possível encontrar uma solução correta e completa.

Você pode, é claro, encontrar uma solução que está correto e em completa. Por exemplo, você pode trabalhar com uma lista branca restritiva de recursos que são seguros de usar (por exemplo, classes de caracteres sim, repetição não ...). Isso permitiria que você passasse por muitas regexes acríticas, rejeite todas as críticas e (erroneamente) rejeite algumas que estão bem, mas são muito complicadas para se provar seguras automaticamente.

Kilian Foth
fonte
3
Você tem uma citação para sua primeira declaração? Eu estaria interessado em ver essa prova. As expressões regulares não são completas de Turing, portanto, o problema de parada pode não se aplicar.
Sebastian Redl
3
@SebastianRedl É verdade que, estritamente falando, expressões regulares não são completas para Turing, mas todas as bibliotecas de expressões regulares em uso popular têm extensões que as deixam mais regulares. Restringir seus usuários a expressões regulares literalmente pode ser uma boa solução para essa situação.
Kilian Foth
2
@KilianFoth: IIRC, mesmo expressões regulares verdadeiras (no sentido da palavra CompSci) podem exigir uma quantidade exponencial de retorno. Mas como eles não são completos para Turing, para qualquer regex, é teoricamente possível estabelecer esse limite superior. No entanto, isso deixa em aberto dois problemas: determinar automaticamente o limite superior é uma tarefa não trivial e o resultado pode gerar resultados excessivamente altos (como em um limite superior muito superior ao tempo esperado ).
MSalters
@msalters qualquer expressão regular verdadeira é mecanicamente conversível em um autômato de estado finito determinístico, ou seja, sempre é possível corresponder à expressão sem retroceder. Seu FSA pode ficar excessivamente grande, é claro, mas isso sugere que um limite para o número de estados no FSA gerado é uma solução suficiente para impedir o ataque em questão.
Jules
1

Como autor do analisador para o projeto lazarus, eu diria que não há maneiras de entender, para uma expressão regular, quais recursos serão consumidos em um determinado texto.

Sem gastar os mesmos recursos, quero dizer (pelo menos em grande-O).

Portanto, a melhor abordagem - execute o analisador em um thread separado e mate-o após o tempo limite.

ANDgineer
fonte
0

Além das outras respostas, uma solução também pode ser a rolagem de sua própria biblioteca de expressões regulares, que permite a instrumentação de desempenho durante a execução e, portanto, fornece os meios para eliminar a execução no meio do caminho, se alguns critérios forem atendidos.

Da mesma forma, você pode executar as expressões regulares em outro encadeamento e eliminá-las se elas demorarem muito.

whatsisname
fonte