By Oleksii Rudenko October 13, 2015 8:46 PM
Using Content Security Policy to Make Apps More Secure

Content Security Policy is a browser mechanism that helps to prevent cross-site scripting (XSS) attacks.

What is XSS? It’s a kind of attack when an attacker injects some client-side script into a web page in order to get access to the secret data or inject other malicious software. Once the injected script gains the access to the page, it needs to send the data to or somehow communicate with the attacker. The obvious measure to prevent XSS is to prevent injection of malicious client scripts. Nevertheless, it’s often hard to make sure that a website or an app are fully protected against injections. Given that injections are still possible, what else can be done? The answer is CSP. Complementing the measures for preventing injections, CSP helps to ensure that even if a malicious code was injected the stolen data will not be available to the attacker.

The CSP is configured per web page using HTTP headers. Whenever the browser loads an HTML document, the response headers of the HTTP request that delivered the document are used to configure the content security policy for all content that originates from this HTML document.

Most of the browsers understand a special header called Content-Security-Policy and IE10++ understands X-Content-Security-Policy. IE9 and lower does not support CSP.

Configuration

The CSP is configured via a single header (Content-Security-Policy or X-Content-Security-Policy). The value of this header is a string that is effectively a set of directives separated by a semicolon. The directives define a list of sources that are safe to communicate with. There is a directive for each of the resource types such as images, xhr, styles, scripts:

  • child-src governs the nested browsing contexts and the execution of Workers
  • connect-src governs network activities such as XMLHttpRequest::send
  • font-src governs fonts loading
  • form-action governs form submissions
  • frame-ancestors governs embedding of iframes, objects, applets etc
  • img-src governs loading of images
  • media-src governs video and audio sources
  • object-src governs plugins
  • script-src governs scripts execution
  • style-src governs CSS sources
  • etc

This list is not complete. So I suggest reading the full specification for more features. For example, it’s possible to configure an endpoint for reporting CSP violations

Each of the directives that I listed can define one or more sources that are safe to consume. The possible values are:

  • 'none' - empty set of sources, nothing is allowed
  • 'self' - a keyword to indicate the current domain and port
  • 'unsafe-inline' - a keyword to allow execution/communication with inline resources such as inline <script>, <style>
  • 'unsafe-eval' - a keyword that allows eval and similar methods
  • any valid host expression (wild-cards supports) - for example, https://60devs.com

Keywords and host expressions can be combined. For example, script-src 'self' https://google-analytics.com means that scripts loaded from the current domain or https://google-analytics.com are allowed for execution on the page.

The rest of the article are default content security policies generated in a form suitable for using with various software such as web server or frameworks. The configuration was generated by a tool called csp-manager(created for educational purposes).

npm install csp-manager -g
csp-manager init
csp-manager generate nginx

Using CSP with NGINX

Add the following lines to your NGINX location:

add_header Content-Security-Policy "base-uri 'self'; connect-src 'self'; default-src 'self'; font-src 'self'; frame-ancestors 'self'; frame-src 'self'; img-src 'self'; manifest-src 'self'; media-src 'self'; object-src 'self'; script-src 'self'; style-src 'self'"
add_header X-Content-Security-Policy "base-uri 'self'; connect-src 'self'; default-src 'self'; font-src 'self'; frame-ancestors 'self'; frame-src 'self'; img-src 'self'; manifest-src 'self'; media-src 'self'; object-src 'self'; script-src 'self'; style-src 'self'"

Using CSP with Browsersync

Add the following lines to browser sync configuration (gulp):

browserSync.init({
    server: {
        baseDir: "./",
        middleware: function (req, res, next) {
            res.setHeader("Content-Security-Policy", "base-uri 'self'; connect-src 'self'; default-src 'self'; font-src 'self'; frame-ancestors 'self'; frame-src 'self'; img-src 'self'; manifest-src 'self'; media-src 'self'; object-src 'self'; script-src 'self'; style-src 'self'");
            res.setHeader("X-Content-Security-Policy", "base-uri 'self'; connect-src 'self'; default-src 'self'; font-src 'self'; frame-ancestors 'self'; frame-src 'self'; img-src 'self'; manifest-src 'self'; media-src 'self'; object-src 'self'; script-src 'self'; style-src 'self'");
            next();
        }
    }
});

Using CSP with Ember-CLI

Add the following lines to your config/environment.js:

ENV.contentSecurityPolicy = {
  "base-uri": "'self'",
  "connect-src": "'self'",
  "default-src": "'self'",
  "font-src": "'self'",
  "frame-ancestors": "'self'",
  "frame-src": "'self'",
  "img-src": "'self'",
  "manifest-src": "'self'",
  "media-src": "'self'",
  "object-src": "'self'",
  "script-src": "'self'",
  "style-src": "'self'"
};

Using CSP with Apache

Add the following lines to your Apache config:

<IfModule mod_headers.c>
  Header set Content-Security-Policy "base-uri 'self'; connect-src 'self'; default-src 'self'; font-src 'self'; frame-ancestors 'self'; frame-src 'self'; img-src 'self'; manifest-src 'self'; media-src 'self'; object-src 'self'; script-src 'self'; style-src 'self'"
  Header set X-Content-Security-Policy "base-uri 'self'; connect-src 'self'; default-src 'self'; font-src 'self'; frame-ancestors 'self'; frame-src 'self'; img-src 'self'; manifest-src 'self'; media-src 'self'; object-src 'self'; script-src 'self'; style-src 'self'"
</IfModule>

Using CSP with NodeJS

KOAJS

Add the following lines to your KoaJS middleware:

this.set("Content-Security", "base-uri 'self'; connect-src 'self'; default-src 'self'; font-src 'self'; frame-ancestors 'self'; frame-src 'self'; img-src 'self'; manifest-src 'self'; media-src 'self'; object-src 'self'; script-src 'self'; style-src 'self'");
this.set("X-Content-Security-Policy", "base-uri 'self'; connect-src 'self'; default-src 'self'; font-src 'self'; frame-ancestors 'self'; frame-src 'self'; img-src 'self'; manifest-src 'self'; media-src 'self'; object-src 'self'; script-src 'self'; style-src 'self'");

KOAJS with lusca

Add the following lines to your KoaJS app:

app.use(lusca({
  csp: {
    "base-uri": "'self'",
    "connect-src": "'self'",
    "default-src": "'self'",
    "font-src": "'self'",
    "frame-ancestors": "'self'",
    "frame-src": "'self'",
    "img-src": "'self'",
    "manifest-src": "'self'",
    "media-src": "'self'",
    "object-src": "'self'",
    "script-src": "'self'",
    "style-src": "'self'"
  },
}));

Checking CSP

Using Firefox one can check which CSP is effective for the current page. To do this, open the target web page and press Shift + F2 to open Developer Toolbar. Type in security csp, press Enter and you should see something like this:

CSP in FF

In other browsers you need to inspect response headers in order to know the current CSP.

Thanks for reading.