style-src, remove the paragraph about
unsafe-eval since CSS doesn’t have that, and that’s all there is to it.
So instead I decided I will tell you about some gotchas that I encountered in the wild with CSP.
style-src there are a lot of other CSP directives, like
frame-src and others. Instead of defining them all you can also use
default-src as a fallback for any directive that isn’t defined in your CSP.
This works fine, but there are some CSP directives that do not honor
default-src, and that’s not clear from the get-go, since the name would suggest it to be the default for all CSP directives.
base-uri, which determines the URLs allowed in the
<base> tag in your HTML does not ue the value from
default-src when omitted from your CSP. So if someone finds an XSS vulnerability in your site they could inject a
<base> tag causing all relative URLs on your site to resolve to their malicious site.
Therefore, never assume that having a good
default-src will cover all your bases, because that will still leave some parts wide open.
Another directive that is not covered in
form-action, which dictates the domains thay may be used in form
action attributes. This is a good idea to set to the current domain to prevent posting to malicious site in case you’re site has been comprimised in an XSS attack.
So I set the value to
self to only allow form POST to the current domain. The problem was however that after posting the data, the user would get redirected to a different domain (as part of an OAuth authentication), and several browsers will actually prevent that from happening if the domain that is redirected to is not in the
The reasoning behind this is that there exists an HTTP code 308 which will redirect POST requests to a different URL, meaning if your server is compromised it could redirect POST requests in its entirety to a malicious website even though a CSP is in place. So browsers prevent that from happening by disallowing any redirect after a POST request, which is odd in my opinion since 301 and 302 will not redirect POST requests, but transform them to GET requests instead, so the attack won’t work in that case.
So if you ever have a form that when submitted redirects to a different domain, the domain that is redirected to must be in the
form-action directive of your CSP as well.
This may seem like an odd one, but from a purely technical standpoint it makes sense. Suppose you have an SVG image like this:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <rect x="10" y="10" height="100" width="100" style="fill: #ff0000"/> </svg>
If your CSP for
style-src doesn’t allow
unsafe-inline the image will be rendered, but in Microsoft Edge instead of the color red defined in the
style attribute, the rectangle will be black, because the CSP will prevent the style from being applied. Other browsers are more linient towards SVG and don’t have this problem, but Edge does. In order to get around this you have to remove the inline style and change it to attributes instead, like so:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <rect x="10" y="10" height="100" width="100" fill="#ff0000"/> </svg>
That will work in Edge. I’ve also found a blog post saying you should send a different CSP header with the SVG image itself allowing
unsafe-inline, but that didn’t work for me.
Once you have a CSP in place in production, it’s a good idea to keep track of any violations of said CSP to avoid sub-optimal experiences for your users. CSP provides the
report-uri directive for this. When this directive is supplied and a browser encounters a problem with your CSP it will send a report to the URL supplied in
However, the reports are not really that easy to read on their own, and an aggregation of the information would be useful. What I’ve found to be very useful is report-uri.com. They have nice dashboards with a clear overview of what’s going on with your CSP, filter out known browser bugs so you don’t have to care about that, and if you have up to 10,000 reports a month it’s free of charge as well.