Tackle Cross Site Scripting using Content Security Policy

Tackle Cross Site Scripting using Content Security Policy

Cross site scripting (XSS) is identified as one of the main threats to web users by the OWASP Foundation.

XSS occurs when a malicious third party injects a script into content served by your website. Sites that serve user-supplied content to the browser without validating or escaping that content are vulnerable to XSS.

For example, take a site that allows users to search for a term and returns their query alongside the result, e.g. 'You searched for cats'. If the site doesn't escape or validate the query 'cats' then it could be possible to insert a link after the query in the URL, for instance to a malicious JavaScript script hosted on another domain.

Other users could then be sent the malicious URL alongside a message saying 'Look at these cute cats' and, if they clicked on the link, the script would execute in their browser. This is an example of what is called a reflected attack, where data is read directly from the HTTP request and reflected back in the HTTP response.

Another common XSS attack method is the stored attack, where the link to the malicious script is uploaded to your site's database and served back to subsequent visitors. An example might be where a forum user includes such a link in their user profile.

There are various ways to guard against XSS attacks, escaping all untrusted data, creating a whitelist to validate inputs and using an auto-santisation library such as OWASP's AntiSamy.

Another way to help protect your site from XSS is to restrict the web domains where scripts can be served from, as is made possible by Content Security Policy (CSP) headers.

CSP headers allow the server to instruct the browser to only accept content served from specific domains, e.g. safedomain.com.

The 'Content-Security-Policy' header can restrict the source of all content served, or just specific content types, such as images, media and scripts.

Such restrictions are set using the CSP policy directives, which specify the domains to use. For example to specify that all content should be served from the site's domain you would set the CSP header like so.

Content-Security-Policy: default-src 'self'

To permit images to be served from any domain but to restrict the source of all other content to the site's domain.

Content-Security-Policy: default-src 'self'; img-src *

If you wanted to alter the restriction above to also allow media to be served from the media1.com and media2.com domains.

Content-Security-Policy: default-src 'self'; img-src *; media-src media1.com media2.com

As you can see, each new domain is separated by whitespace and each new policy directive is separated using a semi-colon.

To broaden the permissions to allow scripts to be served from a trusted server.

Content-Security-Policy: default-src 'self'; img-src *; media-src media1.com media2.com; script-src goodscripts.example.com

There are many different policy directives, such as style-src for specifying sources of stylesheets, font-src for sources of fonts and object-src for sources of plug-ins. A full list of directives can be found here.

To approve sub-domains as a content source you use the * symbol, for instance to approve subdomains of mysite.com.

Content-Security-Policy: default-src 'self' http://*.mysite.com

To implement a CSP without breaking your site you can test the restrictions using the Content-Security-Policy-Report-Only header. This header tells the browser not to enforce the restrictions on where to serve content from, but to report any violations to the specified URI, e.g.

Content-Security-Policy-Report-Only: default-src 'self'; report-uri: /mysite_csp_report;

To stop inline scripts from running and prevent the use of JavaScript's eval() function the default-src or script-src policy directive should be used.

All recent versions of major browsers support the use of the Content Security Policy header, except Internet Explorer. Internet Explorer 10+ supports the X-Content-Security-Policy header, which partially implements CSP. Browsers that don't support CSP won't throw up problems, they'll simply ignore it.