CSP: data:-Fonts erlauben (eingebettete Fonts in Excalidraw-SVGs)

Excalidraw bettet beim Speichern die verwendeten Schrift-Subsets als
data:-URIs ins Snapshot-SVG ein. Die Seiten-CSP (nginx) und die
Plugin-Frame-CSP erlaubten aber nur `font-src 'self'` bzw. den
Asset-Pfad — die Handschrift fiel in der öffentlichen Ansicht und im
Snapshot-Render auf Serifen zurück (auf Prod an der ersten Demo-Skizze
sichtbar). Fix: `data:` in beiden font-src-Direktiven. data:-Fonts
lösen keinerlei Netzwerk-Request aus — die Zero-Third-Party-Garantie
(security.md) bleibt unberührt; fonts.ts-Kommentar entsprechend
präzisiert.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0155v2aT8AG1kZDQEZiCLBWC
This commit is contained in:
Claude Fable 5 2026-07-19 22:27:17 +02:00
parent 60be198e51
commit 75ec7f6006
3 changed files with 13 additions and 5 deletions

View File

@ -29,7 +29,10 @@ export function buildPluginFrameCsp(assetBase: string): string {
`script-src ${assetBase}`, `script-src ${assetBase}`,
`style-src ${assetBase} 'unsafe-inline'`, `style-src ${assetBase} 'unsafe-inline'`,
`img-src ${assetBase} data: blob:`, `img-src ${assetBase} data: blob:`,
`font-src ${assetBase}`, // `data:` so a saved sketch SVG with embedded (subsetted) fonts — the
// Excalidraw plugin stores those — renders its handwriting look in the
// snapshot view too. data: fonts make no network request.
`font-src ${assetBase} data:`,
// A plugin may talk to its OWN version-pinned assets (bundled apps like // A plugin may talk to its OWN version-pinned assets (bundled apps like
// drawio lazy-load stencils/resources via XHR) — and to nothing else: // drawio lazy-load stencils/resources via XHR) — and to nothing else:
// no api, no external hosts. The zero-external-network guarantee holds. // no api, no external hosts. The zero-external-network guarantee holds.

View File

@ -28,7 +28,11 @@ server {
# from this origin only (the GDPR "zero external requests" posture). # from this origin only (the GDPR "zero external requests" posture).
# `style-src 'unsafe-inline'` covers the app's inline style attributes # `style-src 'unsafe-inline'` covers the app's inline style attributes
# (CSS custom properties, layout); scripts are all external files. # (CSS custom properties, layout); scripts are all external files.
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; font-src 'self'; img-src 'self' data: blob:; connect-src 'self'; worker-src 'self'; manifest-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'" always; # font-src includes `data:` for the subsetted fonts Excalidraw embeds
# into saved sketch SVGs (inlined by the plugin fallback renderer on
# public pages). data: fonts trigger no network request, so the
# zero-third-party-request guarantee (security.md) is unaffected.
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; font-src 'self' data:; img-src 'self' data: blob:; connect-src 'self'; worker-src 'self'; manifest-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'" always;
add_header X-Content-Type-Options "nosniff" always; add_header X-Content-Type-Options "nosniff" always;
try_files $uri /index.html; try_files $uri /index.html;
} }

View File

@ -5,9 +5,10 @@
* page lists their licenses. Adding a font is a change here + an image rebuild * page lists their licenses. Adding a font is a change here + an image rebuild
* there is no runtime font management (deliberately small surface). * there is no runtime font management (deliberately small surface).
* *
* Fonts are served only from the instance itself (`font-src 'self'`); a * Fonts are served only from the instance itself (`font-src 'self' data:`
* visitor's browser makes zero third-party requests (the GDPR guarantee, * the `data:` part covers fonts embedded inline in saved plugin SVGs, e.g.
* security.md). * Excalidraw sketches); a visitor's browser makes zero third-party requests
* (the GDPR guarantee, security.md).
*/ */
export type FontCategory = 'sans-serif' | 'serif' | 'monospace'; export type FontCategory = 'sans-serif' | 'serif' | 'monospace';
export type FontLicense = 'OFL-1.1' | 'Apache-2.0'; export type FontLicense = 'OFL-1.1' | 'Apache-2.0';