Adopting strict CSP
To make an application compatible with strict CSP it is usually necessary to make some changes to HTML templates and client-side code, add the policy header, and test that everything works properly once the policy is deployed. This page walks you through the common steps.
Code changes
TIP: If you would first like to understand which parts of your application need to be changed to support CSP, review the adoption workflow section below. It guides you through the process of using the CSP Mitigator extension to identify patterns which might need to be refactored, and explains how you can fix them.
Add nonces to <script>
elements
With strict CSP, every <script>
element must have a nonce
attribute
containing a random, unguessable token which matches the value specified in
the policy. The first step is to add these attributes to all scripts:
<script src="/path/to/script.js"></script> <script>foo()</script>
becomes (depending on the template system syntax):
<script nonce="${nonce}" src="/path/to/script.js"></script> <script nonce="${nonce}">foo()</script>
If you use Closure Templates , the template system will add nonce attributes automatically without requiring any changes to your templates if you pass the nonce value as injected data.
In other template systems you will need to modify the templates which include
<script>
tags to add the nonce
attribute and set its value.
Some example code to generate a nonce is included in the FAQ.
Refactor inline event handlers and javascript:
URIs
Inline event handlers (onclick="..."
, onerror="..."
) and <a
href="javascript:...">
links can be used to run scripts, so an attacker who
finds an XSS bug could inject such HTML and execute malicious JavaScript. CSP
requires refactoring those patterns into safer alternatives.
In most cases the changes will be straightforward. To refactor event handlers, rewrite them to be added from a JavaScript block:
<script> function doThings() { ... } </script> <span onclick="doThings();">A thing.</span>
should become:
<span id="things">A thing.</span> <script nonce="${nonce}"> document.addEventListener('DOMContentLoaded', function () { document.getElementById('things') .addEventListener('click', function doThings() { ... }); }); </script>
For javascript:
URIs, you can use a similar pattern:
<a href="javascript:linkClicked()">foo</a>
into
<a id="foo">foo</a> <script nonce="${nonce}"> document.addEventListener('DOMContentLoaded', function () { document.getElementById('foo') .addEventListener('click', linkClicked); }); </script>
Refactor calls to JS APIs incompatible with CSP
In addition to markup changes, some more rare JavaScript patterns may also have to be refactored to make the application CSP-friendly.
-
document.write()
used to load additional scripts:document.write("<script src='/foo.js'></script>");
should be changed to use
document.createElement('script')
, if possible. Alternatively, a nonce should be included in the string passed as an argument todocument.write()
(not recommended):var script = document.createElement('script'); script.src = "/foo.js"; document.head.appendChild(script); // or
var nonce = goog.getScriptNonce(); document.write("<script nonce='" + nonce + "' src='/foo.js'></script>"); -
createElement('script')
used to add inline scripts.In rare cases, new inline scripts are added to the page by creating a new script node and assigning to its
.text
property. If your application does this, you need to make sure to manually pass set thenonce
attribute of the new script:var script = document.createElement('script'); script.text = 'alert(123)'; document.body.appendChild(script);
should be:
var script = document.createElement('script'); script.nonce = goog.getScriptNonce(); script.text = 'alert(123)'; document.body.appendChild(script);
-
Uses of
eval()
.If your application uses
eval()
to convert JSON string serializations into JS objects, you should refactor such instances toJSON.parse()
.If you cannot remove all uses of
eval()
you can still set a CSP policy, but you will have to use the'unsafe-eval'
CSP keyword which will make your policy slightly less secure.
Serve the Content-Security-Policy header
Finally, you need to enable CSP in your application. Many server-side frameworks provide convenience wrappers or configuration which allows you to set an application-wide policy; see for example the Django-CSP-Nonce module.
If your framework doesn't provide such functionality, you need to directly set the response header and manually specify the policy described on the strict CSP page. Due to implementation issues across browsers, it's best to send a CSP header only for Chrome >= 55, Firefox >= 43, and Opera >= 42.
Report-Only mode
Instead of immediately deploying a policy which enforces all CSP restrictions,
you can use the report-only mode which will not affect the behavior of your
application, but will still generate violation reports
when patterns incompatible with CSP are encountered, and send them to a
reporting endpoint
defined in your policy. To use CSP in this mode, you should serve the policy in
the Content-Security-Policy-Report-Only
header.
Testing and deployment
Adoption workflow
The CSP Mitigator Chrome extension is a tool for identifying the parts of an application which have to be changed to support CSP. As you interact with your app it generates a report with all patterns described in the code changes section above.
We recommend adopting CSP using the following workflow:
- Install the CSP Mitigator extension.
- Click the "M" symbol in the Chrome toolbar and set the path to the root of
your application (e.g.
https://www.example.org/application/
). The default policy of the CSP Mitigator is a good, secure starting point. - Click the "Start" button.
- Interact with your application to exercise as much functionality as possible.
- When you’re done, click the "M" icon again and click "Stop" - you will see a report listing any patterns incompatible with CSP.
- Refactor your application as outlined in the report.
- After you make changes, repeat testing in the CSP Mitigator to see what issues remain. Once you've addressed all the reported issues, your application will support CSP!
Deploying to production
If local testing doesn't show any CSP violations you are likely ready to
apply the policy in production -- either in Report-Only
mode, or by gradually
rolling out an enforcing policy.
A few final things to keep in mind:
-
If your product works with a testing team, it might be worth letting them know about the CSP deployment and ask them to keep an eye out for any CSP warning messages in the browser console.
-
To see violations reported by users' browsers, review the reports sent to the collection URL configured in the
report-uri
directive.