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
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:
- Cuantificator în interiorul unui cuantificator:
(...+)+,(...*)*,(...{n,})+. - Alternative suprapuse sub un cuantificator:
(a|ab)*,(\w|\d)+. - Privire înainte/în urmă cu alternative complexe repetate.
Rescriere defensivă
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
- Asigurați-vă că opțiunile alternative se exclud reciproc (de exemplu, nu utilizați
(a|a+)). - Evitați să aplicați cuantificatori imbricați expresiilor care se suprapun (de exemplu,
(\\s*)*). - Preferați întotdeauna anumite clase de caractere negate (
[^\\n]*) în detrimentul punctului generic cu wildcard (.*).
Încearcă
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+)+.
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
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+)+`.
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ă
Make the vulnerable pattern `(\w+\s*)+:` which causes ReDoS safe, by removing the overlapping whitespace recursion.
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