If you are doing web development, you’ve probably seen the following error message in the debug console:
Refused to load the script 'http://…' because it violates the following Content Security Policy directive.
This is an error that is generated by the browser. The error is because the browser supports Content Security Policy which is designed to reduce harm to users from malicious content injections attacks. Content Security Policy can significantly reduce the risk and impact of cross-site scripting attacks in modern browsers.
What is the Content Security Policy header?
Content Security Policy (CSP), a tool which developers can use to lock down their applications in various ways, mitigating the risk of content injection vulnerabilities such as cross-site scripting, and reducing the privilege with which their applications execute.
- W3C Working Draft, Content Security Policy Level 3
The CSP is an added level of security that helps to identify and mitigate different types of attacks including Cross-Site Scripting (XSS) attack, and data injection attacks. Content injection attacks are very common, 50% of the known Wordpress plugin vulnerabilities are exploited by XSS. The “injection” is usually achieved by finding a way to load external resources to the page.
“Instead of blindly trusting everything that a server delivers, CSP defines the Content-Security-Policy HTTP header, which allows you to create an allowlist of sources of trusted content, and instructs the browser to only execute or render resources from those sources. Even if an attacker can find a hole through which to inject script, the script won't match the allowlist, and therefore won't be executed.”
- Mike West & Joe Medley, Web.dev CSP
The Content Security Policy Header is the mechanism to instruct the browser about which resources and sources of content should be trusted and can be loaded. The Content Security Policy Header allows developers to instruct your web-server to only restrict access to certain sources of scripts. This might include limiting scripts to only those accessed on from your domain, or may include Google Analytics and other services your web applications might be using. Under normal circumstances, the list of whitelisted URLs is very small. You can configure your web server to put a Content Security Policy Header in the response header instructing the browser.
The flexibility of the restrictions is very broad. The CSP can be defined to restrict:
- domains/URLs where images, scripts and other media can be loaded;
- URLs of form actions and submissions;
- and block XSS attacks or plugin execution.
CSP is configurable but instructs the browser to protect the users from harm. You lock down the sources of your content and even a successful XSS attack may not be able to “talk to the mothership”, because access is blocked.
CSP can be configured using a http-eqiv attribute for in the <meta>
tag. This is useful in some situations, but it has limitations and cannot be used for frame-ancestors , report-uri
, or sandbox
. CSP’s preferred delivery mechanism is an HTTP header.
<meta http-equiv="Content-Security-Policy" content="default-src https://cdn.example.net; child-src 'none'; object-src 'none'">
Real World Use Cases
Use Case # 1 - Google Analytics
Different platforms have different requirements. Google Analytics 4 (GA4) gets more complicated if you're also using Google Tag Manager (GTM). GTM requires specific permissions in the CSP to function correctly.
default-src 'self' https://*.google-analytics.com;
script-src 'self' 'unsafe-eval' 'unsafe-inline' https://*.google-analytics.com/ https://tagmanager.google.com/ https://*.googletagmanager.com/;
style-src 'self' 'unsafe-inline' https://pro.fontawesome.com/ https://www.google-analytics.com https://tagmanager.google.com/ https://*.googletagmanager.com/ https://fonts.googleapis.com/;
img-src 'self' 'unsafe-inline' https://*.google-analytics.com https://ssl.gstatic.com/ https://*.analytics.google.com https://*.googletagmanager.com data:;
font-src 'self' 'unsafe-inline' https://pro.fontawesome.com/ https://fonts.gstatic.com/ data:;
connect-src: https://*.google-analytics.com https://*.analytics.google.com https://*.googletagmanager.com https://*.g.doubleclick.net https://*.google.com https://*.google.ca
Use Case # 2 - Lockdown
Assume that you run a health care site or a banking site and only want those resources that you’ve written to be loaded for users. For this scenario, you’d start with a restrictive policy that blocks absolutely everything (default-src ‘none’), and then begin to build from there.
The next steps are to figure out the plan for loading images, scripts, and style. Imagine that the images, scripts and styles are loaded from a CDN at https://cdn.mymedicalapp.net, and connects via XmlHttpRequest (XHR) to https://api.mymedicalapp.com to pull various bits of data. There are no plugins, no fonts, no extras used on the site. The most restrictive CSP that could be used is:
Content-Security-Policy: default-src 'none'; script-src https://cdn.mymedicalapp.net; style-src https://cdn.mymedicalapp.net; img-src https://cdn.mymedicalapp.net; connect-src https://api.mymedicalapp.com; child-src 'self'
Use Case # 3 - SSL connections only
Because CSP can be enabled at the server, it makes a lot of sense for administrators and operators of self hosted web applications like forums, bulletin boards systems and other applications to ensure that all resources only loaded via secure channels. These applications may have a lot of inline script and style that is part of the legacy code.
Content-Security-Policy: default-src https:; script-src https: 'unsafe-inline'; style-src https: 'unsafe-inline'
Even though https: is specified in the default-src, the script and style directives do not automatically inherit the requirement. Each directive must be specified otherwise the default is used.
Configuring CSP at the server?
Configuring CSP as an HTTP header depends on your specific web server, load balancer combination. Ideally, you would put it into the front-line, i.e. the server/load balancer that serves your content. We will show examples for 3 common setups.
The OWASP secure header project has a list of CSP configurations for security https://wiki.owasp.org/index.php/OWASP_Secure_Headers_Project#csp that show different configurations and restrictions that can be useful for your specific web application.
AWS CloudFront
Full instructions to add Security Header for Content Security policy to AWS CloudFront under CloudFront » Policies » Response Headers. Or in your webserver configurations directly.
Nginx
By default, the configuration file is named nginx.conf and is placed in one of the following directories /usr/local/nginx/conf
, /etc/nginx
, or /usr/local/etc/nginx
. Add the following to the nginx server {}
block.
add_header Content-Security-Policy "default-src 'self';
Apache HTTPD
Apache HTTPD server configuration is usually the httpd.conf file often located at /etc/httpd/conf/httpd.conf
but this will depend on your infrastructure.
Add the following configuration changes to httpd.conf:
Header always set Content-Security-Policy "default-src 'self';";
Scan Configuration Files for Security Best Practices
CoGuard is a code scanner for configuration files. CoGuard discovers configurations and configuration files in your IaC code repositories, on your cloud configurations, or in your file system and the containers. CoGuard provides policies that include the identification of the Content Security Policy and other best practices in security. Find out the state of your configurations before you push them to production.
Get started for free today »
Install and run CoGuard locally
pip3 install coguard-cli
cd /your-repository
coguard folder ./
Add it to your Github Workflows
pip3 install coguard-cli
coguard pipeline github add ./your-repository
git commit -a -m “Added coguard to the github pipeline”
git push origin main