Content Security Policy Pt II: Gotchas

Jun 24, 2018 · 778 words · 4 minute read content security policy css svg forms

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.

comments powered by Disqus