Alinear HTML vista previa del editor de armas de destrucción masiva con la validación de HTML del lado del servidor (por ejemplo, el código JavaScript no integrado)

StackOverflow https://stackoverflow.com/questions/2837593

Pregunta

Hay muchas preguntas desbordamiento de pila (por ejemplo, listas blancas, la prevención de XSS con el control de armas de destrucción masiva en C # y armas de destrucción masiva reducción del precio y del lado del servidor ) acerca de cómo hacer del lado del servidor de lavado de rebajas producidas por el editor de armas de destrucción masiva para asegurar el HTML generado no contiene código malicioso, como esto:

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

Sin embargo, no he encontrado una buena manera de tapar el agujero en el lado del cliente también. Validación del cliente no es un sustituto para el lavado de validación en el servidor, por supuesto, ya que cualquiera puede hacerse pasar por un cliente y POST que desagradable de rebajas. Y si estás fregando el código HTML en el servidor, un atacante puede no guardar la mala HTML para que nadie más será capaz de verlo más tarde y tienen sus galletas robadas o sesiones secuestrados por la mala escritura. Así que hay un caso válido para afirmar que puede que no sea digno de hacer cumplir las reglas no compatibles con scripts en el panel de vista previa de ADM también.

Pero imaginemos que un atacante encontró una manera de conseguir malicioso de rebajas en el servidor (por ejemplo, una alimentación comprometida desde otro sitio, o el contenido añadido antes de que un insecto se fijó XSS). Su lado del servidor lista blanca aplicada en la traducción de reducción del precio a HTML normalmente evitar que el mal de rebajas se muestre a los usuarios. Pero si el atacante podría conseguir a alguien para editar la página (por ejemplo, mediante la publicación de otra entrada diciendo la entrada maliciosa tenía un enlace roto y pedir a alguien para arreglarlo), entonces cualquiera que edita la página se pone a sus cookies secuestraron. Este es sin duda un caso límite, pero todavía puede valer la defensa contra.

Además, es probablemente una mala idea permitir que la ventana de vista previa del cliente para permitir diferentes HTML que el servidor permitirá.

El equipo de desbordamiento de la pila ha conectado este agujero, haciendo cambios a armas de destrucción masiva. ¿Cómo lo hicieron?

[NOTA: Ya cuenta de esto, pero requiere algo de JavaScript complicado depuración, así que estoy respondiendo a mi propia pregunta aquí para ayudar a otras personas que puedan querer hacer lo mismo THS].

¿Fue útil?

Solución

Una solución posible es en wmd.js, en el método pushPreviewHtml(). Aquí está el código original de la desbordamiento de pila versión de armas de destrucción masiva en GitHub :

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

Puede reemplazarlo con algo de código de depuración. Aquí está una adaptación del código que utiliza el desbordamiento de pila en respuesta a esta entrada , que restringe a una lista blanca de las etiquetas, y por IMG y los elementos a, restringe a una lista blanca de atributos (y en un orden específico también!). Ver el puesto Meta desbordamiento de pila Qué etiquetas HTML están permitidos en desbordamiento de pila, el servidor falla, y Super usuario? para obtener más información en la lista blanca.

Nota: este código sin duda se puede mejorar, por ejemplo, para permitir que la lista blanca atributos en cualquier orden. Se prohíbe también mailto:. URL que es probablemente una buena cosa en sitios de Internet, pero en su propio sitio de intranet que puede no ser 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 desbordamiento de pila versión de armas de destrucción masiva en GitHub - claramente el cambio se hizo más tarde y no se comprueba de nuevo en GitHub.

ACTUALIZACIÓN: con el fin de evitar la rotura de la característica donde los hipervínculos se crean automáticamente cuando se escribe en una dirección URL, también tendrá que hacer cambios a showdown.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: <address@domain.foo>

    /*
        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;
}

Otros consejos

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 y cuando que es imposible para cualquier tercera parte que la secuencia de comandos. Sin el editor de hacerlo, el usuario siempre puede introducir una URL javascript: mientras que en su página o el uso de Firebug o algo similar.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top