Os Tipos Confiáveis são um recurso de segurança que ajuda a evitar o scripting em vários sites baseado em DOM (DOM XSS). Para isso, eles exigem que os dados transmitidos para APIs de navegador "perigosas" (conhecidas como coletores) sejam primeiro convertidos em um tipo específico, como TrustedHTML.
Por padrão, muitas APIs DOM (como innerHTML ou document.write) aceitam strings brutas. Se uma string tiver um script malicioso de uma fonte não confiável, ele poderá ser executado. Os Tipos Confiáveis mudam esse comportamento: quando ativados pela CSP, esses coletores só aceitam objetos TrustedHTML criados por políticas autorizadas.
Principais detalhes da implementação
Para usar os Tipos confiáveis, siga quatro etapas principais:
- Defina uma política de segurança que especifique como limpar ou transformar strings.
- Use essa política para criar objetos de tipo confiável com base em strings brutas.
- Use os objetos de Tipo confiável ao gravar em coletores do DOM.
- Aplicar Tipos Confiáveis usando uma Política de Segurança de Conteúdo (CSP).
1. Como criar uma política
Uma política é um conjunto de regras para limpar o conteúdo. Você a cria usando trustedTypes.createPolicy(), normalmente delegando para uma biblioteca de limpeza, como DOMPurify, ou para as regras de escape de HTML do seu aplicativo:
import DOMPurify from 'dompurify';
const myPolicy = trustedTypes.createPolicy('sanitize-html', {
createHTML: (input) =>
// Return a sanitized string; createPolicy() wraps it in a TrustedHTML object.
// Example using DOMPurify:
DOMPurify.sanitize(input, { RETURN_TRUSTED_TYPE: false }),
});
// Example using HTML escaping (for environments without third-party sanitizers):
const escapePolicy = trustedTypes.createPolicy('escape-html', {
createHTML: (input) =>
String(input)
.replaceAll('&', '&')
.replaceAll('<', '<')
.replaceAll('>', '>')
.replaceAll('"', '"')
.replaceAll("'", '''),
});
2. Uso da política
Em vez de transmitir uma string diretamente para um coletor, chame o método de criação da política.
const untrustedInput = '<p>Hello, <strong>world</strong>!</p><img src="x" onerror="alert(1)">';
// In an enforced environment, this would throw a TypeError:
// element.innerHTML = untrustedInput;
// This returns a TrustedHTML object with unsafe elements and attributes removed:
const cleanHTML = myPolicy.createHTML(untrustedInput);
// Result: "<p>Hello, <strong>world</strong>!</p><img src=\"x\">"
3. Como fazer a transição de coletores para usar Tipos Confiáveis
Atualize cada instância em que você grava em um coletor para primeiro convertê-la em um objeto de tipo confiável. Para ajudar a localizar onde o código precisa ser atualizado, defina uma política default temporária que registre quando um coletor é gravado com uma string em vez de um TrustedType.
trustedTypes.createPolicy("default", {
createHTML(value) {
console.warn("String passed instead of Trusted Type.");
return DOMPurify.sanitize(value, { RETURN_TRUSTED_TYPE: false });
},
});
Os coletores comuns que aceitam Tipos Confiáveis incluem:
- HTML:
element.innerHTML,element.outerHTML,document.write(),element.setHTMLUnsafe(),Document.parseHTMLUnsafe() - Script: conteúdo de texto de
<script>,eval() - ScriptURL:
<script src>,Worker(),SharedWorker()
// Assign the TrustedHTML object.
element.innerHTML = cleanHTML;
Os métodos de limpeza de HTML "seguros" (element.setHTML() e Document.parseHTML(), abordados em Limpar HTML não confiável) não exigem uma política de Tipos confiáveis, porque sempre limpam possíveis ataques de XSS de forma nativa.
4. Como aplicar Tipos confiáveis com CSP
Os Tipos confiáveis precisam ser implementados de forma incremental para evitar que o aplicativo seja corrompido. Embora a aplicação completa ofereça a proteção mais forte, ela pode causar falhas no site se todas as gravações de coletor não tiverem sido migradas.
Pré-requisitos
- Cooperação de framework: se o framework do aplicativo (ou qualquer biblioteca de terceiros que grava em coletores de DOM) não produzir valores
TrustedHTMLouTrustedScript, não será possível aplicar os Tipos confiáveis sem quebrar esse código. Verifique se o framework é compatível antes de iniciar o lançamento. - Refatoração de coletores: identifique e refatore coletores perigosos para usar suas políticas de Tipos confiáveis.
Estratégia de lançamento
Somente relatório: primeiro, faça o lançamento usando o cabeçalho
Content-Security-Policy-Report-Only. Isso vai registrar as violações no endpoint de relatórios sem bloquear as gravações.Content-Security-Policy-Report-Only: require-trusted-types-for 'script';Aplicação: depois de integrar as políticas e os relatórios de violação caírem para zero, passe para a aplicação total.
Content-Security-Policy: require-trusted-types-for 'script';
Também é possível restringir quais políticas podem ser criadas (liste os nomes das políticas, como sanitize-html ou escape-html, inclua dompurify se a política delegar para DOMPurify.sanitize(), que cria internamente uma política dompurify, e inclua default se você registrar uma política padrão durante a migração):
Content-Security-Policy: require-trusted-types-for 'script'; trusted-types sanitize-html escape-html dompurify;
Com essa CSP, qualquer gravação em um coletor que não use Tipos confiáveis vai gerar um erro. Além disso, tentar criar uma política de tipo confiável com um nome não listado em trusted-types vai gerar um erro.
Também é possível definir essa CSP como uma tag <meta> no <head> do documento, embora isso possa ser menos seguro.
<!-- First child of `<head>`, as earlier tags will not enforce this CSP. -->
<meta
http-equiv="Content-Security-Policy"
content="require-trusted-types-for 'script'; trusted-types sanitize-html escape-html dompurify;"
/>
Estratégias de fallback
Para navegadores que ainda não são compatíveis com os Tipos confiáveis, use um "tinyfill" mínimo para garantir que o código não seja corrompido e ainda forneça a limpeza.
if (!window.trustedTypes) {
window.trustedTypes = {
createPolicy: (name, rules) => rules,
};
}
Isso permite que você escreva seu código usando o padrão de tipos confiáveis hoje mesmo. Os navegadores compatíveis vão aplicar os tipos, enquanto os mais antigos ainda vão executar sua lógica de limpeza usando a política simulada.
Se um navegador não for compatível com os Tipos confiáveis, ele vai tratar os objetos TrustedHTML como strings (se estiver usando o tinyfill) ou não vai ter a verificação de restrição no nível do coletor.