Salt la conținutul principal
Modulul 8 · Lecția 4 din 432/32 în curs~14 min
Lecții din modul (4/4)

Scrierea modelelor sigure pentru ReDoS

ReDoS (Expresie regulată Denial of Service) este o clasă de atacuri în care o intrare atent concepută face ca timpul de potrivire al unei expresii regex să explodeze. Motorul JS folosește backtracking: dacă un model este „ambiguu”, pe un intrare ghinionoasă poate efectua un număr exponențial de încercări.

Modelul clasic catastrofal

Code
Pattern: ^(a+)+$
Input:   "aaaaaaaaaaaaaaaaaaaaab"

Pentru a se potrivi, motorul încearcă toate partiții posibile de „a” între cei doi cuantificatori +. Pe 20 "a" înseamnă 2^20 = ~1 milion de încercări. Pe 30 de „a”, un miliard.

Alte exemple periculoase:

  • (a*)*b -- „stele imbricate”.
  • (a|a)* -- alternative care se suprapun.
  • (\w+)+@ -- grupuri lacome cu un cuantificator exterior.

Cum să descoperi pericolul

Căutați aceste structuri:

  1. Cuantificator în interiorul unui cuantificator: (...+)+, (...*)*, (...{n,})+.
  2. Alternative suprapuse sub un cuantificator: (a|ab)*, (\w|\d)+.
  3. Privire înainte/în urmă cu alternative complexe repetate.

Rescriere defensivă

Code
Dangerous:  ^(\w+\s+)+$
Safe:       ^(?:\w+\s+)*\w+$

Versiunea sigură separă carcasa de bază de carcasa repetată, eliminând ambiguitatea. Alte tehnici:

  • Cuantificatori posesivi (a++) -- nu sunt acceptate în JS, dar sunt disponibile în alte motoare.
  • Modele atomice ((?>...)) -- nu în JS.
  • Limitați lungimea de intrare înainte de potrivire.
  • Timeout la potrivire (editorul acestui curs folosește un worker cu un timeout de 500 ms).

Recomandări pentru modele sigure pentru ReDoS

  1. Asigurați-vă că opțiunile alternative se exclud reciproc (de exemplu, nu utilizați (a|a+)).
  2. Evitați să aplicați cuantificatori imbricați expresiilor care se suprapun (de exemplu, (\\s*)*).
  3. Preferați întotdeauna anumite clase de caractere negate ([^\\n]*) în detrimentul punctului generic cu wildcard (.*).

Încearcă

Exercițiu#regex.m8.l4.e1
Încercări: 0Se încarcă…

Identificați modele de litere repetate, dar într-un mod sigur pentru ReDoS. Folosiți o singură clasă de caractere, NU grupuri imbricate precum (a+)+.

Se încarcă editorul...
Afișează indiciu

Înlocuiește periculosul (a+)+ cu un simplu a+. Rezultatul este același, dar sigur.

Soluție disponibilă după 3 încercări

Exercițiu de revizuire

Exercițiu#regex.m8.l4.e2
Încercări: 0Se încarcă…

Recunoașteți o secvență de cuvinte separate prin spații, într-un mod sigur pentru ReDoS. Utilizați structura `(?:cuvânt+spații+)*cuvânt` în loc de `(cuvânt+spațiu+)+`.

Se încarcă editorul...
Afișează indiciu

Înlocuiți grupul de captură (\\w+\\s+)+ cu versiunea disjunctă (?:\\w+\\s+)*\\w+.

Soluție disponibilă după 3 încercări

Provocare suplimentară

Exercițiu#regex.m8.l4.e3
Încercări: 0Se încarcă…

Make the vulnerable pattern `(\w+\s*)+:` which causes ReDoS safe, by removing the overlapping whitespace recursion.

Se încarcă editorul...
Afișează indiciu

Mutați spațiul astfel încât să nu se suprapună cu repetarea grupului: (?:\\w+\\s+)*\\w+:

Soluție disponibilă după 3 încercări