Security/CSP/Deploying
In this article, we'll recommend steps that can be taken to modify a web site so that it will support CSP base restrictions. We will also explain how to craft a CSP policy for a site that will provide a maximum amount of protection.
Supporting CSP base restrictions
While restricting content loads by source may help mitigate attacks, there are base restrictions needed to properly avoid more complex XSS script injection attacks. Let's take a look at all of the base restrictions employed by CSP and see how equivalent functionality can be obtained through other techniques.
Until a site has been converted to support these base restrictions, the "inline" and "eval" keywords in the script-src directive can be used to disable them. The effort required to support the base restrictions will vary by site, but we'll provide some guidelines on how to convert sites, one restriction at a time.
Removing Inline Scripts
You can skip this part by adding the inline keyword to the script-src directive in your site's CSP policy definition.
Inline scripts are more easily injected into a site than their externally sourced counterparts. This is a side effect of mixing code and content.
<script> tags with text child nodes
- The Problem
- Inline scripting is the most popular vector for XSS, and a site that is vulnerable to any content injection might be coerced into displaying an inline script node. Since CSP rules can't block this (like they can block the script file load from a third party site), it must be disabled.
- General Solution
- To prevent your inline scripts from being blocked, there are two techniques that can be employed.
- Move all the inline scripts into one external script file, then reference the file with a <script src='thefile.js'> tag in the document's head.
- Move each inline script block into an external script file, and reference them individually from script blocks.
The most straightforward conversion technique is (2), but will lead to more HTTP requests being sent. Both techniques will be discussed here.
- Conversion Steps
- If the inline script blocks are context-insensitive (i.e., don't require document.write and just provide some functionality), they can easily be moved into a page-level external file. If they require context, they might need to each be stored in a separate file.
Approach (1): moving scripts into a single external file
- Collect the text content of each script block
- Concatenate the contents into a new file "moved.js"
- Replace the first inline script tag with <script src='moved.js'></script>. Alternatively, this can be placed in the head element of the document.
Approach (2): individual external files
- Generate a unique ID for each script block
- Create a JS file with the script block's contents, named with the given unique ID
- Replace the inline script block with <script src='[unique-id].js'></script>
Approach (1+2): providing context to bits of script
A combination of the two techniques can be used to minimize the number of requests while still providing a bit of context.
- Each inline code block is assigned a unique ID.
- All the code blocks are placed in a single file.
- The file must be loaded at the end of the document, right before the closing body tag.
- Dummy HTML elements are inserted where the inline script blocks were, labeled with the unique IDs. This allows the code to find where it "used to be".
javascript: URIs
- The Problem
- General Solution
- Conversion Steps
Event handling attributes in HTML tags
- The Problem
- There are many HTML event handling attributes (on*) that can contain strings to be evaluated as script.
- General Solution
- Conversion Steps
Removing "eval()"-like features
You can skip this part by adding the eval keyword to the script-src directive in your site's CSP policy definition.
Code generated on the fly can accidentally (or intentionally) contain user-specified content; any strings converted into script code during the run-time of a web application has the potential to be augmented and abused by an attacker. As a result, these must be removed from a site.
eval()
- The Problem
- General Solution
- Conversion Steps
setTimeout()
- The Problem
- General Solution
- Conversion Steps
setInterval()
- The Problem
- General Solution
- Conversion Steps
new Function()
- The Problem
- General Solution
- Conversion Steps
Often Misused Feature Clean up
- data: URIs
- XBL bindings
Writing an effective policy
Example: Media and Object
<video controls="controls" width="320" height="240">
<source src="/media/ogg/bfw-trailer-320x240.ogv" type="video/ogg">
<object type="application/x-java-applet" width="320" height="240">
<param name="archive" value="http://theora.org/cortado.jar">
<param name="code" value="com.fluendo.player.Cortado.class">
<param name="url" value="/media/ogg/bfw-trailer-320x240.ogv">
<param name="autoPlay" value="false">
</object>
</video>
The minimal policy for a page containing only this code:
allow none; media-src self; object-src self http://theora.org;