Zum Inhalt springen
Deutsch

HTML-Antworten & XSS-Schutz

Das html-Tagged-Template escapet standardmäßig jede Interpolation — eine HTML-Antwort zu bauen ist also sicher, ohne darüber nachzudenken. completeHtml sendet sie mit dem richtigen Content-Type.

import { completeHtml, html, Status } from 'actor-ts/http';
get((req) => {
const name = req.query.name ?? 'world'; // untrusted
return completeHtml(Status.OK, html`
<h1>Hello, ${name}!</h1>
`);
});

Ist name gleich <script>alert(1)</script>, lautet die Ausgabe Hello, &lt;script&gt;alert(1)&lt;/script&gt;! — wirkungslos.

ExportZweck
escapeHtml(s)Escapet & < > " ' und das Backtick.
html`…`Tagged Template; escapet Interpolationen, liefert SafeHtml.
SafeHtmlBrand für bereits sicheres HTML; wird verbatim eingesetzt.
rawHtml(s)Umschließt einen String, den du bereits sicher gemacht hast.
completeHtml(status, body, headers?)text/html; charset=utf-8 + X-Content-Type-Options: nosniff.

Interpolationsregeln für html`…`: ein SafeHtml-Wert wird verbatim eingesetzt (Fragmente verschachteln also), Arrays werden Element für Element gerendert, null/undefined werden zum leeren String, alles andere wird zu einem String gecastet und escapet.

const items = ['<a>', '<b>'];
const list = html`<ul>${items.map((i) => html`<li>${i}</li>`)}</ul>`;
// <ul><li>&lt;a&gt;</li><li>&lt;b&gt;</li></ul>

Escaping neutralisiert Markup — es macht von Angreifern verfasstes HTML nicht sicher, um es als HTML zu rendern. Musst du Rich-HTML annehmen (Kommentare, Wiki-Markup), sanitisiere es mit einer dedizierten, kampferprobten Bibliothek wie sanitize-html oder DOMPurify, bevor du das Ergebnis in rawHtml verpackst. Ein konservativer, eingebauter Sanitizer wird separat verfolgt.