Preoccupazioni di negazione del servizio
La preoccupazione più comune con le regex è un attacco denial-of-service attraverso schemi patologici che diventano esponenziali - o addirittura super-esponenziali! - e così sembrano impiegare un'eternità a risolversi. Questi possono apparire solo su particolari dati di input, ma in genere è possibile crearne uno in cui ciò non ha importanza.
Quali sono questi dipenderanno in qualche modo da quanto intelligente sia il compilatore regex che stai usando, perché alcuni di questi possono essere rilevati durante il tempo di compilazione. I compilatori Regex che implementano la ricorsione di solito hanno un contatore di profondità di ricorsione incorporato per controllare la non progressione.
L'eccellente documento di Russ Cox del 2007 sul Corrispondenza delle espressioni regolari può essere semplice e veloce (ma è lento in Java, Perl, PHP, Python, Ruby, ...) parla di come la maggior parte degli NFA moderni, che sembrano tutti derivare dal codice di Henry Spencer , subiscono un grave peggioramento delle prestazioni, ma in cui un NFA in stile Thompson non presenta tali problemi.
Se ammetti solo pattern che possono essere risolti dai DFA, puoi compilarli come tali e funzioneranno più velocemente, forse molto più velocemente. Tuttavia, ci vuole tempo per farlo. Il documento Cox menziona questo approccio e le sue problematiche. Tutto si riduce a un classico compromesso spazio-tempo.
Con un DFA, dedichi più tempo a costruirlo (e allocare più stati), mentre con un NFA dedichi più tempo a eseguirlo, poiché può essere più stati contemporaneamente e il backtracking può consumare il tuo pranzo e la tua CPU.
Soluzioni di negazione del servizio
Probabilmente il modo più ragionevole per affrontare questi schemi che si trovano alla fine perdente di una gara con la morte per calore dell'universo è di avvolgerli con un timer che posiziona effettivamente un tempo massimo consentito per la loro esecuzione. Di solito questo sarà molto, molto inferiore al timeout predefinito fornito dalla maggior parte dei server HTTP.
Esistono vari modi per implementarli, che vanno da un semplice alarm(N)
a livello C, a una sorta di try {}
blocco delle eccezioni di tipo allarme, fino a generare un nuovo thread creato appositamente con un vincolo di temporizzazione incorporato in esso.
Callout di codice
Nei linguaggi regex che ammettono callout di codice, dovrebbe essere fornito un meccanismo per consentire o vietare questi dalla stringa che si sta per compilare . Anche se i callout di codice sono solo per codificare nella lingua che stai usando, dovresti limitarli; non devono essere in grado di chiamare il codice esterno, anche se se possono, hai problemi molto più grandi.
Ad esempio, in Perl non si possono avere callout di codice in regex creati dall'interpolazione di stringhe (come sarebbero, come sono compilati durante il runtime) a meno che lo speciale pragma con ambito lessicale sia use re "eval";
attivo nell'ambito corrente.
In questo modo nessuno può intrufolarsi in un callout di codice per eseguire programmi di sistema come rm -rf *
, ad esempio. Poiché i callout di codice sono così sensibili alla sicurezza, Perl li disabilita di default su tutte le stringhe interpolate e devi fare di tutto per riattivarli.
Definito dall'utente \ P {roperties}
Rimane ancora una questione delicata relativi alla sicurezza per le proprietà in stile Unicode - come \pM
, \p{Pd}
, \p{Pattern_Syntax}
, o \p{Script=Greek}
- che possono esistere in alcuni compilatori regex che il sostegno che di notazione.
Il problema è che in alcuni di questi, l'insieme delle possibili proprietà è estensibile dall'utente. Ciò significa che è possibile avere proprietà personalizzate che sono callout di codice effettivi a funzioni con nome in un determinato nome, come \p{GoodChars}
o \p{Class::Good_Characters}
. Come potrebbe valere la pena esaminare la tua lingua.
sandboxing
In Perl, un compartimento sandbox tramite il Safe
modulo darebbe il controllo sulla visibilità dello spazio dei nomi. Altre lingue offrono tecnologie di sandboxing simili. Se tali dispositivi sono disponibili, ti consigliamo di esaminarli, perché sono specificamente progettati per l'esecuzione limitata di codice non attendibile.