2010-05-14 9 views
5

Hay muchas preguntas desbordamiento de pila (por ejemplo Whitelisting, preventing XSS with WMD control in C# y WMD Markdown and server-side) acerca de cómo hacer lavado del lado del servidor de Markdown producido por el editor de armas de destrucción masiva para asegurar el HTML generado no contiene código malicioso, como esto:alineado en vista previa del editor de armas de destrucción masiva HTML con HTML de validación del lado del servidor (por ejemplo, no hay código JavaScript incrustado)

<img onload="alert('haha');" 
    src="http://www.google.com/intl/en_ALL/images/srpr/logo1w.png" /> 

Pero no me pareció una buena manera de tapar el agujero en el lado del cliente también. La validación del cliente no es un reemplazo para la depuración de validación en el servidor, por supuesto, ya que cualquiera puede pretender ser un cliente y PUBLICAR un desagradable Markdown. Y si está limpiando el HTML en el servidor, un atacante no puede guardar el HTML incorrecto para que nadie más pueda verlo más tarde y sus secuencias de comandos incorrectas le roben las cookies o las sesiones. Por lo tanto, hay un caso válido que puede que no valga la pena aplicar las reglas sin guiones también en el panel de vista previa de WMD.

Pero imagine que un atacante encontró la forma de obtener un Markdown malicioso en el servidor (por ejemplo, un feed comprometido de otro sitio o contenido agregado antes de que se solucionara un error de XSS). La lista blanca del lado del servidor que se aplicó al traducir el marcado a HTML normalmente evitaría que el Mal marcado se muestre a los usuarios. Pero si el atacante logra que alguien edite la página (por ejemplo, publicando otra entrada que dice que la entrada maliciosa tiene un enlace roto y le pide a alguien que la solucione), cualquiera que edite la página obtiene sus cookies secuestradas. Es cierto que es un caso de esquina, pero aún puede valer la pena defenderse.

Además, probablemente sea una mala idea permitir que la ventana de vista previa del cliente permita diferentes HTML de los que permita su servidor.

El equipo de Stack Overflow ha conectado este agujero haciendo cambios a WMD. ¿Cómo lo hicieron?

[NOTA: Ya me di cuenta de esto, pero se requería una depuración de JavaScript complicada, así que estoy respondiendo mi propia pregunta aquí para ayudar a otros que quieran hacer lo mismo].

Respuesta

6

Una posible solución está en wmd.js, en el método pushPreviewHtml(). Aquí está el código original de la Stack Overflow version of WMD on GitHub:

if (wmd.panels.preview) { 
    wmd.panels.preview.innerHTML = text; 
} 

Puede reemplazarlo con algo de código de depuración. Aquí hay una adaptación del código que Stack Overflow usa in response to this post, que restringe a una lista blanca de etiquetas, y para elementos IMG y A, restringe a una lista blanca de atributos (¡y en un orden específico también!). Consulte la publicación de Meta Stack Overflow What HTML tags are allowed on Stack Overflow, Server Fault, and Super User? para obtener más información sobre la lista blanca.

Nota: este código ciertamente se puede mejorar, p. para permitir los atributos de la lista blanca en cualquier orden. También desautoriza mailto: URL, que probablemente sea algo bueno en los sitios de Internet, pero en su propio sitio de intranet, puede que no sea el mejor enfoque.

if (wmd.panels.preview) { 

    // Original WMD code allowed JavaScript injection, like this: 
    // <img src="http://www.google.com/intl/en_ALL/images/srpr/logo1w.png" onload="alert('haha');"/> 
    // Now, we first ensure elements (and attributes of IMG and A elements) are in a whitelist, 
    // and if not in whitelist, replace with blanks in preview to prevent XSS attacks 
    // when editing malicious Markdown. 
    var okTags = /^(<\/?(b|blockquote|code|del|dd|dl|dt|em|h1|h2|h3|i|kbd|li|ol|p|pre|s|sup|sub|strong|strike|ul)>|<(br|hr)\s?\/?>)$/i; 
    var okLinks = /^(<a\shref="(\#\d+|(https?|ftp):\/\/[-A-Za-z0-9+&@#\/%?=~_|!:,.;\(\)]+)"(\stitle="[^"<>]+")?\s?>|<\/a>)$/i; 
    var okImg = /^(<img\ssrc="https?:(\/\/[-A-Za-z0-9+&@#\/%?=~_|!:,.;\(\)]+)"(\swidth="\d{1,3}")?(\sheight="\d{1,3}")?(\salt="[^"<>]*")?(\stitle="[^"<>]*")?\s?\/?>)$/i; 
    text = text.replace(/<[^<>]*>?/gi, function (tag) { 
     return (tag.match(okTags) || tag.match(okLinks) || tag.match(okImg)) ? tag : "" 
    }) 

    wmd.panels.preview.innerHTML = text; // Original code 
} 

También tenga en cuenta que esta solución no está en la Stack Overflow version of WMD on GitHub - claramente el cambio se hizo más tarde y no se comprueba de nuevo en GitHub.

ACTUALIZACIÓN: para evitar que se rompa la función en la que los hipervínculos se crean automáticamente al escribir una URL, también deberá realizar cambios en el enfrentamiento.js, como a continuación:

Código original:

var _DoAutoLinks = function(text) { 

    text = text.replace(/<((https?|ftp|dict):[^'">\s]+)>/gi,"<a href=\"$1\">$1</a>"); 

    // Email addresses: <[email protected]> 

    /* 
     text = text.replace(/ 
      < 
      (?:mailto:)? 
      (
       [-.\w]+ 
       \@ 
       [-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+ 
      ) 
      > 
     /gi, _DoAutoLinks_callback()); 
    */ 
    text = text.replace(/<(?:mailto:)?([-.\w]+\@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)>/gi, 
     function(wholeMatch,m1) { 
      return _EncodeEmailAddress(_UnescapeSpecialChars(m1)); 
     } 
    ); 

    return text; 
} 

Código fijo:

var _DoAutoLinks = function(text) { 
    // use simplified format for links, to enable whitelisting link attributes 
    text = text.replace(/(^|\s)(https?|ftp)(:\/\/[-A-Z0-9+&@#\/%?=~_|\[\]\(\)!:,\.;]*[-A-Z0-9+&@#\/%=~_|\[\]])($|\W)/gi, "$1<$2$3>$4"); 
    text = text.replace(/<((https?|ftp):[^'">\s]+)>/gi, '<a href="$1">$1</a>'); 
    return text; 
} 
+0

No estoy seguro de que esto sea algo que deba solucionarse. Parece una solución en busca de un problema. Quizás la razón por la que no ve este código en la versión de StackOverflow de WMD es porque no existe, porque no es necesario. –

+2

Sí, no estoy convencido de que sea necesario tampoco. Dicho esto, los chicos de StackOverflow.com implementaron esto con el fin de garantizar que la vista previa nunca generara HTML que su validador del lado del servidor no aceptaría. Parece razonable, aunque no estoy muy de acuerdo. Consulte http://meta.stackexchange.com/questions/1227/preview-should-match-the-posted-view para obtener más detalles sobre por qué SO lo hizo. Por cierto, acabo de editar mi pregunta para alinearla con la razón real por la que SO quería hacer esto. –

+0

Podría AJAX publicar el HTML y recuperar el HTML desinfectado del servidor, para obtener una vista previa perfecta. – ceejayoz

2

No es un problema de seguridad para permitir que el usuario local para ejecutar secuencias de comandos en el contexto de la página siempre que sea imposible que un tercero proporcione la secuencia de comandos. Sin que el editor lo haga, el usuario siempre puede ingresar una url javascript: mientras está en su página o usar Firebug o algo similar.

+0

inicialmente estuve de acuerdo contigo, pero encontré un caso interesante: si hubiera otra forma de que un atacante obtuviera un descuento en el servidor, entonces este problema de vista previa de WMD sería peligroso. Si un atacante puede conseguir que un moderador del sitio edite una página incorrecta (por ejemplo, para borrar un enlace roto), entonces podría tomar el control del sitio completo. Es cierto que sería fácil de eliminar borrando el marcador en el servidor antes de enviarlo a la página de edición, pero a menudo se ignora la validación de la salida. Es cierto que es un caso de esquina, pero puede valer la pena defenderse de un sitio seguro. –

Cuestiones relacionadas