DOMPurify es un desinfectante XSS súper rápido, súper tolerante y exclusivo para DOM para HTML, MathML y SVG.
También es muy sencillo de usar y empezar a utilizar. DOMPurify se inició en febrero de 2014 y, mientras tanto, ha alcanzado la versión v3.2.1 .
DOMPurify está escrito en JavaScript y funciona en todos los navegadores modernos (Safari (10+), Opera (15+), Edge, Firefox y Chrome, así como en casi cualquier otro navegador que utilice Blink, Gecko o WebKit). No se interrumpe en MSIE ni en otros navegadores heredados. Simplemente no hace nada.
Tenga en cuenta que DOMPurify v2.5.7 es la última versión que admite MSIE. Para obtener actualizaciones de seguridad importantes compatibles con MSIE, utilice la rama 2.x.
Nuestras pruebas automatizadas cubren 24 navegadores diferentes en este momento y habrá más en el futuro. También cubrimos Node.js v16.x, v17.x, v18.x y v19.x, ejecutando DOMPurify en jsdom. Se sabe que las versiones anteriores de Node también funcionan, pero bueno... no hay garantías.
DOMPurify está escrito por personal de seguridad que tiene una amplia experiencia en ataques web y XSS. No temas. Para obtener más detalles, lea también sobre nuestros objetivos de seguridad y modelo de amenazas. Por favor, léelo. Realmente.
DOMPurify desinfecta HTML y previene ataques XSS. Puede alimentar a DOMPurify con una cadena llena de HTML sucio y devolverá una cadena (a menos que se configure de otra manera) con HTML limpio. DOMPurify eliminará todo lo que contenga HTML peligroso y así evitará ataques XSS y otras cosas desagradables. También es muy rápido. Utilizamos las tecnologías que proporciona el navegador y las convertimos en un filtro XSS. Cuanto más rápido sea tu navegador, más rápido será DOMPurify.
Es fácil. Simplemente incluya DOMPurify en su sitio web.
<script tipo="text/javascript" src="src/purify.js"></script>
<script type="text/javascript" src="dist/purify.min.js"></script>
Luego puede desinfectar cadenas ejecutando el siguiente código:
const clean = DOMPurify.sanitize(sucio);
O tal vez esto, si te encanta trabajar con Angular o similar:
importar DOMPurify desde 'dompurify';const clean = DOMPurify.sanitize('<b>hola</b>');
El HTML resultante se puede escribir en un elemento DOM usando innerHTML
o el DOM usando document.write()
. Eso depende totalmente de usted. Tenga en cuenta que, de forma predeterminada, permitimos HTML, SVG y MathML. Si solo necesita HTML, lo cual podría ser un caso de uso muy común, también puede configurarlo fácilmente:
const clean = DOMPurify.sanitize(sucio, { USE_PROFILES: { html: verdadero } });
Bueno, tenga en cuenta que si primero desinfecta HTML y luego lo modifica, fácilmente podría anular los efectos de la desinfección . Si envía el marcado desinfectado a otra biblioteca después de la desinfección, asegúrese de que la biblioteca no altere el HTML por sí sola.
Después de desinfectar su marcado, también puede echar un vistazo a la propiedad DOMPurify.removed
y descubrir qué elementos y atributos se descartaron. No utilice esta propiedad para tomar decisiones críticas para la seguridad. Esto es sólo una pequeña ayuda para las mentes curiosas.
DOMPurify técnicamente también funciona en el lado del servidor con Node.js. Nuestro soporte se esfuerza por seguir el ciclo de lanzamiento de Node.js.
La ejecución de DOMPurify en el servidor requiere la presencia de un DOM, lo que probablemente no sea una sorpresa. Por lo general, jsdom es la herramienta elegida y recomendamos encarecidamente utilizar la última versión de jsdom .
¿Por qué? Porque se sabe que las versiones anteriores de jsdom tienen errores que resultan en XSS incluso si DOMPurify hace todo 100% correctamente. Hay vectores de ataque conocidos , por ejemplo, jsdom v19.0.0 que están corregidos en jsdom v20.0.0 , y realmente recomendamos mantener jsdom actualizado debido a eso.
Tenga en cuenta también que existen herramientas como happy-dom, pero no se consideran seguras en este momento. Actualmente no se recomienda combinar DOMPurify con happy-dom y probablemente conducirá a XSS.
Aparte de eso, puedes usar DOMPurify en el servidor. Probablemente. Esto realmente depende de jsdom o de cualquier DOM que utilice en el lado del servidor. Si puedes vivir con eso, así es como lo haces funcionar:
npm instala dompurify npm instala jsdom
Para jsdom (utilice una versión actualizada), esto debería funcionar:
const createDOMPurify = require('dompurify');const { JSDOM } = require('jsdom');const ventana = new JSDOM('').ventana;const DOMPurify = createDOMPurify(ventana);const clean = DOMPurify.sanitize(' <b>hola</b>');
O incluso esto, si prefieres trabajar con importaciones:
importar {JSDOM} desde 'jsdom';importar DOMPurify desde 'dompurify';const window = new JSDOM('').window;const purify = DOMPurify(window);const clean = purify.sanitize('<b>hola< /b>');
Si tiene problemas para que funcione en su configuración específica, considere consultar el increíble proyecto isomórfico-dompurify que resuelve muchos problemas con los que la gente podría encontrarse.
npm instala dompurify isomorfo
importar DOMPurify desde 'isomorphic-dompurify'; const clean = DOMPurify.sanitize('<s>hola</s>');
¡Por supuesto que hay una demostración! Juega con DOMPurify
En primer lugar, comuníquese con nosotros de inmediato por correo electrónico para que podamos trabajar en una solución. clave PGP
Además, ¡probablemente califiques para una recompensa por errores! La excelente gente de Fastmail usa DOMPurify para sus servicios y agregó nuestra biblioteca a su alcance de recompensas por errores. Entonces, si encuentra una manera de eludir o debilitar DOMPurify, eche también un vistazo a su sitio web y a la información de recompensas por errores.
¿Cómo se ve el marcado purificado? Bueno, la demostración lo muestra con una gran cantidad de elementos desagradables. ¡Pero también mostremos algunos ejemplos más pequeños!
DOMPurify.sanitize('<img src=x onerror=alert(1)//>'); // se convierte en <img src="x">DOMPurify.sanitize('<svg><g/onload=alert(2)//<p>'); // se convierte en <svg><g></g></svg>DOMPurify.sanitize('<p>abc<iframe//src=jAva	script:alert(3)>def</p>'); // se convierte en <p>abc</p>DOMPurify.sanitize('<math><mi//xlink:href="data:x,<script>alert(4)</script>">'); // se convierte en <math><mi></mi></math>DOMPurify.sanitize('<TABLE><tr><td>HOLA</tr></TABL>'); // se convierte en <table><tbody><tr><td>HOLA</td></tr></tbody></table>DOMPurify.sanitize('<UL><li><A HREF=//google .com>hacer clic</UL>'); // se convierte en <ul><li><a href="//google.com">clic</a></li></ul>
DOMPurify actualmente es compatible con HTML5, SVG y MathML. DOMPurify por defecto permite atributos de datos personalizados CSS y HTML. DOMPurify también admite Shadow DOM y desinfecta las plantillas DOM de forma recursiva. DOMPurify también le permite desinfectar HTML para usarlo con las API jQuery $()
y elm.html()
sin ningún problema conocido.
DOMPurify no hace nada en absoluto. Simplemente devuelve exactamente la cadena que le alimentó. DOMPurify expone una propiedad llamada isSupported
, que le indica si podrá hacer su trabajo, para que pueda crear su propio plan de respaldo.
En la versión 1.0.9, se agregó compatibilidad con la API Trusted Types a DOMPurify. En la versión 2.0.0, se agregó un indicador de configuración para controlar el comportamiento de DOMPurify con respecto a esto.
Cuando se utiliza DOMPurify.sanitize
en un entorno donde la API Trusted Types está disponible y RETURN_TRUSTED_TYPE
está establecido en true
, intenta devolver un valor TrustedHTML
en lugar de una cadena (el comportamiento de las opciones de configuración RETURN_DOM
y RETURN_DOM_FRAGMENT
no cambia).
Tenga en cuenta que para crear una política en trustedTypes
usando DOMPurify, se requiere RETURN_TRUSTED_TYPE: false
, ya que createHTML
espera una cadena normal, no TrustedHTML
. El siguiente ejemplo muestra esto.
ventana.trustedTypes!.createPolicy('predeterminado', { createHTML: (to_escape) =>DOMPurify.sanitize(to_escape, { RETURN_TRUSTED_TYPE: false }),});
Sí. Los valores de configuración predeterminados incluidos ya son bastante buenos, pero, por supuesto, puedes anularlos. Consulte la carpeta /demos
para ver varios ejemplos sobre cómo personalizar DOMPurify.
// elimina {{ ... }}, ${ ... } y <% ... %> para que la salida sea segura para sistemas de plantillas// tenga cuidado, este modo no se recomienda para uso en producción.// permitir No se recomienda en absoluto el análisis de plantillas en HTML controlado por el usuario.// solo use este modo si realmente no hay ninguna alternativa.const clean = DOMPurify.sanitize(dirty, {SAFE_FOR_TEMPLATES: true});// cambie cómo, por ejemplo, los comentarios que contienen riesgos Los caracteres HTML son tratado.// tenga mucho cuidado, esta configuración solo debe establecerse en `falso` si realmente solo maneja // HTML y nada más, nada de SVG, MathML o similares. // De lo contrario, cambiar de `true` a `false` conducirá a XSS de esta o alguna otra manera.const clean = DOMPurify.sanitize(dirty, {SAFE_FOR_XML: false});
// permitir solo elementos <b>, muy estrictoconst clean = DOMPurify.sanitize(dirty, {ALLOWED_TAGS: ['b']});// permitir solo <b> y <q> con atributos de estiloconst clean = DOMPurify.sanitize( sucio, {ALLOWED_TAGS: ['b', 'q'], ALLOWED_ATTR: ['style']});// permite todos los elementos HTML seguros pero ni SVG ni MathML// tenga en cuenta que la configuración USE_PROFILES anulará la configuración ALLOWED_TAGS// así que no los use juntosconst clean = DOMPurify.sanitize(dirty, {USE_PROFILES: {html: true}});// permita todos los elementos SVG y SVG seguros Filtros, sin HTML ni MathMLconst clean = DOMPurify.sanitize(dirty, {USE_PROFILES: {svg: true, svgFilters: true}});// permite todos los elementos MathML y SVG seguros, pero no los filtros SVGconst clean = DOMPurify.sanitize(dirty, {USE_PROFILES: {mathMl: true, svg: true}});// cambia el espacio de nombres predeterminado de HTML a algo diferenteconst clean = DOMPurify.sanitize(dirty, {NAMESPACE: 'http://www.w3.org/2000/svg'});// deja todo el HTML seguro como lo es y agrega elementos <style> a block-listconst clean = DOMPurify.sanitize(dirty, {FORBID_TAGS: ['style']});// deja todo el HTML seguro como está y agrega atributos de estilo a block-listconst clean = DOMPurify.sanitize(dirty, {FORBID_ATTR: ['style']});// extiende la matriz existente de etiquetas permitidas y agrega <my-tag> a enable-listconst clean = DOMPurify.sanitize(dirty, {ADD_TAGS: ['my-tag']});// extiende la matriz existente de atributos permitidos y agrega my-attr a enable-listconst clean = DOMPurify.sanitize(dirty, {ADD_ATTR: [' my-attr']});// prohibir los atributos ARIA, dejar otros HTML seguros como están (el valor predeterminado es verdadero)const clean = DOMPurify.sanitize(dirty, {ALLOW_ARIA_ATTR: false});// prohibir los atributos de datos HTML5, dejar otros HTML seguros como están (el valor predeterminado es verdadero) const clean = DOMPurify.sanitize(dirty, {ALLOW_DATA_ATTR: false});
// DOMPurify permite definir reglas para elementos personalizados. Al utilizar el literal CUSTOM_ELEMENT_HANDLING//, es posible definir exactamente qué elementos desea permitir (de forma predeterminada, no se permite ninguno).//// Lo mismo ocurre con sus atributos. De forma predeterminada, se usa la lista permitida incorporada o configurada.//// Puede usar un literal RegExp para especificar lo que está permitido o un predicado; a continuación se pueden ver ejemplos de ambos.// Los valores predeterminados son muy restrictivos para evitar omisiones accidentales de XSS. ¡Manéjelo con mucho cuidado! const clean = DOMPurify.sanitize('<foo-bar baz="foobar" prohibido="true"></foo-bar><div is="foo-baz"></div>', {CUSTOM_ELEMENT_HANDLING: {tagNameCheck: null, // no se permiten elementos personalizadosattributeNameCheck: null, // se utiliza la lista de permitidos de atributos predeterminados/estándarallowCustomizedBuiltInElements: false, // no personalizado incorporados permitidos},}); // <div is=""></div>const clean = DOMPurify.sanitize('<foo-bar baz="foobar" prohibido="true"></foo-bar><div is="foo-baz "></div>',{CUSTOM_ELEMENT_HANDLING: {tagNameCheck: /^foo-/, // permite todas las etiquetas que comienzan con "foo-"attributeNameCheck: /baz/, // permite todos los atributos que contienen "baz"allowCustomizedBuiltInElements: true, // se permiten elementos integrados personalizados},}); // <foo-bar baz="foobar"></foo-bar><div is="foo-baz"></div>const clean = DOMPurify.sanitize('<foo-bar baz="foobar" prohibido ="true"></foo-bar><div is="foo-baz"></div>',{CUSTOM_ELEMENT_HANDLING: {tagNameCheck: (tagName) => tagName.match(/^foo-/), // permite todas las etiquetas que comienzan con "foo-"attributeNameCheck: (attr) => attr.match(/baz/), // permite todas las que contienen "baz"allowCustomizedBuiltInElements: true, // permitir funciones integradas personalizadas},}); // <foo-bar baz="foobar"></foo-bar><div is="foo-baz"></div>
// ampliar la matriz existente de elementos que pueden usar Data URIsconst clean = DOMPurify.sanitize(dirty, {ADD_DATA_URI_TAGS: ['a', 'area']});// ampliar la matriz existente de elementos que son seguros para URI- valores similares (tenga cuidado, riesgo XSS) const clean = DOMPurify.sanitize(dirty, {ADD_URI_SAFE_ATTR: ['my-attr']});
// permitir controladores de protocolos externos en los atributos de URL (el valor predeterminado es falso, tenga cuidado, riesgo XSS) // de forma predeterminada solo se permiten http, https, ftp, ftps, tel, mailto, callto, sms, cid y xmpp.const clean = DOMPurify.sanitize(dirty, {ALLOW_UNKNOWN_PROTOCOLS: true});// permite controladores de protocolos específicos en atributos de URL a través de expresiones regulares (el valor predeterminado es falso, sea cuidado, riesgo XSS)// de forma predeterminada solo se permiten http, https, ftp, ftps, tel, mailto, callto, sms, cid y xmpp.// RegExp predeterminada: /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^az]|[a-z+.-]+(?:[^ a-z+.-:]|$))/i;const clean = DOMPurify.sanitize(sucio, {ALLOWED_URI_REGEXP: /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|xxx):|[^az]|[a-z+.-]+(?: [^a-z+.-:]|$))/i});
// devuelve un DOM HTMLBodyElement en lugar de una cadena HTML (el valor predeterminado es falso)const clean = DOMPurify.sanitize(dirty, {RETURN_DOM: true});// devuelve un DOM DocumentFragment en lugar de una cadena HTML (el valor predeterminado es falso)const clean = DOMPurify.sanitize(dirty, {RETURN_DOM_FRAGMENT: true});// usa el indicador RETURN_TRUSTED_TYPE para active la compatibilidad con tipos de confianza si está disponibleconst clean = DOMPurify.sanitize(dirty, {RETURN_TRUSTED_TYPE: true}); // devolverá un objeto TrustedHTML en lugar de una cadena si es posible// usará una política de tipos confiables proporcionadaconst clean = DOMPurify.sanitize(dirty, {// la política proporcionada debe definir createHTML y createScriptURLTRUSTED_TYPES_POLICY:trustedTypes.createPolicy({createHTML(s) { return s},createScriptURL(s) { return s},}});
// devuelve el documento completo, incluidas las etiquetas <html> (el valor predeterminado es falso)const clean = DOMPurify.sanitize(dirty, {WHOLE_DOCUMENT: true});// deshabilita la protección DOM Clobbering en la salida (el valor predeterminado es verdadero, manéjelo con cuidado, XSS menor riesgos aquí)const clean = DOMPurify.sanitize(dirty, {SANITIZE_DOM: false});// aplicar una estricta protección contra DOM Clobbering a través del aislamiento del espacio de nombres (predeterminado es falso)// cuando está habilitado, aísla el espacio de nombres de las propiedades nombradas (es decir, los atributos `id` y `name`)// de las variables JS al anteponerles la cadena `user-content-`const clean = DOMPurify.sanitize( sucio, {SANITIZE_NAMED_PROPS: verdadero});// mantiene el contenido de un elemento cuando se elimina el elemento (el valor predeterminado es verdadero)const clean = DOMPurify.sanitize(sucio, {KEEP_CONTENT: false});// pega elementos como estilo, secuencia de comandos u otros en document.body y evita un comportamiento poco intuitivo del navegador en varios casos extremos (el valor predeterminado es false) const clean = DOMPurify.sanitize(dirty, {FORCE_BODY: true} );// elimina todos los elementos <a> debajo de los elementos <p> que se eliminanconst clean = DOMPurify.sanitize(dirty, {FORBID_CONTENTS: ['a'], FORBID_TAGS: ['p']});// cambiar el tipo de analizador para que los datos desinfectados se traten como XML y no como HTML, que es el valor predeterminadoconst clean = DOMPurify.sanitize(dirty, {PARSER_MEDIA_TYPE: ' aplicación/xhtml+xml'});
// usa el modo IN_PLACE para desinfectar un nodo "en su lugar", lo cual es mucho más rápido dependiendo de cómo uses DOMPurifyconst dirty = document.createElement('a');dirty.setAttribute('href', 'javascript:alert(1 )');const clean = DOMPurify.sanitize(sucio, {IN_PLACE: verdadero}); // consulte https://github.com/cure53/DOMPurify/issues/288 para obtener más información
Hay aún más ejemplos aquí, que muestran cómo puede ejecutar, personalizar y configurar DOMPurify para satisfacer sus necesidades.
En lugar de pasar repetidamente la misma configuración a DOMPurify.sanitize
, puede utilizar el método DOMPurify.setConfig
. Su configuración persistirá hasta su próxima llamada a DOMPurify.setConfig
, o hasta que invoque DOMPurify.clearConfig
para restablecerla. Recuerde que solo hay una configuración activa, lo que significa que una vez establecida, se ignoran todos los parámetros de configuración adicionales pasados a DOMPurify.sanitize
.
DOMPurify le permite aumentar su funcionalidad adjuntando una o más funciones con el método DOMPurify.addHook
a uno de los siguientes enlaces:
beforeSanitizeElements
uponSanitizeElement
(No 's' - llamado para cada elemento)
afterSanitizeElements
beforeSanitizeAttributes
uponSanitizeAttribute
afterSanitizeAttributes
beforeSanitizeShadowDOM
uponSanitizeShadowNode
afterSanitizeShadowDOM
Pasa el nodo DOM actualmente procesado, cuando es necesario, un literal con datos de atributos y nodos verificados y la configuración de DOMPurify a la devolución de llamada. Consulte la demostración del enlace MentalJS para ver cómo se puede utilizar correctamente la API.
Ejemplo :
DOMPurify.addHook( 'uponSanitizeAttribute', function (currentNode, hookEvent, config) {// Hacer algo con el nodo actual// También puedes mutar hookEvent para el nodo actual (es decir, establecer hookEvent.forceKeepAttr = true)// Para tipos de gancho distintos a 'uponSanitizeAttribute', hookEvent es igual a nulo });
Opción | Desde | Nota |
---|---|---|
SAFE_FOR_JQUERY | 2.1.0 | No se requiere reemplazo. |
Actualmente utilizamos Github Actions en combinación con BrowserStack. Esto nos da la posibilidad de confirmar para todas y cada una de las confirmaciones que todo va según lo planeado en todos los navegadores compatibles. Consulte los registros de compilación aquí: https://github.com/cure53/DOMPurify/actions
Puede ejecutar más pruebas locales ejecutando npm test
. Las pruebas funcionan bien con Node.js v0.6.2 y [email protected].
Todas las confirmaciones relevantes se firmarán con la clave 0x24BB6BF4
para mayor seguridad (desde el 8 de abril de 2016).
npm i
) Apoyamos npm
oficialmente. El flujo de trabajo de GitHub Actions está configurado para instalar dependencias usando npm
. Cuando utilizamos una versión obsoleta de npm
no podemos garantizar completamente las versiones de las dependencias instaladas, lo que podría provocar problemas imprevistos.
Confiamos en npm run-scripts para integrarnos con nuestra infraestructura de herramientas. Usamos ESLint como gancho de confirmación previa para garantizar la coherencia del código. Además, para facilitar el formateo utilizamos más bonito mientras la construcción de los activos /dist
se realiza mediante rollup
.
Estos son nuestros scripts npm:
npm run dev
para comenzar a construir mientras observa las fuentes en busca de cambios
npm run test
para ejecutar nuestro conjunto de pruebas a través de jsdom y karma
test:jsdom
para ejecutar pruebas solo a través de jsdom
test:karma
para ejecutar pruebas solo a través del karma
npm run lint
para eliminar las fuentes usando ESLint (a través de xo)
npm run format
para formatear nuestras fuentes usando más bonito para facilitar el paso de ESLint
npm run build
para construir nuestros activos de distribución minimizados y no minificados como un módulo UMD
npm run build:umd
para construir solo un módulo UMD no minificado
npm run build:umd:min
para construir solo un módulo UMD minimizado
Nota: todos los scripts de ejecución se activan mediante npm run <script>
.
Hay más scripts npm, pero principalmente se integran con CI o están destinados a ser "privados", por ejemplo, para modificar archivos de distribución de compilación con cada confirmación.
nosotros ma