Content Security Policy (CSP) is 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.
- MDN

Blogthedata.com now has a Content Security Policy and an A+ rating on Mozilla Observatory. The journey began early this month when I got an F on Observatory’s security audit. Since then, I’ve beefed up security, including creating an SRI and a CSP. W3C published the latest CSP standard on June 29th, 2021.

In Django, we implement a CSP using the django-csp module. After installation, you add CSP directives to your settings.py file.

# settings.py
# Content Security Policy
CSP_DEFAULT_SRC = ("'none'",)
CSP_STYLE_SRC = ("'self'", "https://cdn.jsdelivr.net", "'unsafe-inline'")
CSP_SCRIPT_SRC = (
	"'self'",
	"https://cdn.jsdelivr.net",
)
CSP_IMG_SRC = ("'self'", "data:")
CSP_FONT_SRC = ("'self'",)
CSP_CONNECT_SRC = ("'self'",)
CSP_FRAME_SRC = ("*",)
CSP_FRAME_ANCESTORS = ("'none'",)
CSP_BASE_URI = ("'none'",)
CSP_FORM_ACTION = ("'self'", "https://blogthedata.us14.list-manage.com")
CSP_OBJECT_SRC = ("'none'",)

CSP_DEFAULT_SRC - The master directive. With a value of ‘none’ it’s saying ‘block everything unless it’s specifically allowed,’ It’s a good security practice because an allow list won’t block items you might have forgotten. Block everything by default and then selectively allow what you need.

CSP_STYLE_SRC - This tells Django where CSS may come from. In my case, I am allowing styles hosted on my server (self) and Bootstrap CSS, served through jsdeliver. I needed to include ‘unsafe-inline’ because a few plugins I use have inline styles. There’s an open issue to resolve this one.

CSP_SCRIPT_SRC - Same as STYLE_SRC, but this concerns what’s inside a <script> tag.

CSP_IMG_SRC - I host site images locally, so I don’t need to allow external sites like Imgur. The downside to this directive is that it prevents me from having any images on my site hosted on another domain. I also added data: to allow CKEditor’s drag/drop image support, which embeds the image as a base44 encoded string. I could opt for regular image uploads only, but I kept this in for convenience.

CSP_FONT_SRC - Where fonts can come from.

CSP_CONNECT_SRC - Restricts URLs that load using script interfaces such as WebSocket and XMLHttpRequests.

CSP_FRAME_SRC - I used  ‘ * ‘ to wildcard all domains in a child iframe. I am not restricting myself from putting something inside <iframe> when the iframe lives on blogthedata.com. This contrasts with SRC_FRAME_ANCESTORS, which dictates which domains can put blogthedata.com into an iframe.

CSP_BASE_URI - The <base> tag specifies the target of relative URLs in a site.

CSP_FORM_ACTION - Where <form> can submit. Most of my forms POST to routes within my application, except the Mailchimp newsletter sign-up which uses .us14.list-manage.com

CSP_OBJECT_SRC - Limts what sources for <object>, <embed>, and <applet> tags.

My Approach and Gotchas Encountered 

I first set CSP_DEFAULT_SRC to ‘none’ (block everything) and began visiting pages and running unit tests. My first issue was that CKEditor 4 bundles inline CSS with JavaScript in the ckeditor.js file. CSP policies restrict inline <style> and <script> tags. CKEditor improved CSP support in version 5, so I decided to migrate. You can read more about it in this blog post.

Social Share embedded Scripts and Styles

Most social share buttons provided by companies such as LinkedIn and Twitter have embedded scripts and styles. I worked my way around that and wrote on it in this post.

Kofi Donate Button and Mailchimp Embed Form had inline styles and scripts

I had to reverse engineer HTML templates, so Kofi and Mailchimp did not violate the CSP. This involved hosting the JavaScript locally and moving inline styles into a separate CSS file. The changes are in this PR.

Broken styling on the sitemap page

Another interesting issue I ran into was that I broke inline styles on the sitemap page. I don’t think it’s a problem because this page doesn’t need styling. The only reason I have a sitemap page is for site spiders to understand my site better. I came across this Reddit thread that confirmed my thoughts. CSPs are for protecting users on your site, not robots.

Conclusion

Implementing a CSP added XSS protection to blogthedata.com besides increasing the site’s score on Mozilla Observatory. I ran into many setbacks, but they were surmounted. Consider adding a CSP to your site to make it more secure.

Comments

Back to Home
John Solly Profile Picture
John Solly Profile Picture

John Solly

Hi, I'm John, a Software Engineer with a decade of experience building, deploying, and maintaining cloud-native geospatial solutions. I currently serve as a senior software engineer at New Light Technologies (NLT), where I work on a variety of infrastructure and application development projects.

Throughout my career, I've built applications on platforms like Esri and Mapbox while also leveraging open-source GIS technologies such as OpenLayers, GeoServer, and GDAL. This blog is where I share useful articles with the GeoDev community. Check out my portfolio to see my latest work!