2011-12-15 17 views
6

Permitimos algunos RE suministrados por el usuario con el fin de filtrar el correo electrónico. Al principio nos topamos con algunos problemas de rendimiento con RE que contenían, por ejemplo, .*, al hacer coincidir contra correos electrónicos arbitrariamente grandes. Encontramos que una solución simple era s/\*/{0,1024}/ en el RE suministrado por el usuario. Sin embargo, esto no es una solución perfecta, ya que se romperá con el siguiente patrón:Cualquier forma de tratar. * Como. {0,1024} en perl RE?

/[*]/ 

Y en lugar de dar con alguna receta complicada para tener en cuenta todas las posibles mutaciones de entrada RE proporcionada por el usuario, que había Me gusta simplemente limitar la interpretación de Perl de los caracteres * y + para tener una longitud máxima de 1024 caracteres.

¿Hay alguna manera de hacer esto?

+0

¿Qué parte de un correo electrónico tienen estos filtros se ejecutan en? Encabezados, cuerpo? – fge

+0

@fge: el cuerpo es donde esto importa, porque esa es la parte que puede ser arbitrariamente grande. También verificamos los encabezados, pero solo un encabezado a la vez. E incluso los encabezados de correo electrónico más largos no son lo suficientemente largos como para causar problemas de rendimiento con * y +. – Flimzy

+0

Bien, entonces otra pregunta: ¿ejecuta estas expresiones regulares en todo el contenido, los archivos adjuntos incluidos, o se salta los archivos adjuntos? – fge

Respuesta

4

actualización

añadido un (?<!\\) antes de los cuantificadores, porque escaparon * + no debe ser igualada. El reemplazo aún fallará si hay un \\* (coincidencia \ 0 o más veces).

Una mejora sería este

s/(?<!\\)\*(?!(?<!\\)[^[]*?(?<!\\)\])/{0,1024}/ 
s/(?<!\\)\+(?!(?<!\\)[^[]*?(?<!\\)\])/{1,1024}/ 

Verla here on Regexr

Eso significa [*+] partido pero sólo si no hay un cierre ] adelante y sin [ hasta entonces. Y no hay \(la parte (?<!\\)) permitido antes de los corchetes.

(?! ...) es una búsqueda negativa hacia delante

(?<! ...) es una búsqueda hacia atrás negativo

Ver perlretut para más detalles

Actualizar 2 incluyen los cuantificadores posesivos

s/(?<!(?<!\\)[\\+*?])\+(?!(?<!\\)[^[]*?(?<!\\)\])/{1,1024}/ # for + 
s/(?<!\\)\*(?!(?<!\\)[^[]*?(?<!\\)\])/{0,1024}/ # for * 

Ver que here on Regexr

Parece que funciona, ¡pero ahora se está complicando realmente!

+0

Sí, eso es una mejora ... aún deja el caso del cuantificador "posesivo" + (es decir, '* +', '++', '? +' y '{..} +'). Supongo que puedo formar una receta similar para ignorar el + char en estos casos, también. – Flimzy

+0

Buen punto con los cuantificadores posesivos, se agregó una solución para eso. – stema

+0

Gracias ... Me identifico completamente con su último comentario ... * ¡definitivamente se está complicando! * ¡Ojalá hubiera solo una perlvar de $ MAX_REGEXP_STRING_LENGTH o algo así! :) – Flimzy

1

¿Se refiere a la excepción de parchear la fuente?

  1. Puede dividir los textos de entrada en trozos más cortos y hacer coincidir solo aquellos. Pero, de nuevo, no coincidirías en un salto de "línea".
  2. Puede descomponer la expresión regular, buscar solo el primer carácter, cargar los siguientes 1024 caracteres de texto y luego hacer coincidir toda la expresión regular en esto (obviamente, eso no funciona con la expresión regular que comienza con.)
  3. Encuentra el primer carácter característico de la expresión regular que no sea. * +() \, Encuentra eso, carga 1024 caracteres antes y después y luego compara la expresión regular completa en esta cadena. (Complicado y podar a errores en expresiones regulares imprevisto extraña)
+0

sí ... además de parchear la fuente :) (Todavía necesitamos el comportamiento estándar en algunos casos que no involucran la entrada del usuario) – Flimzy

+0

Acabo de agregar algunas ideas más – Nikodemus

5

Esto realmente no responde a su pregunta, pero debe tener en cuenta otros problemas con las expresiones regulares proporcionadas por el usuario, vea por ejemplo este summary at OWASP. Dependiendo de su situación exacta, ¿podría ser mejor escribir o encontrar una biblioteca de coincidencia de patrones simple personalizada?

+2

+1, porque '^ (a | aa) {0,30} $' es suficiente para mantener ocupado el motor de expresiones regulares durante millones de ciclos con una cadena como 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaX' –

+0

Gracias; una buena advertencia. Aunque ciertamente es posible que un usuario pueda aplicar el DOS por sí mismo, realmente solo podría hacerlo por sí mismo. Por lo tanto, nuestro objetivo principal es evitar que lo hagan accidentalmente. – Flimzy

+0

Esto me da la idea de envolver todos mis RE suministrados por el usuario en un 'eval {alarma 1; ...}; 'bloque, aunque ... – Flimzy

Cuestiones relacionadas