Sign in or sign up before continuing. Don't have an account yet? Register now to get started.
Register now

Security: Add Missing HTTP Security Headers (CSP, HSTS, X-Content-Type-Options)

Problem

It was identified that some critical HTTP security headers are missing or not correctly configured in EJ production responses.

Current Status in src/ej/settings/security.py:

Header Status Current Value Impact
X-Frame-Options ✅ Implemented SAMEORIGIN Prevents clickjacking
Content-Security-Policy ❌ MISSING Empty (env("")) Allows XSS attacks
Strict-Transport-Security ❌ MISSING Not defined Allows HTTPS downgrade
X-Content-Type-Options ❌ MISSING Not defined Allows MIME sniffing

Evidence

Production verification:

curl -I https://www.ejplatform.org | grep -E "Content-Security-Policy|Strict-Transport-Security|X-Content-Type-Options"

Result: Headers are missing from all responses (confirmed December 3, 2025).

Test with curl on staging/local:

# Local environment
curl -I http://localhost:8000/ | grep -E "CSP|HSTS|X-Content-Type-Options"

# Staging
curl -I https://staging.ejplatform.org/ | grep -E "CSP|HSTS|X-Content-Type-Options"

Security Impact

This vulnerability exposes EJ to multiple attack vectors:

  1. Cross-Site Scripting (XSS) - CWE-79

    • Severity: High
    • Without CSP, attackers can inject arbitrary JavaScript
    • Related to: Issue #1505 (Stored/Reflected XSS)
    • CVSS: 6.5 (Medium-High)
  2. HTTPS Downgrade / Protocol Fallback - CWE-295

    • Severity: Medium
    • Without HSTS, attackers can downgrade connections to HTTP
    • Can lead to man-in-the-middle attacks
    • CVSS: 5.9 (Medium)
  3. MIME-Sniffing / Content-Type Confusion - CWE-430

    • Severity: Medium
    • Browsers may interpret content differently than intended
    • Can lead to XSS or code injection
    • CVSS: 5.3 (Medium)

Combined CVSS Impact: 5.9 (Medium) - Action Item

Root Cause Analysis

The SecurityConf class in src/ej/settings/security.py uses Boogie Configurations framework, which supports:

  • HTTP_* attributes that are automatically converted to HTTP response headers
  • env() function for environment-based configuration with fallback defaults

Currently:

  • HTTP_CONTENT_SECURITY_POLICY is defined but empty
  • HTTP_STRICT_TRANSPORT_SECURITY is not defined
  • HTTP_X_CONTENT_TYPE_OPTIONS is not defined

Proposed Solution

Add the missing security headers to src/ej/settings/security.py by implementing 3 new configurations:

1. Content-Security-Policy (CSP)

Purpose: Prevent XSS injection attacks by controlling which resources can be loaded

Default Value:

default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self'; frame-ancestors 'none'; base-uri 'self';

Configuration:

HTTP_CONTENT_SECURITY_POLICY = env(
    "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self'; frame-ancestors 'none'; base-uri 'self';",
    name="{attr}",
)

2. Strict-Transport-Security (HSTS)

Purpose: Force HTTPS connections and prevent protocol downgrade attacks

Default Value:

max-age=31536000; includeSubDomains; preload

Configuration:

HTTP_STRICT_TRANSPORT_SECURITY = env(
    "max-age=31536000; includeSubDomains; preload",
    name="{attr}",
)

Explanation of directives:

  • max-age=31536000 - Cache policy for 1 year (31536000 seconds)
  • includeSubDomains - Apply HSTS to all subdomains
  • preload - Enable inclusion in HSTS preload lists (https://hstspreload.org/)

3. X-Content-Type-Options

Purpose: Prevent MIME type sniffing attacks

Default Value:

nosniff

Configuration:

HTTP_X_CONTENT_TYPE_OPTIONS = env(
    "nosniff",
    name="{attr}",
)

Implementation Details

File to modify: src/ej/settings/security.py

Location: Add the 3 configurations within the SecurityConf class, after the existing HTTP_X_FRAME_OPTIONS definition and before the def finalize(self, settings): method.

Mechanism:

  • Boogie Configurations framework automatically converts HTTP_* attributes to HTTP response headers
  • env(default_value, name="{attr}") allows environment variables to override the default
  • Pattern already used for: HTTP_X_FRAME_OPTIONS, HTTP_ACCESS_CONTROL_ALLOW_ORIGIN, etc.

Environment variables for customization:

  • HTTP_CONTENT_SECURITY_POLICY - Override default CSP
  • HTTP_STRICT_TRANSPORT_SECURITY - Override default HSTS
  • HTTP_X_CONTENT_TYPE_OPTIONS - Override default X-Content-Type-Options

Acceptance Criteria

  • Implementation

    • HTTP_CONTENT_SECURITY_POLICY configured in SecurityConf
    • HTTP_STRICT_TRANSPORT_SECURITY configured in SecurityConf
    • HTTP_X_CONTENT_TYPE_OPTIONS configured in SecurityConf
  • Verification

    • Headers returned on all HTTP responses in development
    • Headers returned on production: https://www.ejplatform.org
    • CSP allows all legitimate EJ resources (no console errors)
    • No broken functionality observed
  • Testing

    • Verify with: curl -I https://www.ejplatform.org
    • Test admin panel functionality
    • Test public conversation pages
    • Test API endpoints
  • Documentation

    • Headers documented in security hardening section
    • Configuration options explained in code comments
    • Added to Sprint 5 documentation (GCES)

References and Standards

Security Standards:

  • OWASP Secure Headers Project: https://owasp.org/www-project-secure-headers/
  • OWASP Top 10 2021 - A05:2021 – Security Misconfiguration
  • Mozilla Web Security Guidelines: https://infosec.mozilla.org/guidelines/web_security

Technical References:

  • MDN CSP: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
  • MDN HSTS: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security
  • MDN X-Content-Type-Options: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options
  • HSTS Preload List: https://hstspreload.org/
Assignee Loading
Time tracking Loading