8 Ways to Prepare for CSP
Cross-Site Scripting (XSS) is a critical threat that, despite widespread training, still plagues a large number of web sites. Preventing XSS attacks can get complicated but even a small effort can go a long way–a small effort that nevertheless seems to evade us. Still, developers are getting better at input filtering and output escaping which means we are at least headed in the right direction.
Handling input and output aren’t the only strategies available to us. Content Security Policy (CSP) is a HTTP response header that–when correctly implemented–significantly reduces exposure to XSS attacks. CSP is exactly what it’s name implies: a security policy for your web content.
CSP not only allows you to whitelist browser content features on a per-resource basis, but also lets you whitelist those features on a per-host basis. For example, you might tell the browser it can load scripts for a page, but only if they come from a specific directory on your own web server. CSP allows you to set restrictions on scripts, styles, images, XHR, WebSocket, EventSource, fonts, embedded objects, audio, video, and frames.
One powerful feature of CSP is that by default it blocks inline scripts, inline styles, the eval() function, and data: URI schemes–all common XSS vectors. The only problem is that’s where it starts breaking existing code and could be a major obstacle to its widespread adoption. This is an all-too-common problem with frameworks, code libraries, plugins, and open source applications. If you write code that many other people use and don’t start getting it ready for CSP, you kind of hold us all back. CSP does allow you to re-enable blocked features but that defeats the purpose of implementing content security policies.
So getting to my point, here are some things developers can do to their code to at least get ready for CSP:
- Remove inline scripts and styles. Surely you already know that it’s a good practice to separate code from presentation, now’s a good time for us all to stop being lazy and separating our code.
- Ditch the eval() function. Another thing we’ve all known to avoid for quite some time, but it still seems to show up. Most importantly, if you are working with JSON, make sure you parse it instead of eval’ing it. It’s rare to find a situation where there are secure alternatives to eval, you’d might be surprised how creative you can be.
- Don’t rely on data: schemes. Most often used for embedding icons into your code, data: URI’s are a powerful XSS vector. The problem here isn’t using them yourself which normally is safe, it’s that attackers might use them so the best solution is to disable them altogether. On pages that don’t work with user input in any form, you are probably safe to keep data: URI’s enabled.
- Create an organized, isolated directory structure. Scripts with scripts, images with images. Keeping content separate makes fine-grained CSP policies so much easier.
- Document features needed for each file. A good place to document features required for each file is in the source code itself, such as in a PHPDoc comment. By doing this, when you implement CSP you can start with the most restrictive policy and add only necessary features.
- Centralize your HTTP response headers code. A centralized function to send required headers makes it easier to keep track of it all and avoid hard-to-debug errors later.
- Eliminate unnecessary and superfluous scripts. It’s sometimes hard to give up cool features for security, but good discipline here can pay off. This is a business decision based on your threat model, but it’s always a good question to ask when adding new stuff.
- Mention it whenever possible. Yes, you should be that person who talks about CSP; so much that people simply stop inviting you to meetings.
And if you aren’t quite sure about how CSP works, here is some recommended reading: