How to Get Started with Your Website Content Security Policy

Share this article

How to Get Started with Your Website Content Security Policy
security padlock

This article is part of a series created in partnership with SiteGround. Thank you for supporting the partners who make SitePoint possible.

The web is based on a “same-origin” policy. Only code at mysite.com can access mysite.com’s data in cookies, localStorage, Ajax requests etc. It is isolated from other domains so any access attempts from evilsite.com will be rejected. Unfortunately, it’s never that simple. Modern websites are complex and load a variety of third-party components, styles and scripts. A script loaded from another domain runs in the context of the current page and can do whatever it likes. That social networking button could monitor visitors, hijack login cookies, change page content and more. Even if you trust the third-party site, you could become victim to a man-in-the-Middle attack where the script is changed before it reaches you. Alternatively, it could permit users to launch their own Cross Site Scripting attacks (XXS). By default, browsers implement an anything-goes approach. Fortunately, it’s possible to apply restrictions using a Content Security Policy (CSP) which prevent unexpected security issues. A CSP tells the browser what’s permitted, e.g. run JavaScript at mysite.com but only from files and not inline <script> tags.

Test Your Website

To check whether CSP is implemented on your site, visit observatory.mozilla.org, enter a page URL and hit Scan Me. Those with no CSP protection are likely to score an F (although various other checks are made). CSP should be considered essential for banks, online stores, social networks and any site which implements user accounts. It’s less necessary if your site doesn’t use third-party scripts, fonts, media, widgets or analytics but can you be sure it never will?

Implementing a Content Security Policy

A Content Security Policy must be added to each page by your developer or web host. It’s defined using a Content-Security-Policy HTTP header set by a server-side language (PHP, Node.js, Ruby etc.) or within the server configuration such as Apache’s .htaccess file, e.g.
# Apply a CSP to all HTML and PHP files
<FilesMatch "\.(html|php)$">
Header set Content-Security-Policy "policy-definition"
</FilesMatch>
(We’ll discuss the “policy-definition” value shortly.)
Server configuration files are practical because they apply the same header to all pages within the sub-folder hierarchy. However, you can also define a policy within the HTML <head> of any page using a meta tag:
<meta http-equiv="Content-Security-Policy" content="policy-definition">
This may be necessary if you don’t have permission to configure the server or require differing policies on each page.

Content Security Policy Definition

Now for the complex part. CSPs define a whitelist of permitted domains and contexts for differing types of content. Presume you only want to permit scripts loaded from your domain. You could use the following CSP (please don’t do this for real yet — it’s just an example!):
script-src 'self';
You then realise you’re also loading a third-party library from a CDN which can appear on various sub-domains of mycdn.com. A domain wildcard is added to the space-separated list:
script-src 'self' *.mycdn.com;
You then remember some of your scripts run inline on the page — we can define that too:
script-src 'self' *.mycdn.com 'unsafe-inline';
We now have a policy for scripts. However, we’ve not defined other types so all stylesheets, images, fonts, etc. would fail to load. To solve this, we can apply a default policy using default-src which serves as a fallback for any undefined type:
default-src 'self'; script-src 'self' *.mycdn.com 'unsafe-inline';
Note that each content type definition is separated with a semi-colon (;). We can now use this policy in our .htaccess file:
Header set Content-Security-Policy "default-src 'self'; script-src 'self' *.mycdn.com 'unsafe-inline';"
or a page meta tag:
<meta http-equiv="Content-Security-Policy" 
content="default-src 'self'; script-src 'self' *.mycdn.com 'unsafe-inline';">

CSP Directive Reference

The full set of CSP directives:
directivedescription
default-src the default fallback policy. Typically set to 'self' or 'none' to ensure all other directives must be declared
style-src valid stylesheet sources
script-src valid JavaScript sources
connect-src valid Ajax, WebSocket or EventSource sources for JavaScript data retrieval
form-action valid sources for form action attributes
img-src valid image sources
font-src valid font sources
media-src valid HTML5 audio and video element sources
object-src valid plugin sources for HTML object, embed and applet elements
plugin-types valid MIME types for plugins invoked by object and embed, e.g. application/pdf
frame-src valid frame and iframe sources (now deprecated — use child-src instead)
child-src valid frame and iframe sources
frame-ancestors valid embedding sources for frame, iframe, object, embed and applet elements
sandbox enables a sandbox for the resource in a similar way to the HTML5 iframe sandbox attribute. This has a number of restrictions unique to this directive: allow-forms, allow-same-origin, allow-scripts, allow-popups, allow-modals, allow-orientation-lock, allow-pointer-lock, allow-presentation, allow-popups-to-escape-sandbox, and allow-top-navigation
report-uri an address where the browser can POST reports of policy failures

CSP Sources Reference

The CSP source directives ending -src support the following values. Any number of space-separated values can be used:
sourcedescription
'none' prevents loading from any source, e.g. frame-ancestors 'none' stops the page showing any iframe or plugin. The value cannot be followed by other sources
'self' allows loading from sources on the same origin (protocol, domain/IP and port)
https: only allows sources on HTTPS connections
data: permits data: sources, e.g. style-src data: allows base64-encoded images in your stylesheets
* wildcard for any URL
*.domain.com permits sources from any sub-domain of domain.com, i.e. www.domain.com, cdn.domain.com, etc.
exact.domain.com permits sources from exact.domain.com
https://exact.domain.com/ permits HTTPS sources on the given domain
'unsafe-inline' permits inline CSS, scripts, javascript: URIs, and element event handlers such as onclick within the HTML
'unsafe-eval' permits unsafe dynamic code using JavaScript’s eval() function
'nonce-id' permits an inline CSS or script to run if the id matches the nonce attribute value, e.g. script-src 'nonce-abc123' runs inline code within a <script nonce="abc123">...</script> block
'sha256-hash' permits styles or scripts if the file content matches the generated SHA-256 hash value

CSP Development Recommendations

It’s practical to start with a strict default policy of default-src 'none'; then add further permissions as required. A good starting point for the majority of websites could be:
default-src 'none'; style-src 'self' data:; img-src 'self' data:; script-src 'self'; connect-src 'self';
This permits styles, images, scripts and Ajax requests from the same origin. Open your page in a web browser then launch the developer tools console. Blocked resource warnings will be reported, e.g.
Refused to load the script 'XXX' because it violates the following Content Security Policy directive: "YYY".
You may need to browse various pages to ensure you’ve accounted for all the fonts, images, videos, scripts, plugins and iframes your site requires.

Google Services

Google provides a great range of services and you’re possibly using analytics, fonts, maps and more. Unfortunately, these are enabled on a range of URIs which require further Ajax calls, inline execution and data schemes. You may end up with a convoluted policy such as:
default-src 'self'; 
style-src 'self' 'unsafe-inline' *.googleapis.com; 
script-src 'self' *.google-analytics.com *.googleapis.com data:; 
connect-src 'self' *.google-analytics.com *.googleapis.com *.gstatic.com data:; 
font-src 'self' *.gstatic.com data:; 
img-src * data:;
(Line breaks have been added for clarity but must not be used in real code.) This cannot be avoided at the time of writing and other third-party vendors will have similar challenges.

Test Again

Finally, re-test your pages again at observatory.mozilla.org and, with luck, your Content Security Policy grade has improved significantly. The tool will also advise about older browsers, HTTPS, CORS, MIME, cookies, referrer and redirection policy headers.

Implementing a Content Security Policy is an important step in the prevention of unexpected security issues. Another important step is the selection of a hosting provider that takes security to heart. Our partner, SiteGround, is a great option for anyone looking for a web hosting platform built for advanced website security.

Frequently Asked Questions (FAQs) about Content Security Policy

What is the role of Content Security Policy in PHP?

Content Security Policy (CSP) plays a crucial role in PHP by providing an added layer of security that helps to detect and mitigate certain types of attacks, including Cross Site Scripting (XSS) and data injection attacks. These attacks are used for everything from data theft to site defacement or distribution of malware. CSP is designed to be fully backward compatible; browsers that don’t support it still work with servers that implement it, and vice-versa: browsers that don’t support CSP simply ignore it, functioning as usual, albeit without the added security benefits.

How do I implement Content Security Policy in PHP?

Implementing CSP in PHP involves adding the appropriate HTTP header to your web page. This can be done using the header() function in PHP. The header should be structured as follows: “Content-Security-Policy: policy”. Replace “policy” with the actual policy directives you want to implement. For example, to only allow scripts from the same origin, your header would look like this: header(“Content-Security-Policy: script-src ‘self'”);

What are some examples of Content Security Policy directives?

CSP provides a wide range of directives that you can use to control resources the user agent is allowed to load for a given page. Some examples include “default-src”, which sets a default policy for loading content such as JavaScript, Images, CSS, Font’s, AJAX requests, Frames, HTML5 Media; “script-src”, which specifies valid sources of JavaScript; and “style-src”, which specifies valid sources of stylesheets.

How can I use Content Security Policy to prevent XSS attacks?

CSP can be used to mitigate XSS attacks by controlling which resources the user agent is allowed to load for a given page. By specifying the origins from which content can be loaded, you can prevent the loading of malicious scripts from unauthorized sources. For example, using the “script-src ‘self'” directive, you can ensure that only scripts from the same origin as the page are executed.

Can I use Content Security Policy with Laravel?

Yes, you can use CSP with Laravel. Laravel provides a middleware where you can add your CSP directives. This middleware can be assigned to a route or a group of routes. When a request is handled by the route or routes, the middleware will add the CSP header to the response.

What are the limitations of Content Security Policy?

While CSP provides a robust mechanism for preventing a wide range of attacks, it is not a silver bullet. It cannot prevent all types of attacks, and it can sometimes be bypassed if not properly implemented. Additionally, it can be complex to implement correctly, especially on large sites or sites that use a lot of third-party content.

How can I test my Content Security Policy?

You can test your CSP using various online tools that check if your policy is correctly implemented and provide suggestions for improvements. Additionally, you can use the browser’s developer tools to see if any resources are being blocked by your policy.

Can I use Content Security Policy in HTML?

Yes, CSP can also be implemented in HTML using the meta tag. However, this is less secure than implementing it via HTTP headers and is generally not recommended.

What is the impact of Content Security Policy on SEO?

CSP itself does not directly impact SEO. However, by improving the security of your site, it can indirectly benefit SEO. A secure site is likely to rank higher in search engine results, and users are more likely to trust and engage with sites that are secure.

How can I handle inline scripts with Content Security Policy?

Handling inline scripts with CSP can be tricky, as they are considered unsafe. However, you can use the ‘unsafe-inline’ keyword to allow them, or better yet, use nonces or hashes to allow specific inline scripts. Note that allowing unsafe inline scripts can open up your site to potential attacks, so it should be done with caution.

Craig BucklerCraig Buckler
View Author

Craig is a freelance UK web consultant who built his first page for IE2.0 in 1995. Since that time he's been advocating standards, accessibility, and best-practice HTML5 techniques. He's created enterprise specifications, websites and online applications for companies and organisations including the UK Parliament, the European Parliament, the Department of Energy & Climate Change, Microsoft, and more. He's written more than 1,000 articles for SitePoint and you can find him @craigbuckler.

browserscontentpolicysecuritysiteground
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week