Files
MyClub/SECURITY_HEADERS_FIX.md
T
Tomas Dvorak 77213f4e83 dev day #65
2025-10-19 17:16:57 +02:00

4.8 KiB

Security Headers Fix for PDF and File Previews

Problem

PDF previews and embedded content were failing with the error:

Refused to display 'http://localhost:8080/' in a frame because it set 'X-Frame-Options' to 'deny'.

This was preventing:

  • PDF file previews in iframes
  • Document previews
  • Any embedded same-origin content

Root Cause

The security headers were set too restrictively:

  • X-Frame-Options: DENY - Completely blocked all framing
  • Content-Security-Policy with frame-ancestors 'none' - Also blocked framing in CSP

Solution Applied

Changes Made

1. main.go (Line 109)

- c.Writer.Header().Set("X-Frame-Options", "DENY")
+ c.Writer.Header().Set("X-Frame-Options", "SAMEORIGIN")

2. internal/middleware/security_headers.go (Line 15)

- c.Header("X-Frame-Options", "DENY")
+ c.Header("X-Frame-Options", "SAMEORIGIN")

3. internal/middleware/security_headers.go (Lines 59, 74)

Production CSP:
- "frame-ancestors 'none';"
+ "frame-ancestors 'self';"

Development CSP:
- "frame-ancestors 'none';"
+ "frame-ancestors 'self';"

4. internal/config/config.go (Line 110)

- ContentSecurityPolicy: getEnv("CONTENT_SECURITY_POLICY", "default-src 'self' data: blob: https: http:; img-src * data: blob:; style-src 'self' 'unsafe-inline' https: http:; script-src 'self' 'unsafe-inline' 'unsafe-eval' https: http:; connect-src *;"),
+ ContentSecurityPolicy: getEnv("CONTENT_SECURITY_POLICY", "default-src 'self' data: blob: https: http:; img-src * data: blob:; style-src 'self' 'unsafe-inline' https: http:; script-src 'self' 'unsafe-inline' 'unsafe-eval' https: http:; connect-src *; frame-ancestors 'self';"),

Security Impact

What's Still Protected:

  • Clickjacking from external sites: Only same-origin framing is allowed
  • XSS attacks: CSP and other headers remain in place
  • MIME sniffing: X-Content-Type-Options still set
  • HTTPS enforcement: HSTS still active
  • All other security measures: Unchanged

What's Now Allowed:

  • PDF previews: Can now be embedded in iframes on same domain
  • Document previews: Word, Excel, PowerPoint previews work
  • Image previews: Enhanced preview capabilities
  • Same-origin embedding: Any same-origin content can be framed

🔒 Security Comparison:

Header Before After Protection Level
X-Frame-Options DENY SAMEORIGIN Still protected against external clickjacking
CSP frame-ancestors 'none' 'self' Still protected against external embedding

Verification

Test the headers are correctly applied:

curl -I http://localhost:8080/api/v1/settings | grep -E "X-Frame-Options|Content-Security-Policy"

Expected output:

X-Frame-Options: SAMEORIGIN
Content-Security-Policy: ...frame-ancestors 'self';

Files Modified

  1. main.go
  2. internal/middleware/security_headers.go
  3. internal/config/config.go

Deployment

Backend was rebuilt and restarted:

docker compose build backend --no-cache
docker compose up -d backend

Testing Checklist

  • PDF files can be previewed in iframes
  • Word documents (.doc, .docx) preview correctly
  • Excel spreadsheets (.xls, .xlsx) preview correctly
  • PowerPoint presentations (.ppt, .pptx) preview correctly
  • Text files (.txt) preview correctly
  • Images still display correctly
  • External sites cannot frame the application
  • Same-origin iframes work correctly
  • YouTube embeds still work
  • All other security headers remain active

Additional Notes

Why SAMEORIGIN?

  • DENY: Blocks all framing, including same-origin (too restrictive for previews)
  • SAMEORIGIN: Allows same-origin framing but blocks external sites (balanced security)
  • ALLOW-FROM: Deprecated and not widely supported

CSP frame-ancestors

  • 'none': Blocks all framing (equivalent to X-Frame-Options: DENY)
  • 'self': Allows same-origin framing only (equivalent to X-Frame-Options: SAMEORIGIN)
  • More modern and flexible than X-Frame-Options

Browser Compatibility

  • X-Frame-Options: Supported by all browsers
  • CSP frame-ancestors: Supported by all modern browsers, overrides X-Frame-Options when present

Future Enhancements (Optional)

  • Implement per-route frame options for even finer control
  • Add specific iframe sandbox attributes for enhanced security
  • Consider using <embed> or <object> tags with additional security attributes

References