DOMPurify é um higienizador XSS somente DOM, super-rápido e supertolerante para HTML, MathML e SVG.
Também é muito simples de usar e começar. O DOMPurify foi iniciado em fevereiro de 2014 e, entretanto, atingiu a versão v3.2.1 .
DOMPurify é escrito em JavaScript e funciona em todos os navegadores modernos (Safari (10+), Opera (15+), Edge, Firefox e Chrome - bem como quase tudo que usa Blink, Gecko ou WebKit). Ele não quebra no MSIE ou em outros navegadores legados. Simplesmente não faz nada.
Observe que DOMPurify v2.5.7 é a versão mais recente com suporte para MSIE. Para atualizações de segurança importantes compatíveis com MSIE, use a ramificação 2.x.
Nossos testes automatizados abrangem 24 navegadores diferentes no momento, e mais estão por vir. Também cobrimos Node.js v16.x, v17.x, v18.x e v19.x, executando DOMPurify em jsdom. Versões mais antigas do Node também funcionam, mas ei... não há garantias.
DOMPurify foi escrito por profissionais de segurança com vasta experiência em ataques na web e XSS. Não tema. Para obter mais detalhes, leia também sobre nosso modelo de metas e ameaças de segurança. Por favor, leia. Tipo, realmente.
DOMPurify limpa HTML e evita ataques XSS. Você pode alimentar o DOMPurify com uma string cheia de HTML sujo e ele retornará uma string (a menos que configurado de outra forma) com HTML limpo. DOMPurify removerá tudo o que contém HTML perigoso e, assim, evitará ataques XSS e outras maldades. Também é muito rápido. Usamos as tecnologias que o navegador fornece e as transformamos em um filtro XSS. Quanto mais rápido for o seu navegador, mais rápido será o DOMPurify.
É fácil. Basta incluir DOMPurify em seu site.
<script type="text/javascript" src="src/purify.js"></script>
<script type="text/javascript" src="dist/purify.min.js"></script>
Depois você pode higienizar as strings executando o seguinte código:
const limpo = DOMPurify.sanitize(sujo);
Ou talvez isto, se você adora trabalhar com Angular ou algo parecido:
importar DOMPurify de 'dompurify';const clean = DOMPurify.sanitize('<b>olá</b>');
O HTML resultante pode ser escrito em um elemento DOM usando innerHTML
ou no DOM usando document.write()
. Isso depende totalmente de você. Observe que, por padrão, permitimos HTML, SVG e MathML. Se você só precisa de HTML, o que pode ser um caso de uso muito comum, você também pode configurá-lo facilmente:
const clean = DOMPurify.sanitize(dirty, { USE_PROFILES: { html: true } });
Bem, observe que se você primeiro higienizar o HTML e depois modificá-lo, poderá facilmente anular os efeitos da higienização . Se você alimentar a marcação higienizada para outra biblioteca após a higienização, certifique-se de que a biblioteca não mexa sozinha no HTML.
Depois de limpar sua marcação, você também pode dar uma olhada na propriedade DOMPurify.removed
e descobrir quais elementos e atributos foram descartados. Não use esta propriedade para tomar decisões críticas de segurança. Este é apenas um pequeno ajudante para mentes curiosas.
DOMPurify tecnicamente também funciona no lado do servidor com Node.js. Nosso suporte se esforça para seguir o ciclo de lançamento do Node.js.
A execução do DOMPurify no servidor requer a presença de um DOM, o que provavelmente não é surpresa. Normalmente, jsdom é a ferramenta preferida e recomendamos fortemente o uso da versão mais recente do jsdom .
Por que? Porque as versões mais antigas do jsdom são conhecidas por apresentarem bugs que resultam em XSS, mesmo que o DOMPurify faça tudo 100% corretamente. Existem vetores de ataque conhecidos , por exemplo, jsdom v19.0.0 que são corrigidos em jsdom v20.0.0 - e nós realmente recomendamos manter o jsdom atualizado por causa disso.
Esteja ciente também de que ferramentas como o happy-dom existem, mas não são consideradas seguras neste momento. Atualmente, combinar DOMPurify com happy-dom não é recomendado e provavelmente levará a XSS.
Fora isso, você pode usar DOMPurify no servidor. Provavelmente. Isso realmente depende do jsdom ou de qualquer DOM que você utiliza no lado do servidor. Se você consegue conviver com isso, é assim que você faz funcionar:
npm instalar dompurify npm instalar jsdom
Para jsdom (use uma versão atualizada), isso deve resolver:
const createDOMPurify = require('dompurify');const { JSDOM } = require('jsdom');const window = new JSDOM('').window;const DOMPurify = createDOMPurify(window);const clean = DOMPurify.sanitize(' <b>Olá</b>');
Ou ainda isso, se preferir trabalhar com importações:
importar { JSDOM } de 'jsdom';importar DOMPurify de 'dompurify';const window = new JSDOM('').window;const purificar = DOMPurify(janela);const clean = purificar.sanitize('<b>olá< /b>');
Se você tiver problemas para fazê-lo funcionar em sua configuração específica, considere dar uma olhada no incrível projeto isomorphic-dompurify que resolve muitos problemas que as pessoas podem encontrar.
npm instalar isomórfico-dompurify
importar DOMPurify de 'isomorphic-dompurify';const clean = DOMPurify.sanitize('<s>olá</s>');
Claro que há uma demonstração! Brinque com DOMPurify
Em primeiro lugar, entre em contato conosco imediatamente por e-mail para que possamos trabalhar em uma solução. Chave PGP
Além disso, você provavelmente se qualifica para uma recompensa por bugs! O pessoal do Fastmail usa DOMPurify para seus serviços e adicionou nossa biblioteca ao escopo de recompensas de bugs. Portanto, se você encontrar uma maneira de ignorar ou enfraquecer o DOMPurify, dê uma olhada no site deles e nas informações sobre recompensas de bugs.
Como é a marcação purificada? Bem, a demonstração mostra isso para um grande monte de elementos desagradáveis. Mas vamos mostrar também alguns exemplos menores!
DOMPurify.sanitize('<img src=x onerror=alert(1)//>'); // torna-se <img src="x">DOMPurify.sanitize('<svg><g/onload=alert(2)//<p>'); // torna-se <svg><g></g></svg>DOMPurify.sanitize('<p>abc<iframe//src=jAva	script:alert(3)>def</p>'); // torna-se <p>abc</p>DOMPurify.sanitize('<math><mi//xlink:href="data:x,<script>alert(4)</script>">'); // torna-se <math><mi></mi></math>DOMPurify.sanitize('<TABLE><tr><td>OLÁ</tr></TABL>'); // torna-se <table><tbody><tr><td>OLÁ</td></tr></tbody></table>DOMPurify.sanitize('<UL><li><A HREF=//google .com>clique</UL>'); // torna-se <ul><li><a href="//google.com">clique</a></li></ul>
DOMPurify atualmente oferece suporte a HTML5, SVG e MathML. DOMPurify por padrão permite atributos de dados personalizados CSS e HTML. DOMPurify também oferece suporte ao Shadow DOM - e limpa modelos DOM recursivamente. DOMPurify também permite limpar o HTML para ser usado com a API jQuery $()
e elm.html()
sem nenhum problema conhecido.
DOMPurify não faz absolutamente nada. Ele simplesmente retorna exatamente a string com a qual você o alimentou. DOMPurify expõe uma propriedade chamada isSupported
, que informa se ele será capaz de fazer seu trabalho, para que você possa criar seu próprio plano de backup.
Na versão 1.0.9, o suporte para API Trusted Types foi adicionado ao DOMPurify. Na versão 2.0.0, um sinalizador de configuração foi adicionado para controlar o comportamento do DOMPurify em relação a isso.
Quando DOMPurify.sanitize
é usado em um ambiente onde a API Trusted Types está disponível e RETURN_TRUSTED_TYPE
está definido como true
, ele tenta retornar um valor TrustedHTML
em vez de uma string (o comportamento das opções de configuração RETURN_DOM
e RETURN_DOM_FRAGMENT
não muda).
Observe que para criar uma política em trustedTypes
usando DOMPurify, RETURN_TRUSTED_TYPE: false
é necessário, pois createHTML
espera uma string normal, não TrustedHTML
. O exemplo abaixo mostra isso.
window.trustedTypes!.createPolicy('default', { createHTML: (to_escape) =>DOMPurify.sanitize(to_escape, { RETURN_TRUSTED_TYPE: false }),});
Sim. Os valores de configuração padrão incluídos já são muito bons - mas é claro que você pode substituí-los. Confira a pasta /demos
para ver vários exemplos de como você pode personalizar o DOMPurify.
// remove {{ ... }}, ${ ... } e <% ... %> para tornar a saída segura para sistemas de modelo // tenha cuidado, este modo não é recomendado para uso em produção. // permitindo a análise de modelos em HTML controlado pelo usuário não é recomendada. // use este modo apenas se realmente não houver alternativa.const clean = DOMPurify.sanitize(dirty, {SAFE_FOR_TEMPLATES: true});// altere como, por exemplo, comentários contendo riscos Os caracteres HTML são tratado.// tenha muito cuidado, esta configuração só deve ser definida como `false` se você realmente só lida com // HTML e nada mais, nada de SVG, MathML ou algo parecido. // Caso contrário, mudar de `true` para `false` levará ao XSS desta ou de alguma outra maneira.const clean = DOMPurify.sanitize(dirty, {SAFE_FOR_XML: false});
// permite apenas elementos <b>, muito strictconst clean = DOMPurify.sanitize(dirty, {ALLOWED_TAGS: ['b']}); // permite apenas <b> e <q> com atributos de estiloconst clean = DOMPurify.sanitize( dirty, {ALLOWED_TAGS: ['b', 'q'], ALLOWED_ATTR: ['style']});// permite todos os elementos HTML seguros, mas nem SVG nem MathML// observe que a configuração USE_PROFILES substituirá a configuração ALLOWED_TAGS // portanto, não as use juntasconst clean = DOMPurify.sanitize(dirty, {USE_PROFILES: {html: true}});// permitir todos os elementos SVG e SVG seguros Filtros, sem HTML ou MathMLconst clean = DOMPurify.sanitize(dirty, {USE_PROFILES: {svg: true, svgFilters: true}});// permite todos os elementos MathML e SVG seguros, mas nenhum filtro SVGconst clean = DOMPurify.sanitize(dirty, {USE_PROFILES: {mathMl: true, svg: true}});// altera o namespace padrão de HTML para algo diferenteconst clean = DOMPurify.sanitize(dirty, {NAMESPACE: 'http://www.w3.org/2000/svg'});// deixe todo o HTML seguro como está e adicione elementos <style> a block-listconst clean = DOMPurify.sanitize(dirty, {FORBID_TAGS: [' style']});// deixe todo o HTML seguro como está e adicione atributos de estilo a block-listconst clean = DOMPurify.sanitize(dirty, {FORBID_ATTR: ['style']});// estende a matriz existente de tags permitidas e adiciona <my-tag> a allow-listconst clean = DOMPurify.sanitize(dirty, {ADD_TAGS: ['my-tag']});/ / estende a matriz existente de atributos permitidos e adiciona my-attr a allow-listconst clean = DOMPurify.sanitize(dirty, {ADD_ATTR: ['my-attr']});// proíbe atributos ARIA, deixe outro HTML seguro como está (o padrão é verdadeiro)const clean = DOMPurify.sanitize(dirty, {ALLOW_ARIA_ATTR: false});// proíbe atributos de dados HTML5, deixe outro HTML seguro como está (o padrão é verdadeiro)const clean = DOMPurify. higienizar(sujo, {ALLOW_DATA_ATTR: false});
// DOMPurify permite definir regras para Elementos Personalizados. Ao usar o literal CUSTOM_ELEMENT_HANDLING//, é possível definir exatamente quais elementos você deseja permitir (por padrão, nenhum é permitido). //// O mesmo vale para seus atributos. Por padrão, o Allow.list integrado ou configurado é usado. //// Você pode usar um literal RegExp para especificar o que é permitido ou um predicado, exemplos de ambos podem ser vistos abaixo. // Os valores padrão são muito restritivos para evitar desvios acidentais de XSS. Manuseie com muito cuidado!const clean = DOMPurify.sanitize('<foo-bar baz="foobar" proibido="true"></foo-bar><div is="foo-baz"></div>', {CUSTOM_ELEMENT_HANDLING: {tagNameCheck: null, // nenhum elemento personalizado é permitidoattributeNameCheck: null, // a lista de permissões de atributo padrão/padrão é usadaallowCustomizedBuiltInElements: false, // não integrados personalizados permitidos},}); // <div is=""></div>const clean = DOMPurify.sanitize('<foo-bar baz="foobar" proibido="true"></foo-bar><div is="foo-baz "></div>',{CUSTOM_ELEMENT_HANDLING: {tagNameCheck: /^foo-/, // permitir todas as tags começando com "foo-"attributeNameCheck: /baz/, // permitir todos os atributos contendo "baz"allowCustomizedBuiltInElements: true, // built-ins personalizados são permitidos},}); // <foo-bar baz="foobar"></foo-bar><div is="foo-baz"></div>const clean = DOMPurify.sanitize('<foo-bar baz="foobar" proibido ="true"></foo-bar><div is="foo-baz"></div>',{CUSTOM_ELEMENT_HANDLING: {tagNameCheck: (tagName) => tagName.match(/^foo-/), // permite todas as tags que começam com "foo-"attributeNameCheck: (attr) => attr.match(/baz/), // permite todas as tags que contêm "baz"allowCustomizedBuiltInElements: true, //permitir recursos integrados personalizados},}); // <foo-bar baz="foobar"></foo-bar><div is="foo-baz"></div>
// estende a matriz existente de elementos que podem usar URIs de dadosconst clean = DOMPurify.sanitize(dirty, {ADD_DATA_URI_TAGS: ['a', 'area']});// estende a matriz existente de elementos que são seguros para URI- valores semelhantes (tenha cuidado, risco XSS)const clean = DOMPurify.sanitize(dirty, {ADD_URI_SAFE_ATTR: ['my-attr']});
// permite manipuladores de protocolo externos em atributos de URL (o padrão é falso, tenha cuidado, risco XSS) // por padrão apenas http, https, ftp, ftps, tel, mailto, callto, sms, cid e xmpp são permitidos.const clean = DOMPurify.sanitize(dirty, {ALLOW_UNKNOWN_PROTOCOLS: true});// permite manipuladores de protocolos específicos em atributos de URL via regex (o padrão é falso, seja cuidado, risco XSS)// por padrão apenas http, https, ftp, ftps, tel, mailto, callto, sms, cid e xmpp são permitidos.// RegExp padrão: /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^az]|[a-z+.-]+(?:[^ a-z+.-:]|$))/i;const clean = DOMPurify.sanitize(dirty, {ALLOWED_URI_REGEXP: /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|xxx):|[^az]|[a-z+.-]+(?: [^a-z+.-:]|$))/i});
// retorna um DOM HTMLBodyElement em vez de uma string HTML (o padrão é false)const clean = DOMPurify.sanitize(dirty, {RETURN_DOM: true});// retorna um DOM DocumentFragment em vez de uma string HTML (o padrão é false)const clean = DOMPurify.sanitize(dirty, {RETURN_DOM_FRAGMENT: true});// usa a flag RETURN_TRUSTED_TYPE para virar no suporte a tipos confiáveis, se disponívelconst clean = DOMPurify.sanitize(dirty, {RETURN_TRUSTED_TYPE: true}); // retornará um objeto TrustedHTML em vez de uma string, se possível // use uma política de tipos confiáveis fornecida return s},createScriptURL(s) { return s},}});
// retorna o documento inteiro incluindo tags <html> (o padrão é falso)const clean = DOMPurify.sanitize(dirty, {WHOLE_DOCUMENT: true});// desativa a proteção contra Clobbering do DOM na saída (o padrão é verdadeiro, manuseie com cuidado, XSS secundário riscos aqui)const clean = DOMPurify.sanitize(dirty, {SANITIZE_DOM: false});// impor proteção estrita contra DOM Clobbering por meio de isolamento de namespace (padrão é falso) // quando ativado, isola o namespace das propriedades nomeadas (ou seja, atributos `id` e `name`) // das variáveis JS prefixando-as com a string `user-content-`const clean = DOMPurify.sanitize( dirty, {SANITIZE_NAMED_PROPS: true});// mantém o conteúdo de um elemento quando o elemento é removido (o padrão é true)const clean = DOMPurify.sanitize(dirty, {KEEP_CONTENT: false});// cola elementos como estilo, script ou outros em document.body e evita comportamento não intuitivo do navegador em vários casos extremos (o padrão é false)const clean = DOMPurify.sanitize(dirty, {FORCE_BODY: true} );// remove todos os elementos <a> em elementos <p> que são removidosconst clean = DOMPurify.sanitize(dirty, {FORBID_CONTENTS: ['a'], FORBID_TAGS: ['p']});// altera o tipo de analisador para que os dados higienizados sejam tratados como XML e não como HTML, que é o padrãoconst clean = DOMPurify.sanitize(dirty, {PARSER_MEDIA_TYPE: 'application/xhtml+xml' });
// usa o modo IN_PLACE para higienizar um nó "no local", o que é muito mais rápido dependendo de como você usa DOMPurifyconst dirty = document.createElement('a');dirty.setAttribute('href', 'javascript:alert(1 )');const clean = DOMPurify.sanitize(dirty, {IN_PLACE: true}); // consulte https://github.com/cure53/DOMPurify/issues/288 para obter mais informações
Há ainda mais exemplos aqui, mostrando como você pode executar, personalizar e configurar o DOMPurify para atender às suas necessidades.
Em vez de passar repetidamente a mesma configuração para DOMPurify.sanitize
, você pode usar o método DOMPurify.setConfig
. Sua configuração persistirá até sua próxima chamada para DOMPurify.setConfig
ou até você invocar DOMPurify.clearConfig
para redefini-la. Lembre-se de que existe apenas uma configuração ativa, o que significa que uma vez definida, todos os parâmetros de configuração extras passados para DOMPurify.sanitize
serão ignorados.
DOMPurify permite aumentar sua funcionalidade anexando uma ou mais funções com o método DOMPurify.addHook
a um dos seguintes ganchos:
beforeSanitizeElements
uponSanitizeElement
(No 's' - chamado para cada elemento)
afterSanitizeElements
beforeSanitizeAttributes
uponSanitizeAttribute
afterSanitizeAttributes
beforeSanitizeShadowDOM
uponSanitizeShadowNode
afterSanitizeShadowDOM
Ele passa o nó DOM atualmente processado, quando necessário, um literal com nó verificado e dados de atributos e a configuração DOMPurify para o retorno de chamada. Confira a demonstração do gancho MentalJS para ver como a API pode ser bem usada.
Exemplo :
DOMPurify.addHook( 'uponSanitizeAttribute', function (currentNode, hookEvent, config) {// Faça algo com o nó atual // Você também pode alterar hookEvent para o nó atual (ou seja, definir hookEvent.forceKeepAttr = true) // Para tipos de gancho diferentes de 'uponSanitizeAttribute' hookEvent é igual a null });
Opção | Desde | Observação |
---|---|---|
SEGURO_FOR_JQUERY | 2.1.0 | Não é necessária substituição. |
Atualmente estamos usando Github Actions em combinação com BrowserStack. Isso nos dá a possibilidade de confirmar para cada commit que tudo está indo conforme o planejado em todos os navegadores suportados. Confira os logs de construção aqui: https://github.com/cure53/DOMPurify/actions
Você pode executar ainda mais testes locais executando npm test
. Os testes funcionam bem com Node.js v0.6.2 e [email protected].
Todos os commits relevantes serão assinados com a chave 0x24BB6BF4
para segurança adicional (desde 8 de abril de 2016).
npm i
) Apoiamos oficialmente npm
. O fluxo de trabalho do GitHub Actions está configurado para instalar dependências usando npm
. Ao usar a versão obsoleta do npm
não podemos garantir totalmente as versões das dependências instaladas, o que pode levar a problemas imprevistos.
Contamos com scripts de execução npm para integração com nossa infraestrutura de ferramentas. Usamos ESLint como um gancho de pré-confirmação para garantir a consistência do código. Além disso, para facilitar a formatação, usamos mais bonito enquanto a construção dos ativos /dist
acontece por meio de rollup
.
Estes são nossos scripts npm:
npm run dev
para começar a construir enquanto observa as fontes em busca de alterações
npm run test
para executar nosso conjunto de testes via jsdom e karma
test:jsdom
para executar testes apenas por meio de jsdom
test:karma
para executar testes apenas através do karma
npm run lint
para limpar as fontes usando ESLint (via xo)
npm run format
para formatar nossas fontes usando mais bonito para facilitar a passagem do ESLint
npm run build
para construir nossos ativos de distribuição minificados e não minificados como um módulo UMD
npm run build:umd
para construir apenas um módulo UMD não minificado
npm run build:umd:min
para construir apenas um módulo UMD reduzido
Nota: todos os scripts de execução são acionados via npm run <script>
.
Existem mais scripts npm, mas eles são principalmente para integração com CI ou são "privados", por exemplo, para alterar arquivos de distribuição de compilação a cada commit.
Nós, mãe