C'è un modo per mettere il codice dannoso in un'espressione regolare?


138

Voglio aggiungere funzionalità di ricerca di espressioni regolari alla mia pagina Web pubblica. Oltre alla codifica HTML dell'output, devo fare qualcosa per proteggermi da input di utenti malintenzionati?

Le ricerche su Google sono sommerse da persone che risolvono il problema opposto - usando espressioni regolari per rilevare input dannosi - che non mi interessano. Nel mio scenario, l'input dell'utente è un'espressione regolare.

Sarò con il Regex libreria in .NET (C #).


4
Questo potrebbe dipendere dalla lingua e / o dalla libreria regex che usi.
aschepler

Risposte:


216

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 Safemodulo 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.


4
La conversione NFA-> DFA può produrre un'esplosione di stato esponenziale, trasformando un DoS temporale in un DoS spaziale, nonché il costo del tempo di generazione del numero esponenziale di stati.
Barry Kelly,

ma probabilmente non avrà bisogno dell'intera capacità delle espressioni regolari, cosa ne pensi di limitare il potere delle espressioni regolari come ha fatto google: google.com/intl/it/help/faq_codesearch.html#regexp
systemfault

1
@Barry Esatto. Avevo pensato alla strategia di Russ Cox descritta in uno dei suoi articoli sulla compilazione progressiva di parti dell'NFA in un DFA equivalente, ma buttandolo via se diventava troppo grande. Ma non c'è un proiettile d'argento in un DFA, anche se Thompson lo ha dimostrato equivalente a un NFA, perché in un punto o in un altro devi pagare il pifferaio. Il tempo impiegato a chiedere più spazio al sistema operativo e i relativi costi di impostazione della tabella delle pagine possono talvolta spostare ulteriormente la scala di bilanciamento nell'altro modo e rendere la conversione dal tempo allo spazio meno attraente di quanto sarebbe.
tchrist,

20

Aggiungendo all'ottima risposta di tchrist: anche lo stesso Russ Cox che ha scritto la pagina "Espressione regolare" ha rilasciato il codice! re2 è una libreria C ++ che garantisce il runtime O (length_of_regex) e il limite di utilizzo della memoria configurabile. È utilizzato in Google in modo da poter digitare una regex nella ricerca del codice di Google, il che significa che è stato testato in battaglia.


2
Davvero così. Puoi scambiare re2 nel motore regex di Perl con un modulo e utilizzerà re2 se possibile e Perl in caso contrario. Funziona abbastanza bene.
tchrist


6

Ti consigliamo di leggere questo documento:

Cambio di contesto insicuro: inoculazione di espressioni regolari per la sopravvivenza Il documento tratta di cosa può andare storto con i motori di espressione regolare (ad esempio PCRE), ma può aiutarti a capire cosa stai affrontando.


1
Ecco un avviso di sicurezza sul codice GNU libc regcomp (3): securityreason.com/achievement_securityalert/93 Che puntualità! Almeno sotto Linux, la vulnerabilità è facile da dimostrare: grep -E ". * {10,} {10,} {10,} {10,} {10,}"
Bruce Ediger

5

Devi preoccuparti non solo della corrispondenza stessa, ma di come esegui la corrispondenza. Ad esempio, se l'input passa attraverso una sorta di fase di valutazione o sostituzione del comando mentre si dirige verso il motore delle espressioni regolari, potrebbe esserci del codice che viene eseguito all'interno del modello. Oppure, se la sintassi delle espressioni regolari consente comandi incorporati, devi anche diffidare di quello. Dal momento che non hai specificato la lingua nella tua domanda, è difficile dire con certezza quali siano tutte le implicazioni per la sicurezza.


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.