web-dev-qa-db-fra.com

Java ReDos est-il vulnérable?

J'ai essayé de recréer attaque par déni de service d'expression régulière en utilisant (a+)+ regexp et aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa! (avec de grandes quantités de a) en utilisant jshell:

Pattern.compile("(a+)+")
    .matcher("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!")
    .matches()

Mais cela se termine assez rapidement à chaque fois que j'ai essayé. L'implémentation de regexp en Java est-elle différente des autres? Ou la page wikipedia liée est incorrecte?

(BTW. J'utilise Java 11, si c'est pertinent)

EDIT: Il semble que cela soit lié à la version Java. Lorsque je l’ai essayée sur Java 8, cela se bloque, mais cela fonctionne immédiatement avec Java 9 et 11. Qu'est-ce qui a changé entre ces versions et qui pourrait affecter ça? Est-ce que tous les regex sont en sécurité maintenant en Java?

Existe-t-il un JEP Java spécifique qui a modifié l'implémentation de regexp? J'aimerais savoir quel type de regexps pose encore problème pour les versions plus récentes de Java.

14
Krzysztof Krasoń

J'utilise actuellement Java 8 et le code suivant se bloque:

Pattern.compile("(a|aa)+")
       .matcher("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab")
       .matches()

Étant donné que vous utilisez Java 11 (et que vous l’avez également testé avec Java 9/10) et que vous avez constaté que cela prend un peu de temps, une modification a été apportée entre ces versions.

En regardant le code source de Matcher dans Java 11, nous trouvons l’addition suivante qui n’est pas présente dans Java 8:

/**
 * Storage used by top greedy Loop node to store a specific hash set to
 * keep the beginning index of the failed repetition match. The nodes
 * themselves are stateless, so they rely on this field to hold state
 * during a match.
 */
IntHashSet[] localsPos;

Ce stockage local, ainsi que de nombreux autres codes ajoutés, semble être l’une des principales raisons pour lesquelles la machine à états des expressions régulières dans Java 9+ se termine beaucoup plus rapidement que dans Java 8 et les versions ultérieures.

1
Jacob G.