# 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) ```diff - c.Writer.Header().Set("X-Frame-Options", "DENY") + c.Writer.Header().Set("X-Frame-Options", "SAMEORIGIN") ``` #### 2. **internal/middleware/security_headers.go** (Line 15) ```diff - c.Header("X-Frame-Options", "DENY") + c.Header("X-Frame-Options", "SAMEORIGIN") ``` #### 3. **internal/middleware/security_headers.go** (Lines 59, 74) ```diff Production CSP: - "frame-ancestors 'none';" + "frame-ancestors 'self';" Development CSP: - "frame-ancestors 'none';" + "frame-ancestors 'self';" ``` #### 4. **internal/config/config.go** (Line 110) ```diff - 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: ```bash 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: ```bash 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 `` or `` tags with additional security attributes ## References - [MDN: X-Frame-Options](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options) - [MDN: CSP frame-ancestors](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-ancestors) - [OWASP: Clickjacking Defense](https://cheatsheetseries.owasp.org/cheatsheets/Clickjacking_Defense_Cheat_Sheet.html)