Mozilla's MDN describes Content Security Policy (CSP) as:
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, to malware distribution.
Setting up CSP headers provides great security benefits but can be difficult to deploy and monitor. A common problem is accidentally blocking the assets you need. This issues include:
To demonstrate setting up CSP, let's review how GlitchTip itself deploys and monitors CSP headers. First, we need a baseline metric we can measure against. I like Mozilla Observatory for this as it provides an easy to read list of good practices and a business team ready letter grade. GlitchTip receives an A+ rating. Note that while GlitchTip is built with Django, CSP headers are a web standard that can be applied regardless of the server technology used.
The first step is to decide how to set the headers. The Django web framework can utilize django-csp. We can find GlitchTip's pyproject.toml referencing this. Another popular library for JavaScript projects is helmet. Alternatively, headers can be set manually. Here's an example with express:
res.set("Content-Security-Policy", "default-src 'self'");
CSP is set in GlitchTip with django-csp. GlitchTip uses django-environ so that the default policy can be overwritten with environment variables. This is important as we may need to make quick changes to production without a code deployment.
CSP_DEFAULT_SRC = env.list("CSP_DEFAULT_SRC", str, ["'self'"])
When first deploying CSP, it's usually a good idea to enable reporting only. This will not block any asset requests, but will only report them when a reporting uri is set. Here's another example with django-csp.
CSP_REPORT_URI = env.tuple("CSP_REPORT_URI", str, None)
CSP_REPORT_ONLY = env.bool("CSP_REPORT_ONLY", False)
GlitchTip can monitor these CSP violation reports. First create a GlitchTip project, if you haven't already done so. It's up to you if you want to reuse a project with other reports or make a new one only for CSP. Next get your "Security Endpoint" from project settings.
This is the URI to set the "report-uri". It looks something like this Content-Security-Policy: default-src 'self'; report-uri https://0000000@app.glitchtip.com/1
. In fact, if you go to https://app.glitchtip.com you should see this header set with a report-uri.
To test, ensure you have an asset that will be blocked by CSP. For example, if you use Plausible Analytics you can leave https://plausible.io
out of your CSP policy header. If the Content-Security-Policy-Report-Only header is set, the script should still be allowed to run but will send a report to GlitchTip. The report will show in Issues. Here's an example of blocking an image from facebook.com.
Now we have a test CSP policy, are able to quickly make changes via environment variables, and receive reports of violations. Violation reports will need monitored for a period of time. You may find violations from web extensions that should be ignored (consider marking them Ignore in GlitchTip). Once you are confident that your policy is correct, change the header Content-Security-Policy-Report-Only to Content-Security-Policy. In django-csp that would mean setting CSP_REPORT_ONLY
to False
.
Once deployed, it's best to use Mozilla Observatory again to ensure CSP is enabled correctly and make further recommendations for improvement. Remember that a less than ideal CSP is better than none at all. It may take time to analyze and remove unsafe inlines, evals, and excessive third party scripts. As you adjust the policy and your website, GlitchTip will continue monitoring for problems.
If this blog post or GlitchTip have helped you out, please consider a donation and star GlitchTip on social sites like GitLab and AlternativeTo. GlitchTip is a fully open source application monitoring platform that's made to be as easy as possible to self host or used as a hosted application. Mozilla also accepts donations and has many great resources like MDN and Observatory.