Add support for Content Security Policy nonces
Closed this issue · 6 comments
Description
A common technique to mitigate XSS attacks, is to use a Content Security Policy. The server sends a header detailing with a whitelist of scripts and resources that are allowed to be included in the page.
Scripts can be whitelisted by origin, secure hash, or with a nonce effectively signing the contents of the page. To implement such a nonce, you need to do the following:
- Generate a cryptographically secure nonce
$nonce
- Send the CSP header containing said nonce `Content-Security-Policy: script-src nonce-$nonce;
- For every inline script, add the nonce to its opening tag
<script nonce="$nonce">
It is currently doable to implement this, but it requires some awkward interactions between the Response
object and the template being rendered. It would be nice if the Request
object got some kind of native support for the content security policy mechanism to aid in implementing this. I have two ideas in mind shown below, but I'd love to hear comments.
Option 1: expose a cspNone()
function.
The Response
object gains a method cpsNonce(): string
which will generate the proper nonce and store it for future use. This is really simple to implement but also not very helpful.
Option 2: add a content security policy object to the response.
We add a member (similar to the headers) to the response object to manage the CSP header and related work. This would be a sort of "out-of-the-box" solution where you declare your CSP in config files and if it contains a nonce option, you add the nonce to the header. This nonce can then be exposed in a similar way as above.
We use middleware to handle CSP and other security related headers at work. I'll see if I can extract the code and create a package or include it in the core.
The middleware could auto-assign a global $_csp_nonce
view variable or replace a configurable token (e.g. @csp_nonce
). It can also support both if that's desirable.
A global view variable would be great; I didn't think of that possibility.
https://gist.github.com/freost/0991a84d119be488367b148e680bdce0
Would something like this be sufficient? I has some sensible defaults and can be extended to add custom directives and headers.
Looks great. We use something similar but it can easily be replaced by this.
The middleware will be available in the 6.3 release. It also supports the new reporting api.