In this post, we are going to explore and understand how you can prevent someone from executing a malicious code on your website.

Cross-site scripting – the ability to inject attacker-controlled scripts into the context of a web application – is arguably the most notorious web vulnerability.

Today, Content Security Policy (CSP) is one of the most promising countermeasures against XSS on modern browsers. CSP is a declarative policy mechanism that allows web application developers to define which client-side resources can be loaded and executed by the browser. By disallowing inline scripts and allowing only trusted domains as a source of external scripts, CSP aims to restrict a site’s capability to execute malicious client-side code. Hence, even when an attacker is capable of finding an XSS vulnerability, CSP aims to keep the application safe by preventing the exploitation of the bug – the attacker should not be capable of loading malicious code without controlling a trusted host.

To enable CSP, you need to configure your web server to return the Content-Security-Policy HTTP header.

Syntax

Content-Security-Policy: <policy-directive>; <policy-directive>

where <policy-directive> consists of: <directive> <value> with no internal punctuation.

Alternatively, the <meta> element can be used to configure a policy, for example:

<meta http-equiv="Content-Security-Policy"
      content="default-src 'self'; img-src https://*; child-src 'none';">

Directives

  • Fetch directives – controls the locations from which certain resource types may be loaded. e.g. default-src, font-src, frame-src, img-src, manifest-src, media-src, object-src, prefetch-src, srcipt-src, style-src, child-src, connect-src, worker-src, etc.

  • Document directives – governs the properties of a document or worker environment to which a policy applies. e.g. base-uri and sandbox.

  • Navigation directives – Directives that govern to which locations a user can navigate or submit a form, e.g. form-action, frame-ancestors.

  • Reporting directives – directives that control the reporting process of CSP violations. See also the Content-Security-Policy-Report-Only header. e.g. report-uri and report-to.

Values

  • Keywords - none, self, unsafe-inline, unsafe-eval, unsafe-hashes.
  • Hosts Values
    • Host: example.com, *.example.com, https://*.xyz.com/path/file.js
    • Scheme: http:, data:
  • Other Valuesnonce-*, sha*-*

Examples: Common use cases

  1. Disable unsafe inline/eval, only allow loading of resources (images, fonts, scripts, etc.) over https:
Content-Security-Policy: default-src https:
  1. Pre-existing site that uses too much inline code to fix but wants to ensure resources are loaded only over HTTPS and to disable plugins:
Content-Security-Policy: default-src https: 'unsafe-eval' 'unsafe-inline'; object-src 'none'
  1. Do not implement the above policy yet; instead just report violations that would have occurred:
Content-Security-Policy-Report-Only: default-src https:; report-uri /csp-violation-report-endpoint/

Sample violation report

Let’s consider a page located at http://example.com/signup.html. It uses the following policy, disallowing everything but stylesheets from cdn.example.com.

Content-Security-Policy-Report-Only: default-src 'none'; style-src cdn.example.com; report-uri /_/csp-reports

The HTML of signup.html looks like this:

<!DOCTYPE html>
<html>
  <head>
    <title>Sign Up</title>
    <link rel="stylesheet" href="css/style.css">
  </head>
  <body>
    ... Content ...
  </body>
</html>

Can you spot the violation? Stylesheets are only allowed to be loaded from cdn.example.com, yet the website tries to load one from its own origin (http://example.com). A browser capable of enforcing CSP will send the following violation report as a POST request to http://example.com/_/csp-reports, when the document is visited:

{
  "csp-report": {
    "document-uri": "http://example.com/signup.html",
    "referrer": "",
    "blocked-uri": "http://example.com/css/style.css",
    "violated-directive": "style-src cdn.example.com",
    "original-policy": "default-src 'none'; style-src cdn.example.com; report-uri /_/csp-reports",
    "disposition": "report"
  }
}

Allowlist CSP vs Strict CSP

A CSP based on nonces or hashes is often called a strict CSP (added in CSP 2). When an application uses a strict CSP, attackers who find HTML injection flaws will generally not be able to use them to force the browser to execute malicious scripts in the context of the vulnerable document. This is because strict CSP only permits hashed scripts or scripts with the correct nonce value generated on the server, so attackers cannot execute the script without knowing the correct nonce for a given response.

Implementation Notes

  • Aiming for default-src https: is a great first goal, as it disables inline code and requires https.
  • For existing websites with large codebases that would require too much work to disable inline scripts, default-src https: 'unsafe-inline' is still helpful, as it keeps resources from being accidentally loaded over http. However, it does not provide any XSS protection.
  • It is recommended to start with a reasonably locked down policy such as default-src 'none'; img-src 'self'; script-src 'self'; style-src 'self' and then add in sources as revealed during testing.
  • In lieu of the preferred HTTP header, pages can instead include a <meta http-equiv=Content-Security-Policycontent=> tag. If they do, it should be the first <meta> tag that appears inside <head>.
  • Care needs to be taken with data: URIs, as these are unsafe inside script-src and object-src (or inherited from default-src).
  • Similarly, the use of script-src 'self' can be unsafe for sites with JSONP endpoints. These sites should use a script-src that includes the path to their JavaScript source folder(s).
  • Unless sites need the ability to execute plugins such as Flash or Silverlight, they should disable their execution with object-src 'none'.
  • Sites should ideally use the report-uri directive, which POSTs JSON reports about CSP violations that do occur. This allows CSP violations to be caught and repaired quickly.
  • Prior to implementation, it is recommended to use the Content-Security-Policy-Report-Only HTTP header, to see if any violations would have occurred with that policy.

Summary

In this post, we looked at what is CSP, how it plays an important role in securing modern web applications against injection of malicious code, and different implementation strategies.

At Fueled, we are always excited to work with folks interested in web security, and we are also hiring! You can also reach out to me on twitter – @_theskumar.

Futher Reading:

Discuss on Twitter

Related articles: