Table of Contents#
-
Understanding CSP and Inline Script Whitelisting
- What is Content Security Policy (CSP)?
- The Risk of Inline Scripts
- How SHA-256 Hashing Works for Whitelisting
-
Common Reasons SHA-256 Whitelisting Fails in Firefox
- Incorrect Hash Generation
- Syntax Errors in CSP Directives
- Case Sensitivity Issues
- Firefox-Specific Whitespace/Encoding Quirks
- Mixed Content or HTTPS Problems
- Browser Version Compatibility
- Inline Event Handlers (onclick, onload, etc.)
-
Step-by-Step Troubleshooting Guide
- Step 1: Verify the CSP Header is Being Sent
- Step 2: Generate the Correct SHA-256 Hash
- Step 3: Validate CSP Directive Syntax
- Step 4: Inspect CSP Violations in Firefox DevTools
- Step 5: Check for Firefox-Specific Quirks
- Step 6: Test with a Minimal Example
- Step 7: Update Firefox and Check Compatibility
-
Advanced Scenarios and Workarounds
- Handling Inline Event Handlers with
unsafe-hashes - Dynamic Inline Scripts and CSP
- Combining Hashes with
strict-dynamic
- Handling Inline Event Handlers with
1. Understanding CSP and Inline Script Whitelisting#
What is Content Security Policy (CSP)?#
CSP is a browser security mechanism enforced via HTTP headers or <meta> tags. It lets website owners define a "whitelist" of trusted sources for resources like scripts, stylesheets, images, and more. By default, CSP blocks risky practices like inline scripts and eval(), unless explicitly allowed.
The Risk of Inline Scripts#
Inline scripts (e.g., <script>console.log('Hi');</script>) are a major XSS vector. Attackers can inject malicious inline code into web pages if input sanitization fails. CSP mitigates this by blocking inline scripts unless explicitly whitelisted.
How SHA-256 Hashing Works for Whitelisting#
Instead of using unsafe-inline (which disables all inline script protections), CSP allows you to whitelist specific inline scripts using their SHA-256 hash. Here’s how it works:
- Compute the SHA-256 hash of the inline script’s exact content (excluding
<script>tags). - Encode the hash in Base64.
- Add the hash to your CSP
script-srcdirective (e.g.,script-src 'sha256-abc123...').
Browsers will only execute the inline script if its hash matches the whitelisted value.
2. Common Reasons SHA-256 Whitelisting Fails in Firefox#
Incorrect Hash Generation#
The most common issue is generating an invalid hash. This happens if:
- You include
<script>tags in the hash (only the script content is hashed). - You forget to exclude trailing newlines (e.g., using
echowithout-nin Linux). - The script content has whitespace (spaces, tabs, newlines) that differs between your source and the browser’s parsing.
Syntax Errors in CSP Directives#
Firefox strictly enforces CSP syntax. Common mistakes include:
- Missing quotes around the hash (e.g.,
sha256-abc123instead of'sha256-abc123'). - Typos (e.g.,
sha256instead ofsha256-prefix). - Conflicting directives (e.g.,
script-src 'self'overriding your hash).
Case Sensitivity Issues#
CSP hashes are case-sensitive. A hash like 'sha256-AbC123' will fail if the browser expects 'sha256-abc123' (or vice versa).
Firefox-Specific Whitespace/Encoding Quirks#
Firefox parses inline scripts more strictly than Chrome in some cases:
- Whitespace: Firefox includes all whitespace (e.g., leading/trailing spaces, tabs) when computing the hash. If your script has a trailing space you forgot to include in the hash, Firefox will block it.
- Encoding: Firefox may handle HTML entities (e.g.,
<for<) or escaped characters differently than Chrome.
Mixed Content or HTTPS Issues#
If your site uses HTTPS but the CSP header is served over HTTP (or vice versa), Firefox may ignore the CSP policy. Always serve CSP over HTTPS.
Browser Version Compatibility#
Older Firefox versions (pre-40) do not support SHA-256 hashing for inline scripts. Ensure users are on Firefox 40+.
Inline Event Handlers (onclick, onload, etc.)#
Inline event handlers like <button onclick="doSomething()"> are treated as inline scripts but require special handling. SHA-256 hashing alone won’t whitelist them unless you also include the unsafe-hashes directive (supported in Firefox 75+).
3. Step-by-Step Troubleshooting Guide#
Step 1: Verify the CSP Header is Being Sent#
First, confirm Firefox is receiving your CSP header.
How to check:
- Open Firefox DevTools (F12) → Network tab → Reload the page → Select the main HTML request → Response Headers → Look for
Content-Security-PolicyorContent-Security-Policy-Report-Only.
If the header is missing, fix your server configuration (e.g., Apache .htaccess, Nginx nginx.conf, or framework-specific CSP middleware).
Step 2: Generate the Correct SHA-256 Hash#
A invalid hash is the #1 culprit. Follow these steps to generate it correctly:
Example Inline Script:#
<script>
console.log('Hello, CSP!');
</script>How to Generate the Hash:#
-
Extract the script content (excluding
<script>tags):
console.log('Hello, CSP!');(note: include all whitespace, like the newline after<script>if present). -
Compute the SHA-256 hash (use
opensslor an online tool):-
Linux/macOS:
echo -n "console.log('Hello, CSP!');" | openssl dgst -sha256 -binary | base64The
-nflag ensuresechodoesn’t add a trailing newline (critical for accuracy). -
Windows (PowerShell):
$scriptContent = "console.log('Hello, CSP!');" $bytes = [System.Text.Encoding]::UTF8.GetBytes($scriptContent) $sha256 = [System.Security.Cryptography.SHA256]::Create() $hashBytes = $sha256.ComputeHash($bytes) [Convert]::ToBase64String($hashBytes) -
Online Tool: Use Report URI’s CSP Hash Generator.
-
Step 3: Validate CSP Directive Syntax#
Ensure your CSP directive is formatted correctly.
Correct Example:
Content-Security-Policy: script-src 'self' 'sha256-abc123def456...';Common Syntax Mistakes:
- Missing quotes around the hash:
sha256-abc123→ Should be'sha256-abc123'. - Extra spaces:
' sha256-abc123 '(spaces inside quotes break the hash). - Using
sha256instead ofsha256-:'sha256abc123'→ Invalid prefix.
Step 4: Inspect CSP Violations in Firefox DevTools#
Firefox’s DevTools will tell you why a script was blocked.
How to check:
- Open DevTools → Console tab. Look for errors like:
Content Security Policy: The page’s settings blocked the loading of a resource at inline ("script-src"). - Click the error to expand details. Firefox often shows the expected hash (the one it computed for your inline script). Compare this to your whitelisted hash—they must match exactly.
Step 5: Check for Firefox-Specific Quirks#
Firefox may differ from Chrome in how it parses inline scripts. Test these scenarios:
- Whitespace: If your script has trailing spaces (e.g.,
console.log('test');), include them in the hash. - Newlines: A script with
console.log('test');\n(newline at end) will have a different hash than one without. - Encoding: If your script uses escaped characters (e.g.,
console.log(\'test\');), ensure the hash is computed on the decoded content (not the escaped version).
Step 6: Test with a Minimal Example#
Isolate the issue with a minimal HTML file:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Security-Policy" content="script-src 'sha256-abc123def456...';">
</head>
<body>
<script>console.log('Minimal test');</script>
</body>
</html>Host this file locally (e.g., with python -m http.server) and test in Firefox. If it works, the issue is likely in your larger codebase (e.g., conflicting directives, dynamic script modification).
Step 7: Update Firefox and Check Compatibility#
Ensure you’re using the latest Firefox version. Older versions may lack support for:
- SHA-256 hashing (Firefox 40+ required).
unsafe-hashes(Firefox 75+ required for inline event handlers).
4. Advanced Scenarios and Workarounds#
Handling Inline Event Handlers with unsafe-hashes#
Inline event handlers (e.g., onclick) require the unsafe-hashes directive in script-src to work with SHA-256 hashing.
Example:
Content-Security-Policy: script-src 'self' 'unsafe-hashes' 'sha256-abc123...';Note: unsafe-hashes weakens CSP slightly, so only use it if absolutely necessary.
Dynamic Inline Scripts and CSP#
If your inline script is dynamically generated (e.g., with server-side variables), ensure the hash is computed on the final rendered content (not the template). For example, a script like <script>var user = "<?= $user ?>";</script> must have a hash based on the rendered value of $user.
Combining Hashes with strict-dynamic#
For complex apps, use strict-dynamic to trust scripts loaded by whitelisted inline scripts. This reduces reliance on hashes for every script:
Content-Security-Policy: script-src 'sha256-abc123...' 'strict-dynamic';5. Conclusion#
Troubleshooting Firefox CSP SHA-256 issues boils down to:
- Generating the correct hash (exact script content, no extra whitespace/newlines).
- Ensuring valid CSP syntax (quotes around hashes, correct prefixes).
- Using Firefox DevTools to inspect violations and compare expected vs. actual hashes.
By following this guide, you’ll resolve most inline script whitelisting issues and secure your site with CSP.