Evite vulnerabilidades de scripting cross-site baseado em DOM com Tipos confiáveis
Reduza a superfície de ataque DOM XSS de seu aplicativo.
Por que você deveria se importar? #
Cross-site scripting baseado em DOM (DOM XSS) é uma das vulnerabilidades de segurança da web mais comuns e é muito fácil introduzi-lo em seu aplicativo. Ps Tipos confiáveis fornecem as ferramentas para escrever, revisar a segurança e manter aplicativos livres de vulnerabilidades DOM XSS, tornando as funções perigosas da API da web seguras por padrão. Tipos confiáveis são suportados no Chrome 83 e um polyfill está disponível para outros navegadores. Consulte Compatibilidade do navegador para obter informações atualizadas de suporte entre navegadores.
Histórico #
Por muitos anos, o DOM XSS foi uma das vulnerabilidades de segurança da web mais prevalentes e perigosas.
Existem dois grupos distintos de scripting cross-site. Algumas vulnerabilidades XSS são causadas pelo código do lado do servidor que cria de forma insegura o código HTML que forma o site. Outros têm uma causa raiz no cliente, em que o código JavaScript chama funções perigosas com conteúdo controlado pelo usuário.
Para evitar o XSS do lado do servidor, não gere HTML concatenando strings e, em vez disso, use bibliotecas de modelos de escape automático contextual. Use uma Política de Segurança de Conteúdo baseada em nonce para mitigação adicional contra os bugs conforme eles inevitavelmente acontecerem.
Agora, um navegador também pode ajudar a prevenir os XSSes do lado do cliente (também conhecidos como baseados em DOM) com Tipos confiáveis .
Introdução sobre a API #
Tipos confiáveis funcionam bloqueando as seguintes funções de coletor de risco. Você já deve reconhecer alguns deles, pois os fornecedores de navegadores e estruturas da web já afastam você do uso desses recursos por motivos de segurança.
Manipulação de script :
<script src>
e configuração do conteúdo de texto dos elementos<script>
Gerando HTML a partir de uma string :
innerHTML
,outerHTML
,insertAdjacentHTML
,<iframe> srcdoc
,document.write
,document.writeln
eDOMParser.parseFromString
Executando o conteúdo do plugin :
<embed src>
,<object data>
e<object codebase>
Compilação de código JavaScript em tempo de execução :
eval
,setTimeout
,setInterval
,new Function()
Tipos confiáveis exigem que você processe os dados antes de transmiti-los às funções de coletor acima. Apenas usar uma string irá falhar, pois o navegador não sabe se os dados são confiáveis:
Não faça
anElement.innerHTML = location.href;
Para indicar que os dados foram processados com segurança, crie um objeto especial - um tipo confiável.
Faça
anElement.innerHTML = aTrustedHTML;
Tipos confiáveis reduzem fortemente a superfície de ataque DOM XSS de seu aplicativo. Ele simplifica as revisões de segurança e permite que você aplique as verificações de segurança baseadas em tipo feitas durante a compilação, linting ou agrupamento de seu código em tempo de execução, no navegador.
Como usar Tipos Confiáveis #
Prepare-se para relatórios de violação da política de segurança de conteúdo #
Você pode implantar um coletor de relatórios (como o go-csp-collector de código aberto) ou usar um dos equivalentes comerciais. Você também pode depurar as violações no navegador:
window.addEventListener('securitypolicyviolation',
console.error.bind(console));
Adicione um cabeçalho CSP somente para relatório #
Adicione o seguinte cabeçalho de resposta HTTP aos documentos que deseja migrar para tipos confiáveis.
Content-Security-Policy-Report-Only: require-trusted-types-for 'script'; report-uri //my-csp-endpoint.example
Agora todas as violações são relatadas para //my-csp-endpoint.example
, mas o site continua a funcionar. A próxima seção explica como //my-csp-endpoint.example
funciona.
Identifique violações de tipos confiáveis #
A partir de agora, toda vez que os Tipos Confiáveis detectarem uma violação, um relatório será enviado para um report-uri
configurado. Por exemplo, quando seu aplicativo passa uma string para innerHTML
, o navegador envia o seguinte relatório:
{
"csp-report": {
"document-uri": "https://my.url.example",
"violated-directive": "require-trusted-types-for",
"disposition": "report",
"blocked-uri": "trusted-types-sink",
"line-number": 39,
"column-number": 12,
"source-file": "https://my.url.example/script.js",
"status-code": 0,
"script-sample": "Element innerHTML <img src=x"
}
}
Isso diz que em https://my.url.example/script.js
na linha 39 innerHTML
foi chamado com a string começando com <img src=x
. Essas informações devem ajudá-lo a restringir quais partes do código podem estar introduzindo o DOM XSS e precisam ser alteradas.
Corrija as violações #
Existem algumas opções para corrigir uma violação de tipo confiável. Você pode remover o código ofensivo, usar uma biblioteca, criar uma política de Tipo Confiável ou, como último recurso, criar uma política padrão .
Reescreva o código ofensivo #
Talvez a funcionalidade não conforme não seja mais necessária ou possa ser reescrita de uma maneira moderna sem usar as funções sujeitas a erros?
Não faça
el.innerHTML = '<img src=xyz.jpg>';
Faça
el.textContent = '';
const img = document.createElement('img');
img.src = 'xyz.jpg';
el.appendChild(img);
Use uma biblioteca #
Algumas bibliotecas já geram Tipos Confiáveis que você pode passar para as funções de coletor. Por exemplo, você pode usar DOMPurify para limpar um trecho de HTML, removendo cargas úteis de XSS.
import DOMPurify from 'dompurify';
el.innerHTML = DOMPurify.sanitize(html, {RETURN_TRUSTED_TYPE: true});
DOMPurify suporta Trusted Tipos e irá retornar HTML higienizado envolto em um TrustedHTML
objeto de tal forma que o navegador não gera uma violação.
Crie uma política de Tipo Confiável #
Às vezes, não é possível remover a funcionalidade e não há biblioteca para higienizar o valor e criar um tipo confiável para você. Nesses casos, crie você mesmo um objeto Tipo confiável.
Para isso, primeiro crie uma política. As políticas são fábricas de Tipos Confiáveis que impõem certas regras de segurança em suas entradas:
if (window.trustedTypes && trustedTypes.createPolicy) { // Feature testing
const escapeHTMLPolicy = trustedTypes.createPolicy('myEscapePolicy', {
createHTML: string => string.replace(/\</g, '<')
});
}
Este código cria uma política chamada myEscapePolicy
que pode produzir TrustedHTML
por meio de sua função createHTML()
. As regras definidas irão escapar de HTML <
caracteres para evitar a criação de novos elementos HTML.
Use a política da seguinte forma:
const escaped = escapeHTMLPolicy.createHTML('<img src=x onerror=alert(1)>');
console.log(escaped instanceof TrustedHTML); // true
el.innerHTML = escaped; // '<img src=x onerror=alert(1)>'
Use uma política padrão #
Às vezes, você não pode alterar o código ofensivo. Por exemplo, esse é o caso se você estiver carregando uma biblioteca de terceiros de um CDN. Nesse caso, use uma política padrão:
if (window.trustedTypes && trustedTypes.createPolicy) { // Feature testing
trustedTypes.createPolicy('default', {
createHTML: (string, sink) => DOMPurify.sanitize(string, {RETURN_TRUSTED_TYPE: true})
});
}
A política com um nome default
é usada sempre que uma string é usada em um coletor que aceita apenas o tipo confiável.
Mude para a aplicação da Política de Segurança de Conteúdo #
Quando seu aplicativo não produzir mais violações, você pode começar a aplicar Tipos Confiáveis:
Content-Security-Policy: require-trusted-types-for 'script'; report-uri //my-csp-endpoint.example
Aí está! Agora, não importa o quão complexo seja seu aplicativo da web, a única coisa que pode introduzir uma vulnerabilidade DOM XSS é o código em uma de suas políticas, e você pode bloquear isso ainda mais limitando a criação de políticas .