콘텐츠로 이동
한국어

HTML responses & XSS prevention

이 콘텐츠는 아직 번역되지 않았습니다.

The html tagged template escapes every interpolation by default, so building an HTML response is safe without thinking about it. completeHtml sends it with the right 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>
`);
});

If name is <script>alert(1)</script>, the output is Hello, &lt;script&gt;alert(1)&lt;/script&gt;! — inert.

ExportWhat it does
escapeHtml(s)Escape & < > " ' and the backtick.
html`…`Tagged template; escapes interpolations, returns SafeHtml.
SafeHtmlBrand for already-safe HTML; interpolated verbatim.
rawHtml(s)Wrap a string you have already made safe.
completeHtml(status, body, headers?)text/html; charset=utf-8 + X-Content-Type-Options: nosniff.

Interpolation rules for html`…`: a SafeHtml value is inserted verbatim (so fragments nest), arrays are rendered item-by-item, null/undefined become the empty string, and everything else is coerced to a string and escaped.

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 neutralises markup — it does not make attacker-authored HTML safe to render as HTML. If you must accept rich HTML (comments, wiki markup), sanitise it with a dedicated, battle-tested library such as sanitize-html or DOMPurify before wrapping the result in rawHtml. A conservative built-in sanitizer is tracked separately.