CSP Violation Fixes

Most uses of inline scripts that would break when using CSP can be fixed by factoring the javascript out to an external .js file, and making the location of that file a CSP-approved source.

 

Fixing Inline Script Blocks

The code in the inline script block violation example can be fixed by simply moving the <script> block into a .js file and adding the location of that file to the script-src part of the CSP declaration.

If necessary, or during a transition period to fully refactored code, CSP 1.1 allows the use of a script nonce attribute on script blocks that should be allowed.

The previous inline block has simply been moved to a .js file, with no other changes:

Alternately, the script element below uses a nonce value. If that value is matches one provided in the script-src of the CSP header, it will add the current time here: 12:14:22 PM

(The nonce here is hardcoded for demonstration purposes; in proper usage it should be cryptographically random, just as with a session cookie.)

<script nonce='nRfqpuKWNuYyUAFPTr6WVNZk9'>
document.getElementById('example-inline-script-nonce').innerHTML=new Date().toLocaleTimeString();
</script> 

 

Fixing Inline Event Handlers

Inline event handlers can be moved to external js files, and the equivalent code can be programmatically attached to the event handler by wrapping it in an anonymous function.

This button will pop an alert even if inline events are not allowed:
document.getElementById('example-inline-event-handler').onclick = function() {alert('Programmatically attached event handler ran')};

Fixing ‘javascript:’ URIs

These are simply not allowed with any effective CSP settings. If necessary, they can be emulated by setting an onClick event, as in Inline Event Handlers <a> tags.

This link will pop an alert if inline sources are allowed: Try Me

The event handler was attached using an external .js file

document.getElementById('example-javascript-uri').onclick =
   function() {alert('Programmatically attached <a> onclick ran')};

Eval is pretty much nuked by default when using CSP; since it can do anything, it’s not possible to assert that it’s safe. You can allow it by adding 'unsafe-eval' to your sources list, but you should probably consider that a transitional band-aid.

Fixing Eval

If eval is being used to execute arbitrary code, there really isn’t a fix; the entire approach needs to be rethought.

On the other hand, most limited uses of eval should be easy to fix by creating functions with parameters to handle the variations of code that were being passed to eval in normal, expected use.

No example here; just meditate on if eval is really needed (it isn’t).

In particular, using eval() to unpack JSON is a terrible idea. Use a proper JSON parser instead (jQuery provides access to the browser’s own parser via $.parseJSON()).

And, just to top it off… non-eval based code is also going to run faster (possibly much faster if the eval is in a loop).


Fixing setTimeout() and setInterval()

Both versions of these that take existing functions are perfectly fine. Only invocations that take a string and eval it are affected, and just like eval, there’s no direct fix for these if they’re being used for arbitrary code.

More reasonable uses should also be able to be replaced by one or more functions defined in external js files.

The return values here should all be zero if they were prevented from running: [ , , , , ]If the code must access the global scope (such creating var foo in the example), simply explicitly stick it in the window object.

document.getElementById('example-settimeout-value1').innerHTML =
   '' + setTimeout(function() {window['foo0'] = 'bar';}, 1000 * 3600);

Fixing document.write()

Use cases for document.write() are varied, but the most challenging use cases to replace tend to involve ad-hoc creation of lots of tags (DOM elements) via string concatenation. These can generally be replaced by programmatically constructing the DOM elements, using JSON data or HTML5 data-* attributes if the source data should be supplied by the HTML content (context).

This line uses a data attribute and JS DOM element creation instead of document.write():
var parentNode = document.getElementById('example-docwrite');
var contentNode = document.createElement('strong');
contentNode.innerHTML = parentNode.dataset.docwriteExampleText;
parentNode.appendChild(contentNode);

Fixing Inline Style Attributes

Replace inline CSS with either a stylesheet or styling with javascript in an allowed source.

The following text will be blue if styling worked: This font should be blue
document.getElementById('example-inline-style').style = 'color:blue;';

Internal Style Sheet

Internal style blocks can simply be extracted to an external CSS file.

If the style values are dynamic (such as user skins), the css classes can either be modified via javascript (based on whatever criteria are currently used), or factored out to a dynamic CSS file that is generated server-side.

The following text will be blue if styling worked: This font should be blue
<link href='/static/compliant_styles.css' rel='stylesheet'>

External Style Sheet

Without 'unsafe-inline' inline use of the <style> attribute to an external style sheet throws a violation instead of executing

The following text will be blue if CSP is disabled: This font should be blue
<link rel='stylesheet' type='text/css' href='blue.css'><div class='get-blue-2'>This font should be blue</div>

Fixing Image Sources

Make sure all your image sources are on the included in img-src directives in the CSP policy. Here the img tag isn’t changed at all; https://*.google.com is just added to the img-src list.

<img src='https://www.google.com/images/srpr/logo4w.png'>
img-src https://*.google.com

Embedded Image

Embedded images can be allowed by adding data: to the img-src directive, or by factoring out the generator code into a server side script and pointing the image src there.

<img alt='' src='data:image/jpeg;base64,/9j/4AAQSkZJRgABAgAAZABkAAD/2wBDAAEBAQEBAQEBAQECAQEBAgICAQECAgMCAgICAgMEAwMDAwMDBAQEBAUEBAQGBgYGBgYICAgICAkJCQkJCQkJCQn/2wBDAQICAgMDAwUEBAUIBgUGCAkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQn/wAARCAAwADADAREAAhEBAxEB/8QAGQABAQEBAQEAAAAAAAAAAAAAAAgKCQUH/8QAKxAAAAQFAwMDBQEAAAAAAAAAAgMEBQABBgcICRESExQWFRciGSRak9YK/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhEDEQA/ANhEAgEAgEAgEBOV3sw8R8fKlQ0ZfvKW3NkKwc0JTo20pV9bs1NOShtONNILVlJXFUSaMkZpJgAmSDxmIApSnuGewfVbb3OtteSi2a5FobhMd1bd1H3Hj1e027JXxlX9meYlP7dciMNIN6R5Qyx8RT4jCIM9pynKA9yp6npqiaaqGs6zqFDSNH0ihVulV1W6KykDa2NqAoR6pWrVHiAUSSSUAQzDBikEIZTnOcpSgJytvnVhHeStGa29ocxrV3VuJUfcePUFTdwmF8el/ZkGKj+3Qolhp5vSIKGYPiGfEARCntKU5wFUwCAxZ/6NdJfUEzxzctbd7FGwHurbunLVslNvNQ+VU2x9F6Rvz4tOT9B4ckZ4uJCwkXMIJgny2kKc5ClIO/WifjfejEbTHxnx6yFoz2+vBb7zPy+kPUULt2nq1Vuzkl+6bT1KUzqJVJY/gYLbltPYUpykFU51W3rS8mEeY1obbs3kdxLq2ruFTdBU93BCPv3p8YViJCn66owogrqnmhDzMGEAd9xClKU5wGLPRP0T9TjEbU4xnyFyFxn9vrP2+8z8vq/zOlHbtPVqUdm1L9q2uylUZ1FSksHwLFty3nsGU5yDfrAIBAIBAIBAIDizqN6YmXGad7qWulYTVYuNgxR7BSqFgcrS0gU8jbXFySr1ysx3Nm3VG0FdY4pUWSLckQuJIdxzlsEIQF9AjUm/Invh+iqf7iAfQI1JvyJ74foqn+4gKpwn0hc3MXsnLZ30u9rO3Uywt3Q3rPkNgKkKfgsr/wCptKtvI7ia2qnIj7U9QBSDkmH8yw7cZ7CCHfqAQCAQCAQCA//Z' />
img-src data:

Frame restrictions are described in the child-src of the CSP spec:

The child-src directive governs the creation of nested browsing contexts as well as Worker execution contexts.

  • Whenever the user agent fetches a URI (including when following redirects) in the course of one of the following activities, if the URI does not match the allowed frame sources, the user agent must act as if it had received an empty HTTP 400 response and report a violation.
  • Report a violation when requesting data for display in a nested browsing context in the protected resource created by an iframe or a frame element.
  • Navigating such as nested browsing context.

Iframe Example 1

The use of the <iframe> tag with a 'src' to a frame or iframe throws a violation instead of loading the page

example.iana.org should be rendered here:
<iframe src='https://example.iana.org'></iframe>

Iframe Example 2

The use of the <iframe> tag with a 'src' to a frame or iframe throws a violation instead of loading the page

Write the Word ‘Iframe’ here:
<iframe SRC='javascript:document.write('Iframe');'></iframe>

Remote Inline

Fonts can still be sourced from external domains, they just just need to be specified in the font-src directive.

This example uses a font from the Google Font API, so it also uses a style-src directive to allow the @font-face declaration to be loaded.

This should be a non-standard font, sourced from a remote domain.
<link href='https://fonts.googleapis.com/css?family=Chela+One' rel='stylesheet' type='text/css'>
font-src https://themes.googleusercontent.com

XMLHttpRequest

XHR requests are controlled by connect-src; simply include domains you want to allow connections to (* is supported). You’ll need an appropriate Access-Control-Allow-Origin header on the remote side of course.

The response code of an XHR request to Github is here:

var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
    if (xhr.readyState == 4) {
        document.getElementById('example-connect').innerHTML = xhr.status;
    }
}
// Github is a cross-origin early adopter, and don't seem like they'd mind the traffic
xhr.open('GET', 'https://api.github.com', true);
xhr.send(null);
connect-src 'self' https://api.github.com ; 

Remote Object Sources

Valid object src locations should be specified in the object-src part of the policy.

The box below is a demo Flash widget sourced from adobe.com.

<object type="application/x-shockwave-flash"
        data="https://helpx.adobe.com/content/help/en/flash-player/kb/find-version-flash-player/_jcr_content/main-pars/flash_0/file.res/widget.swf"
        width="406" height="140" style="visibility: visible;">
...
</object>
object-src 'self' https://helpx.adobe.com ; 

Embed

CSP 1.1 introduces the concept of plugin-types (not recognized in 1.0), allowing you to specify the MIME type of object and embded tags.

CSP also enforces that the expected MIME type (in the type attribute) matches the actual MIME type from the server header; make sure they agree.

An embedded PDF, sourced from the current domain:
    <embed src="/static/stack_smashing.pdf" type="application/pdf" width="800" height="150"></embed>
    object-src 'self' ;
    plugin-types application/pdf ; 

Start typing and press Enter to search

Shopping Cart