Add Cross-Origin Resource Policy headers for enhanced security
- Introduced Cross-Origin-Resource-Policy header in server.js, nginx.conf, and _headers to restrict resource sharing to same-site origins, improving security against cross-origin attacks. - Ensured consistent application of Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy across server and nginx configurations for better resource management.
This commit is contained in:
116
SECURITY_REVIEW_CSP_CHANGES.md
Normal file
116
SECURITY_REVIEW_CSP_CHANGES.md
Normal file
@@ -0,0 +1,116 @@
|
||||
# Security Review: CSP and Cross-Origin Headers Changes
|
||||
|
||||
## Changes Made
|
||||
|
||||
### 1. CSP `default-src` Directive
|
||||
**Change:** Added explicit `https://chat.365devnet.eu` to `default-src` alongside existing `https://*.365devnet.eu`
|
||||
|
||||
**Security Impact:** ✅ **SAFE - No security degradation**
|
||||
- The subdomain `chat.365devnet.eu` is already explicitly allowed in:
|
||||
- `script-src` (for RocketChat scripts)
|
||||
- `connect-src` (for API calls)
|
||||
- `frame-src` (for iframe embedding)
|
||||
- The wildcard `https://*.365devnet.eu` should have covered it, but explicit entry ensures Windows browser compatibility
|
||||
- This is a subdomain you control, not a third-party domain
|
||||
- **No new attack surface introduced**
|
||||
|
||||
### 2. Cross-Origin-Resource-Policy Header
|
||||
**Change:** Added `Cross-Origin-Resource-Policy: same-site` header
|
||||
|
||||
**Security Impact:** ✅ **SECURITY ENHANCEMENT**
|
||||
- `same-site` restricts resource loading to pages from the same site (same eTLD+1)
|
||||
- Since `365devnet.eu` and `chat.365devnet.eu` share the same eTLD+1, they can still load each other's resources
|
||||
- **Prevents other websites from embedding your resources**, which is a security improvement
|
||||
- This is a defense-in-depth measure, not a weakening
|
||||
|
||||
## Current Security Posture
|
||||
|
||||
### ✅ Strong Security Headers (All Present)
|
||||
1. **X-Content-Type-Options: nosniff** - Prevents MIME type sniffing
|
||||
2. **Referrer-Policy: strict-origin-when-cross-origin** - Limits referrer information leakage
|
||||
3. **Cross-Origin-Opener-Policy: same-origin** - Prevents cross-origin window access
|
||||
4. **Cross-Origin-Embedder-Policy: credentialless** - Isolates cross-origin resources
|
||||
5. **Cross-Origin-Resource-Policy: same-site** - Prevents cross-site resource embedding (NEW)
|
||||
6. **Strict-Transport-Security** - Enforces HTTPS with subdomain inclusion
|
||||
|
||||
### ⚠️ Known Acceptable Risks (Pre-existing)
|
||||
|
||||
#### 1. CSP `script-src` with `'unsafe-inline'`
|
||||
**Status:** Acceptable risk, documented
|
||||
- Required for inline scripts (RocketChat initialization, etc.)
|
||||
- Documented in `SECURITY_AUDIT.md` as acceptable
|
||||
- Could be improved with nonces in the future, but not critical
|
||||
|
||||
#### 2. CSP `script-src` with `'wasm-unsafe-eval'`
|
||||
**Status:** Acceptable risk
|
||||
- Required for WebAssembly execution
|
||||
- Only allows WASM, not arbitrary eval()
|
||||
- Necessary for modern web features
|
||||
|
||||
#### 3. CSP `img-src` with `https:`
|
||||
**Status:** Permissive but acceptable
|
||||
- Allows images from any HTTPS source
|
||||
- Common pattern for content-rich sites
|
||||
- Could be restricted to specific domains if needed
|
||||
|
||||
#### 4. CSP `style-src` with `'unsafe-inline'`
|
||||
**Status:** Standard practice
|
||||
- Inline styles are common and generally safe
|
||||
- Most sites use this pattern
|
||||
|
||||
### 🔒 CSP Directives Analysis
|
||||
|
||||
```javascript
|
||||
default-src 'self' https://365devnet.eu https://*.365devnet.eu https://chat.365devnet.eu;
|
||||
// ✅ Restrictive - only allows own domains
|
||||
|
||||
script-src 'self' 'unsafe-inline' 'wasm-unsafe-eval' https://chat.365devnet.eu;
|
||||
// ⚠️ Requires unsafe-inline (documented acceptable risk)
|
||||
|
||||
style-src 'self' 'unsafe-inline';
|
||||
// ✅ Standard practice
|
||||
|
||||
img-src 'self' data: https: blob:;
|
||||
// ⚠️ Permissive but acceptable for content sites
|
||||
|
||||
font-src 'self' data:;
|
||||
// ✅ Restrictive - only self and data URIs
|
||||
|
||||
connect-src 'self' https://365devnet.eu https://*.365devnet.eu https://chat.365devnet.eu https://git.365devnet.eu wss://chat.365devnet.eu;
|
||||
// ✅ Restrictive - only allows specific domains
|
||||
|
||||
frame-src 'self' https://chat.365devnet.eu;
|
||||
// ✅ Restrictive - only allows RocketChat iframe
|
||||
|
||||
frame-ancestors 'none';
|
||||
// ✅ Strong - prevents clickjacking
|
||||
|
||||
base-uri 'self';
|
||||
// ✅ Strong - prevents base tag injection
|
||||
|
||||
form-action 'self';
|
||||
// ✅ Strong - prevents form hijacking
|
||||
```
|
||||
|
||||
## Recommendations
|
||||
|
||||
### ✅ No Immediate Action Required
|
||||
The changes made are secure and do not introduce vulnerabilities.
|
||||
|
||||
### 🔄 Future Improvements (Optional)
|
||||
1. **Consider nonces for inline scripts** - Replace `'unsafe-inline'` with nonce-based CSP
|
||||
2. **Restrict `img-src`** - If possible, list specific image domains instead of `https:`
|
||||
3. **Add missing headers to nginx** - For consistency, add Cross-Origin headers to nginx config (though they're already in server.js)
|
||||
|
||||
## Conclusion
|
||||
|
||||
**Security Status: ✅ SECURE**
|
||||
|
||||
The changes made:
|
||||
- ✅ Do not introduce new vulnerabilities
|
||||
- ✅ Maintain existing security posture
|
||||
- ✅ Add a security enhancement (Cross-Origin-Resource-Policy)
|
||||
- ✅ Fix Windows compatibility without weakening security
|
||||
|
||||
The configuration remains secure and follows security best practices for a production website.
|
||||
|
||||
@@ -54,6 +54,9 @@ http {
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||
add_header Permissions-Policy "geolocation=(), camera=(), microphone=(), interest-cohort=()" always;
|
||||
add_header Cross-Origin-Opener-Policy "same-origin" always;
|
||||
add_header Cross-Origin-Embedder-Policy "credentialless" always;
|
||||
add_header Cross-Origin-Resource-Policy "same-site" always;
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
|
||||
|
||||
# Client body size limit
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
Permissions-Policy: geolocation=(), camera=(), microphone=(), interest-cohort=()
|
||||
Cross-Origin-Opener-Policy: same-origin
|
||||
Cross-Origin-Embedder-Policy: credentialless
|
||||
Cross-Origin-Resource-Policy: same-site
|
||||
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
|
||||
# Content-Security-Policy starter (enable after auditing inline scripts)
|
||||
# Content-Security-Policy: default-src 'self' https://365devnet.eu https://*.365devnet.eu; script-src 'self' 'wasm-unsafe-eval' 'nonce-astro' https://chat.365devnet.eu; style-src 'self' 'unsafe-inline'; img-src 'self' data: https://cdn.pixabay.com https://raw.githubusercontent.com; font-src 'self' data:; connect-src 'self' https://365devnet.eu https://chat.365devnet.eu wss://chat.365devnet.eu; frame-src https://chat.365devnet.eu; frame-ancestors 'none'; base-uri 'self'; form-action 'self'
|
||||
|
||||
@@ -21,6 +21,7 @@ app.use((req, res, next) => {
|
||||
res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin');
|
||||
res.setHeader('Cross-Origin-Opener-Policy', 'same-origin');
|
||||
res.setHeader('Cross-Origin-Embedder-Policy', 'credentialless');
|
||||
res.setHeader('Cross-Origin-Resource-Policy', 'same-site');
|
||||
// Gate SSR CSP to avoid breaking inline scripts unless explicitly enabled
|
||||
if (process.env.ENABLE_SSR_CSP === '1') {
|
||||
res.setHeader(
|
||||
|
||||
Reference in New Issue
Block a user