Content Security Policy (CSP) Implementation
Overview
This site implements Content Security Policy (CSP) to protect against XSS attacks, data injection, and other common web vulnerabilities.
Implementation
The CSP is implemented via a <meta> tag in _includes/csp.html and included in the default layout. GitHub Pages doesn’t support custom HTTP headers, so the meta tag approach is used.
Policy Details
Current CSP Configuration
default-src 'self'
Only allow resources from the same origin by default.
script-src 'self' 'unsafe-inline' https://www.clarity.ms https://scripts.clarity.ms https://*.clarity.ms https://*.disqus.com https://*.disquscdn.com
'self': Allow scripts from same origin (simple-jekyll-search.min.js, cookie-consent.js, search-init.js)https://www.clarity.ms,https://scripts.clarity.ms,https://*.clarity.ms: Microsoft Clarity analyticshttps://*.disqus.comandhttps://*.disquscdn.com: Disqus comments (if enabled)- No
'unsafe-inline': All inline scripts have been refactored into external files for maximum XSS protection
style-src 'self' 'unsafe-inline' https://fonts.googleapis.com
'self': Allow stylesheets from same origin'unsafe-inline': Required for inline styles in cookie consent and other componentshttps://fonts.googleapis.com: Google Fonts stylesheet
img-src 'self' data: https://www.jfokus.se
Allow images from:
'self': Same origin (blog post images, avatars, logos)data:: Data URIs for inline imageshttps://www.jfokus.se: JFocus conference speaker images
font-src 'self' data: https://fonts.gstatic.com
Allow fonts from same origin, data URIs, and Google Fonts CDN.
connect-src 'self' https://www.clarity.ms https://*.clarity.ms https://*.disqus.com
Allow AJAX/fetch requests to same origin, Clarity analytics, and Disqus.
frame-src https://*.disqus.com
Allow embedding of Disqus comment iframes.
object-src 'none'
Disallow plugins like Flash and Java applets.
base-uri 'self'
Restrict <base> tag to same origin.
form-action 'self'
Forms can only submit to same origin.
upgrade-insecure-requests
Automatically upgrade HTTP requests to HTTPS.
Note: The frame-ancestors directive is not supported in <meta> CSP tags, only in HTTP headers. For meta-based CSP, this directive is ignored.
Eliminating Inline Scripts (XSS Protection)
To maximize XSS protection, all inline JavaScript has been refactored into external files:
Refactored Scripts
| Inline Script | External File | Location |
|---|---|---|
| Clarity analytics initialization | assets/clarity-init.js |
Loaded by _includes/analytics_head.html |
| Cookie consent handler | assets/cookie-consent.js |
Loaded by _includes/cookie-consent.html |
| Search initialization | assets/search-init.js |
Loaded by _pages/search.md |
Benefits of External Scripts
- Blocks inline script injections: Attackers cannot inject inline
<script>tags to execute malicious code - Maintains CSP without
'unsafe-inline': All scripts follow proper CSP directives - Uses DOMContentLoaded event: Scripts initialize safely after DOM is ready
- High ROI security improvement: Eliminates an entire class of XSS attacks
Implementation Details
- Scripts use
document.addEventListener('DOMContentLoaded', ...)to initialize after the page loads - Event listeners are attached using
.addEventListener()instead of inlineonclickattributes - All script-src directives now point to whitelisted external origins only
Styling: Still Uses ‘unsafe-inline’
Note: style-src still includes 'unsafe-inline' for the cookie consent banner styling. CSS injection attacks are significantly less common than JavaScript injection, but this could be further hardened using external stylesheets or CSS-in-JS solutions.
Testing CSP
- Open browser Developer Tools (F12)
- Navigate to Console tab
- Look for CSP violation warnings
- Test all site functionality (search, cookie consent, analytics)
Monitoring
- Check browser console for CSP violations
- Consider using CSP reporting (
report-uriorreport-todirectives) to collect violation reports
Maintenance
When adding new external services, update _includes/csp.html accordingly. Avoid adding inline scripts; create external files instead.
