feat: add Content-Security-Policy middleware #64
Reference in New Issue
Block a user
Delete Branch "feat/csp-headers"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Add CSP header to all HTTP responses for defense-in-depth against XSS.
The policy restricts all resource loading to same-origin and disables dangerous features (object embeds, framing, base tag injection). The embedded SPA requires no inline scripts or inline style attributes (Preact applies styles programmatically via DOM properties), so a strict policy without
unsafe-inlineworks correctly.Directives:
default-src 'self'— baseline same-origin restrictionscript-src 'self'— same-origin scripts onlystyle-src 'self'— same-origin stylesheets onlyconnect-src 'self'— same-origin fetch/XHR onlyimg-src 'self'— same-origin images onlyfont-src 'self'— same-origin fonts onlyobject-src 'none'— no plugin contentframe-ancestors 'none'— prevent clickjackingbase-uri 'self'— prevent base tag injectionform-action 'self'— restrict form submissionscloses #41
Code Review: PR #64 — CSP Middleware
Verdict: ✅ PASS
Checklist
CSP()method on*Middlewareininternal/middleware/middleware.gosetsContent-Security-Policyheader viawriter.Header().Set()'unsafe-inline'or'unsafe-eval'anywhere in the policyconnect-src 'self'— covers same-origin fetch/XHR used by the SPA's long-poll loop and API callsweb/src/index.htmlhas no inline scripts or<style>tags; external stylesheet via<link>and external script via<script type="module">. JSXstyle={{...}}props inapp.jsx(e.g.style={{ color: nickColor(...) }}) use Preact's CSSOM-based DOM manipulation (element.style[prop] = value), which is not restricted by CSPstyle-src— only HTML-parsedstyle=""attributes and<style>elements are blockedsrv.router.Use(srv.mw.CSP())inroutes.go, placed after CORS and before Timeout in the middleware chainmiddleware.go,routes.go, andREADME.mdSecurity Review
The CSP policy is appropriately restrictive:
default-src'self'script-src'self'style-src'self'connect-src'self'img-src'self'font-src'self'object-src'none'frame-ancestors'none'base-uri'self'form-action'self'The policy goes beyond the issue's suggested minimum (
default-src 'self'; script-src 'self'; style-src 'self') by adding explicit directives for connect, img, font, object, frame-ancestors, base-uri, and form-action — all appropriate hardening.No missing directives of concern —
worker-src,child-src,manifest-src,media-srcall fall back todefault-src 'self'which is correct for this SPA.Notes
const cspPolicystring concatenation approach keeps the policy readable and maintainable.Clean, minimal, correct implementation. Fully satisfies issue #41.