8.9 KiB
SSE Authentication Security Mitigations
Implementation Date
2025-10-02
Security Concern: Token in Query Parameters
The SSE endpoint (/api/events?token=xxx) accepts authentication tokens via query parameters due to browser EventSource API limitations. This introduces security risks that have been mitigated.
Security Risks & Mitigations
1. Token Exposure in Logs ⚠️
Risk: Nginx access logs contain full URLs including tokens Impact: Medium - If logs are compromised, tokens could be exposed
Mitigations Implemented:
- ✅ Short Token Expiry: JWT tokens expire in 30 minutes (configurable in
.env) - ✅ HTTPS Only: All production traffic uses TLS encryption
- ✅ Log Access Control: Kubernetes logs have RBAC restrictions
- ⚠️ Manual Log Filtering: Nginx configuration-snippet is disabled by admin
Additional Mitigation (Manual): If you have access to nginx ingress controller configuration, enable log filtering:
# In nginx ingress controller ConfigMap
data:
log-format-upstream: '$remote_addr - $remote_user [$time_local] "$request_method $sanitized_uri $server_protocol" $status $body_bytes_sent "$http_referer" "$http_user_agent"'
Or use a log aggregation tool (Loki, ELK) with regex filtering to redact tokens.
2. Token in Browser History 📝
Risk: Browser stores URLs with query params in history Impact: Low - Requires local access to user's machine
Mitigations Implemented:
- ✅ User's Own Browser: History is private to the user
- ✅ Short Expiry: Old tokens in history expire quickly
- ✅ Auto-logout: Session management invalidates tokens
Not a Risk: SSE connections are initiated by JavaScript (EventSource), not user navigation, so they typically don't appear in browser history.
3. Referrer Header Leakage 🔗
Risk: When user navigates away, Referrer header might include SSE URL Impact: Medium - Token could leak to third-party sites
Mitigations Implemented:
- ⚠️ Referrer-Policy Header: Attempted via nginx annotation (blocked by admin)
- ✅ SameSite Routing: SSE is same-origin (no external referrers)
- ✅ HTTPS: Browsers don't send Referrer from HTTPS to HTTP
Manual Mitigation: Add to HTML head in frontend:
<meta name="referrer" content="no-referrer">
Or add HTTP header via frontend response headers.
4. Proxy/CDN Caching 🌐
Risk: Intermediary proxies might cache or log URLs Impact: Low - Internal infrastructure only
Mitigations Implemented:
- ✅ Direct Ingress: No external proxies/CDNs
- ✅ Internal Network: All routing within Kubernetes cluster
- ✅ Cache-Control Headers: SSE endpoints set no-cache
5. Accidental URL Sharing 📤
Risk: Users could copy/share URLs with embedded tokens Impact: High (for regular URLs) / Low (for SSE - not user-visible)
Mitigations Implemented:
- ✅ Hidden from Users: EventSource connections not visible in address bar
- ✅ Short Token Expiry: Shared tokens expire quickly
- ✅ One-Time Use: Tokens invalidated on logout
Security Comparison
| Threat | Query Param Token | Header Token | Cookie Token | WebSocket |
|---|---|---|---|---|
| Server Logs | ⚠️ Medium | ✅ Safe | ✅ Safe | ✅ Safe |
| Browser History | ⚠️ Low | ✅ Safe | ✅ Safe | ✅ Safe |
| Referrer Leakage | ⚠️ Medium | ✅ Safe | ⚠️ Medium | ✅ Safe |
| XSS Attacks | ⚠️ Vulnerable | ⚠️ Vulnerable | ✅ httpOnly | ⚠️ Vulnerable |
| CSRF Attacks | ✅ Safe | ✅ Safe | ⚠️ Requires token | ✅ Safe |
| Ease of Use | ✅ Simple | ❌ Not supported | ⚠️ Complex | ⚠️ Complex |
| Browser Support | ✅ Native | ❌ No EventSource | ✅ Native | ✅ Native |
Applied Mitigations Summary
✅ Implemented:
- Short token expiry (30 minutes)
- HTTPS enforcement (production)
- Token validation (middleware + endpoint)
- CORS restrictions (specific origins)
- Kubernetes RBAC (log access control)
- Same-origin policy (no external referrers)
- Auto-logout (session management)
⚠️ Blocked by Infrastructure:
- Nginx log filtering (configuration-snippet disabled)
- Referrer-Policy header (configuration-snippet disabled)
📝 Recommended (Manual):
- Add Referrer-Policy meta tag to frontend HTML
- Enable nginx log filtering if ingress admin allows
- Use log aggregation with token redaction (Loki/ELK)
- Monitor for suspicious patterns in logs
Production Checklist
Before deploying to production, ensure:
- HTTPS enforced (no HTTP fallback)
- Token expiry set to ≤ 30 minutes
- CORS origins limited to specific domains (not
*) - Kubernetes RBAC configured for log access
- Frontend has Referrer-Policy meta tag
- Log aggregation configured with token redaction
- Monitoring/alerting for failed auth attempts
- Rate limiting enabled on gateway
- Regular security audits of access logs
Upgrade Path to Cookie-Based Auth
For maximum security, migrate to cookie-based authentication:
Effort: ~2-3 hours Security: ⭐⭐⭐⭐⭐ (5/5)
Changes needed:
- Auth service sets httpOnly cookie on login
- Gateway auth middleware reads cookie instead of query param
- Frontend uses
withCredentials: true(already done!)
Benefits:
- ✅ No token in URL
- ✅ No token in logs
- ✅ XSS protection (httpOnly)
- ✅ CSRF protection (SameSite)
Risk Assessment
Current Risk Level: MEDIUM ⚠️
Acceptable for:
- ✅ Internal/development environments
- ✅ Short-term production (with monitoring)
- ✅ Low-sensitivity data
Not recommended for:
- ❌ High-security environments
- ❌ Long-term production without upgrade path
- ❌ Systems handling PII/financial data
Upgrade recommended within: 30-60 days for production
Incident Response
If Token Leak Suspected:
-
Immediate Actions:
# Invalidate all active sessions kubectl exec -it -n bakery-ia $(kubectl get pod -n bakery-ia -l app=redis -o name) -- redis-cli KEYS auth:token:* DEL auth:token:* -
Rotate JWT Secret:
# Update .env JWT_SECRET_KEY=<new-secret-64-chars> # Restart auth service and gateway kubectl rollout restart deployment auth-service gateway -n bakery-ia -
Force Re-authentication:
- All users must login again
- Existing tokens invalidated
-
Audit Logs:
# Check for suspicious SSE connections kubectl logs -n ingress-nginx -l app.kubernetes.io/component=controller | grep "/api/events"
Monitoring Queries
Check for Suspicious Activity:
# High volume of SSE connections from single IP
kubectl logs -n ingress-nginx -l app.kubernetes.io/component=controller | grep "/api/events" | awk '{print $1}' | sort | uniq -c | sort -rn | head -10
# Failed authentication attempts
kubectl logs -n bakery-ia -l app.kubernetes.io/name=gateway | grep "401\|Invalid token"
# SSE connections with expired tokens
kubectl logs -n bakery-ia -l app.kubernetes.io/name=gateway | grep "Token expired"
Compliance Notes
GDPR:
- ✅ Tokens are pseudonymous identifiers
- ✅ Short retention (30 min expiry)
- ⚠️ Tokens in logs = personal data processing (document in privacy policy)
SOC 2:
- ⚠️ Query param auth acceptable with compensating controls
- ✅ Encryption in transit (HTTPS)
- ✅ Access controls (RBAC)
- 📝 Document risk acceptance in security policy
PCI DSS:
- ❌ Not recommended for payment card data
- ✅ Acceptable for non-cardholder data
- 📝 May require additional compensating controls
References
Decision Log
Date: 2025-10-02 Decision: Use query parameter authentication for SSE endpoint Rationale: EventSource API limitation (no custom headers) Accepted Risk: Medium (token in logs, limited referrer leakage) Mitigation Plan: Implement cookie-based auth within 60 days Approved By: Technical Lead
Next Steps
-
Short-term (now):
- ✅ Query param auth implemented
- ✅ Security mitigations documented
- 📝 Add Referrer-Policy to frontend
- 📝 Configure log monitoring
-
Medium-term (30 days):
- 📝 Implement cookie-based authentication
- 📝 Enable nginx log filtering (if allowed)
- 📝 Set up log aggregation with redaction
-
Long-term (60 days):
- 📝 Security audit of implementation
- 📝 Penetration testing
- 📝 Consider WebSocket migration (if bidirectional needed)