CSPHeaders returns a middleware that sets the Content-Security-Policy header for coderd. Arguments: - proxyHosts: a function that returns a list of supported proxy hosts (including the primary). This is to support the terminal connecting to a workspace proxy and for embedding apps in an iframe. T
(telemetry bool, proxyHosts func() []*proxyhealth.ProxyHost, staticAdditions map[CSPFetchDirective][]string)
| 59 | // |
| 60 | //nolint:revive |
| 61 | func CSPHeaders(telemetry bool, proxyHosts func() []*proxyhealth.ProxyHost, staticAdditions map[CSPFetchDirective][]string) func(next http.Handler) http.Handler { |
| 62 | return func(next http.Handler) http.Handler { |
| 63 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
| 64 | // Content-Security-Policy disables loading certain content types and can prevent XSS injections. |
| 65 | // This site helps eval your policy for syntax and other common issues: https://csp-evaluator.withgoogle.com/ |
| 66 | // If we ever want to render something like a PDF, we need to adjust "object-src" |
| 67 | // |
| 68 | // The list of CSP options: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/default-src |
| 69 | cspSrcs := cspDirectives{ |
| 70 | // All omitted fetch csp srcs default to this. |
| 71 | CSPDirectiveDefaultSrc: {"'self'"}, |
| 72 | CSPDirectiveConnectSrc: {"'self'"}, |
| 73 | CSPDirectiveChildSrc: {"'self'"}, |
| 74 | // https://github.com/suren-atoyan/monaco-react/issues/168 |
| 75 | CSPDirectiveScriptSrc: {"'self'"}, |
| 76 | CSPDirectiveStyleSrc: {"'self' 'unsafe-inline'"}, |
| 77 | // data: is used by monaco editor on FE for Syntax Highlight |
| 78 | CSPDirectiveFontSrc: {"'self' data:"}, |
| 79 | CSPDirectiveWorkerSrc: {"'self' blob:"}, |
| 80 | // object-src is needed to support code-server |
| 81 | CSPDirectiveObjectSrc: {"'self'"}, |
| 82 | // blob: for loading the pwa manifest for code-server |
| 83 | CSPDirectiveManifestSrc: {"'self' blob:"}, |
| 84 | CSPDirectiveFrameSrc: {"'self'"}, |
| 85 | // data: for loading base64 encoded icons for generic applications. |
| 86 | // https: allows loading images from external sources. This is not ideal |
| 87 | // but is required for the templates page that renders readmes. |
| 88 | // We should find a better solution in the future. |
| 89 | CSPDirectiveImgSrc: {"'self' https: data:"}, |
| 90 | CSPDirectiveFormAction: {"'self'"}, |
| 91 | CSPDirectiveMediaSrc: {"'self'"}, |
| 92 | // Report all violations back to the server to log |
| 93 | CSPDirectiveReportURI: {"/api/v2/csp/reports"}, |
| 94 | |
| 95 | // Only scripts can manipulate the dom. This prevents someone from |
| 96 | // naming themselves something like '<svg onload="alert(/cross-site-scripting/)" />'. |
| 97 | // "require-trusted-types-for" : []string{"'script'"}, |
| 98 | } |
| 99 | |
| 100 | if telemetry { |
| 101 | // If telemetry is enabled, we report to coder.com. |
| 102 | cspSrcs.Append(CSPDirectiveConnectSrc, "https://coder.com") |
| 103 | } |
| 104 | |
| 105 | // This extra connect-src addition is required to support old webkit |
| 106 | // based browsers (Safari). |
| 107 | // See issue: https://github.com/w3c/webappsec-csp/issues/7 |
| 108 | // Once webkit browsers support 'self' on connect-src, we can remove this. |
| 109 | // When we remove this, the csp header can be static, as opposed to being |
| 110 | // dynamically generated for each request. |
| 111 | host := r.Host |
| 112 | // It is important r.Host is not an empty string. |
| 113 | if host != "" { |
| 114 | // We can add both ws:// and wss:// as browsers do not let https |
| 115 | // pages to connect to non-tls websocket connections. So this |
| 116 | // supports both http & https webpages. |
| 117 | cspSrcs.Append(CSPDirectiveConnectSrc, fmt.Sprintf("wss://%[1]s ws://%[1]s", host)) |
| 118 | } |