Content Security Policy Pt II: Gotchas
Jun 24, 2018 · 778 words · 4 minute read
My original idea was to blog about Content Security Policy (CSP) and CSS now, after Part I: Javascript, but since everything that applies to Javascript applies to CSS as well, as far as CSP goes, that wouldn’t make for a very interesting read. For those interested you can take the previous blog post, replace script-src
with 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.
default-src
Beside script-src
and style-src
there are a lot of other CSP directives, like font-src
, connect-src
, 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.
For example 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.
Form submission
Another directive that is not covered in default-src
is 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 form-action
directive.
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.
SVG Images
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.
Monitoring problems
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 report-uri
.
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.