Content Security Policy (CSP) - Deep Dive¶
Understanding why Airbase enforces strict Content Security Policy
This explanation provides deep understanding of Content Security Policy, why it's critical for government applications, and how it prevents security vulnerabilities.
What is Content Security Policy?¶
Content Security Policy (CSP) is a web security standard that helps prevent Cross-Site Scripting (XSS) attacks by controlling which resources a web page can load and execute.
Simple analogy: CSP is like a bouncer at a club - it checks every piece of JavaScript trying to run and only allows in the ones from trusted sources.
HTTP header example:
What it means: "Only allow JavaScript from the same origin (domain) as the web page itself."
Why Airbase Enforces CSP¶
1. Government Security Requirements¶
Context: Singapore Government applications handle: - Citizen data - Sensitive information - Critical services - Public trust
Requirement: Must meet IM8 (Information Management 8) security standards.
CSP role: Prevents entire categories of attacks that could compromise citizen data.
2. XSS Prevention¶
Cross-Site Scripting (XSS) is one of the most common web vulnerabilities.
How XSS works: 1. Attacker injects malicious JavaScript 2. Victim's browser executes malicious code 3. Attacker steals data, hijacks sessions, or redirects user
Example XSS attack:
<!-- User input not sanitized -->
<div>Welcome, <?php echo $_GET['name']; ?></div>
<!-- Attacker visits: -->
<!-- ?name=<script>steal_cookies()</script> -->
<!-- Browser executes attacker's script -->
CSP protection: Even if malicious script gets into HTML, CSP blocks execution.
3. Defense in Depth¶
Security principle: Multiple layers of protection.
Layers in Airbase: 1. Input validation - Sanitize user input 2. Output encoding - Escape HTML/JS 3. CSP - Block execution even if previous layers fail
CSP is the last line of defense.
Airbase's CSP Policy¶
The Policy¶
What This Means¶
script-src: Controls where JavaScript can load from
'self': Only from the same origin (same domain)
Blocked: - ❌ Inline <script> tags - ❌ Inline event handlers (onclick="...") - ❌ eval() and similar - ❌ javascript: URLs - ❌ External scripts from CDNs
Allowed: - ✅ External .js files from same domain - ✅ Scripts loaded via <script src="/app.js">
Why So Strict?¶
Question: Why not allow inline scripts with nonces or hashes?
Answer: Simplicity and consistency.
'nonce-...' approach: - Requires server-side nonce generation - Different nonce per page load - Complex to implement correctly - Framework-dependent
'self' approach: - Simple rule to understand - Works across all frameworks - No server-side logic needed - Harder to misconfigure
Trade-off: Stricter but simpler and more robust.
How CSP Prevents Attacks¶
Attack Scenario 1: Reflected XSS¶
Without CSP:
-
Attacker crafts malicious URL:
-
Application reflects input in HTML:
-
Browser executes malicious script
- Attack succeeds
With CSP:
1-2. Same as above
- Browser blocks inline script (CSP violation)
- User sees console error, but attack fails
CSP blocks execution even though code is in HTML.
Attack Scenario 2: Stored XSS¶
Without CSP:
-
Attacker posts comment with malicious script:
-
Server stores comment in database
-
Victim visits page, comment loads:
-
Browser executes script, attack succeeds
With CSP:
1-3. Same as above
- CSP blocks inline script execution
- Attack fails
CSP protects all users from stored attacks.
Attack Scenario 3: DOM-Based XSS¶
Without CSP:
-
Application reads URL parameter:
-
Attacker crafts URL:
-
Code injects HTML with inline event handler
- Browser executes
onerrorhandler - Attack succeeds
With CSP:
1-3. Same as above
- CSP blocks inline event handler
- Attack fails
CSP blocks execution from DOM manipulation.
Technical Details¶
How Browsers Enforce CSP¶
1. Server sends CSP header:
2. Browser parses policy
3. For every script: - Check source against policy - If matches: Execute - If doesn't match: Block and log violation
4. Violations logged to console
CSP Violation Reports¶
Browser console:
Refused to execute inline script because it violates the following
Content Security Policy directive: "script-src 'self'".
What this tells developers: - Policy violation occurred - What was blocked (inline script) - Which policy directive blocked it
Developers can fix violations before users are affected.
CSP and the Same-Origin Policy¶
Same-Origin Policy: Browser security feature restricting cross-origin access.
CSP: Additional layer on top of Same-Origin Policy.
Relationship: - Same-Origin Policy: Controls what scripts can access - CSP: Controls what scripts can execute
Both work together for defense in depth.
Common Misconceptions¶
Misconception 1: "CSP Breaks My App"¶
Reality: CSP doesn't break apps, it reveals insecure patterns.
Example:
<!-- This was insecure before CSP -->
<button onclick="handleClick()">Click</button>
<!-- CSP makes the insecurity visible -->
Truth: Inline event handlers were always risky. CSP just enforces secure alternatives.
Misconception 2: "CSP Is Too Restrictive"¶
Reality: CSP script-src 'self' allows all legitimate use cases.
What you CAN still do: - ✅ Load external JS files - ✅ Use modern frameworks (React, Vue, Angular) - ✅ Use build tools (Webpack, Vite) - ✅ Use addEventListener - ✅ Dynamic content
What you CAN'T do: - ❌ Inline scripts (never secure) - ❌ eval() (dangerous) - ❌ Inline event handlers (XSS risk)
All blocked patterns have secure alternatives.
Misconception 3: "I Need to Relax CSP for My Library"¶
Reality: Modern libraries are CSP-compatible.
CSP-compatible libraries: - React, Vue, Angular, Svelte - Express, Next.js, Nuxt - Bootstrap, Tailwind - Chart.js, D3.js
If a library isn't CSP-compatible: - It's likely using insecure patterns - Find an alternative - Or contribute a fix to the library
Exception: Some Python visualization libraries (workaround available).
Misconception 4: "CSP Prevents All XSS"¶
Reality: CSP significantly reduces XSS risk but isn't a complete solution.
CSP prevents: - Inline script execution - eval() exploitation - Inline event handler attacks
CSP doesn't prevent: - Server-side injection - Logic errors in JavaScript - Other vulnerability types (CSRF, SQLi, etc.)
CSP is one layer in defense in depth.
CSP and Modern Frameworks¶
React / Vite¶
Framework approach: Build-time bundling
CSP compatibility: Excellent
How it works: 1. React components compile to JavaScript 2. Vite bundles into external .js files 3. HTML loads bundled files 4. No inline scripts needed
Example:
// src/App.jsx - CSP-compliant
function App() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>
Count: {count}
</button>
);
}
Compiles to external JS, fully CSP-compliant.
Next.js¶
Framework approach: Server-side rendering + bundling
CSP compatibility: Excellent (with configuration)
Configuration needed:
// next.config.js
module.exports = {
compiler: {
removeConsole: false, // Keep for debugging
},
// Don't use `next/script` with inline scripts
}
Avoid:
Use:
Static Sites¶
Approach: Pre-built HTML + external JS
CSP compatibility: Excellent
Pattern:
<!DOCTYPE html>
<html>
<head>
<title>My Site</title>
</head>
<body>
<div id="app"></div>
<!-- ✅ External script -->
<script src="/dist/bundle.js"></script>
</body>
</html>
All build tools (Webpack, Vite, Parcel) generate external JS by default.
The Security Trade-Off¶
What We Gain¶
1. XSS Prevention: - Blocks most XSS attack vectors - Protects user data - Prevents session hijacking
2. Zero-Day Protection: - Even unknown XSS vulnerabilities are mitigated - Attacker can inject code but can't execute it
3. Audit Trail: - Violations logged to console - Easy to identify and fix issues
4. Compliance: - Meets government security standards - Demonstrates security commitment
What We Give Up¶
1. Inline Convenience: - Can't use inline scripts - Must use external files
2. Some Old Patterns: - onclick="..." not allowed - Must use addEventListener
3. Dynamic Script Generation: - Can't use eval() - Can't use new Function() - Must use safe alternatives
Is It Worth It?¶
For government applications: Absolutely.
Consider: - Cost of data breach: Millions of dollars, loss of public trust - Cost of CSP compliance: Few hours of development time
The trade-off heavily favors security.
CSP Evolution¶
CSP Level 1 (2012)¶
Features: - Basic script-src directive - 'unsafe-inline', 'unsafe-eval'
Limitation: All-or-nothing (no granular control)
CSP Level 2 (2016)¶
Features: - Nonces ('nonce-random123') - Hashes ('sha256-...') - 'strict-dynamic'
Improvement: More flexible while maintaining security
CSP Level 3 (Draft)¶
Features: - 'strict-dynamic' improvements - Better error reporting - External hash sources
Status: Being adopted by browsers
Airbase's Choice¶
Policy: CSP Level 1 (script-src 'self')
Rationale: - Universal browser support - Simple to understand - Sufficient for our needs - Easier to audit
Future: May adopt Level 2 features (nonces) if needed.
Global CSP Landscape¶
Industry Adoption¶
Tech companies: - Google: Strict CSP on most services - GitHub: CSP enforced - Twitter: CSP enforced - Facebook: CSP enforced
Government: - UK Government Digital Service: CSP required - US Government (NIST): CSP recommended - Singapore Government (Airbase): CSP enforced
Trend: CSP adoption increasing globally.
Why Not Everyone Uses CSP¶
Challenges: - Legacy code with inline scripts - Third-party widgets - Developer unfamiliarity - Framework incompatibility (old frameworks)
Airbase advantage: Greenfield platform, can enforce from day one.
Best Practices¶
For Developers¶
1. Plan for CSP from the start: - Use external JS files - Avoid inline scripts - Use addEventListener
2. Test with CSP locally:
3. Check console for violations: - Open DevTools (F12) - Check Console tab - Fix all CSP errors
4. Use modern frameworks: - React, Vue, Angular are CSP-friendly - Avoid jQuery plugins with inline scripts
For Teams¶
1. Make CSP compliance a requirement: - Code review checklist - Automated testing - CI/CD gates
2. Educate team members: - CSP training - Share examples - Document patterns
3. Build CSP-compliant component libraries: - Reusable components - Pre-tested for CSP - Team-wide adoption
Future of CSP in Airbase¶
Planned Enhancements¶
1. CSP Reporting API: - Collect violation reports - Analytics dashboard - Proactive issue detection
2. Stricter Policies: - style-src 'self' (CSS) - img-src 'self' data: (images) - connect-src 'self' (API calls)
3. Developer Tools: - CSP testing utilities - Automated violation scanning - Migration helpers
4. Documentation: - More framework examples - Video tutorials - Interactive playground
Feedback Welcome¶
Have CSP issues? - Report via GitHub issues - Share your use case - Suggest improvements
CSP evolves based on developer needs.
Summary¶
CSP (script-src 'self') is non-negotiable on Airbase because:
- Security: Prevents XSS attacks, protects citizen data
- Compliance: Meets government security standards
- Defense in depth: Additional layer beyond input validation
- Modern development: Compatible with all modern frameworks
- Industry standard: Adopted by major tech companies and governments
The cost is minimal: - Use external JS files instead of inline - Use addEventListener instead of inline handlers - Use safe alternatives to eval()
The benefit is massive: - Protection against entire attack categories - User trust - Regulatory compliance - Sleep better at night
Bottom line: CSP makes applications secure by default, which is exactly what government services need.
See Also¶
- Reference: CSP Policy Specification - Authoritative policy details
- How-To: Write CSP-Compliant Code - Practical compliance guide
- How-To: Troubleshoot CSP Violations - Debug CSP errors
- Tutorial: Getting Started - CSP-compliant example
- Explanation: Architecture - How Airbase enforces CSP