C'è un modo per verificare se la mia regex è vulnerabile al backtracking catastrofico?

Aug 21 2020

Ci sono molte domande su questo argomento, ma non sono sicuro che la mia regex sia vulnerabile o meno. La seguente regex è ciò che utilizzo per la convalida dell'email:

/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(email)

Poiché sto usando un * in alcuni posti, sospetto che potrebbe essere.

Mi piacerebbe poter testare qualsiasi numero di occorrenze nel mio codice per problemi.

Sto usando Node.js quindi questo potrebbe chiudere il mio server completamente data la natura a thread singolo del ciclo di eventi.

Risposte

4 wp78de Aug 22 2020 at 03:02

Buona domanda. Sì, dato il giusto input, è vulnerabile e un'espressione regolare in fuga è in grado di bloccare l'intero processo del nodo, rendendo il servizio non disponibile.

L'esempio di base di una regex incline a un backtracking catastrofico sembra

^(\w+)*$

un modello che può essere trovato più volte nella regex data.
Quando la regex contiene quantificatori opzionali e l'input contiene lunghe sequenze che non possono essere abbinate alla fine, il motore di regex JS deve tornare indietro molto e brucia la CPU. Potenzialmente all'infinito se l'input è abbastanza lungo. (Puoi giocare con questo anche su regex101 usando la tua regex regolando il valore di timeout nelle impostazioni.)

In generale,

  • evitare mostruosità ,
  • utilizzare la convalida dell'input HTML5 quando possibile (nel front-end),
  • utilizzare librerie di convalida consolidate per input comuni, ad esempio validator.js ,
  • provare a rilevare in anticipo le espressioni regolari esponenziali in tempo potenzialmente catastrofiche utilizzando strumenti come safe-regex e vuln-regex-detector (che offrono praticamente quello che avevi in ​​mente),
  • e conosci le tue cose 1 , 2 , 3 (penso che il terzo link spieghi meglio il problema).

Approcci più drastici per mitigare il backtracking catastrofico in node.js stanno avvolgendo i tuoi sforzi regex in un processo o vmcontesto figlio e impostano un timeout significativo. (In un mondo perfetto il RegExpcostruttore di JavaScript avrebbe un parametro di timeout, forse un giorno.)

  1. L'approccio all'utilizzo di un processo figlio è descritto qui su SO.

  2. L'approccio al contesto VM (sandboxing) è descritto qui .

Gary Aug 22 2020 at 18:11
const Joi = require('@hapi/joi');

function isEmail(emailAsStr) {
        const schema = Joi.object({ email: Joi.string().email() });
        const result = schema.validate({ email: emailAsStr });

        const validated = result.error ? false : true;

        if (validated) return true;
        return [false, result.error.details[0].message];
}

Ecco un altro modo per farlo: usa una libreria! :) L'ho testato contro le comuni regex catastrofiche di backtrack. La risposta alla mia domanda originale è usare npm lib. safe-regex, ma ho pensato di condividere un altro esempio di come risolvere questo problema senza regex.