Critical (1-3): - Replace hardcoded admin credentials with secure auto-generation (seed.py) - Enforce SECRET_KEY configuration, fail in production if missing (config.py) - Add Zip Slip and Zip Bomb protection to all ZIP import services High/Medium (4-9): - Add 50MB file size limit and extension whitelist to evidence uploads - Configure CORS origins via environment variable instead of hardcoded - Migrate JWT storage from localStorage to HttpOnly cookies (frontend+backend) - Add rate limiting (5/min) on login endpoint via slowapi - Replace generic dict payloads with Pydantic schemas (mass assignment) Medium (10-17): - Check is_active on login to prevent disabled users from authenticating - Sanitize exception messages in API responses (system, data_sources) - Escape LIKE wildcards in all ilike search filters across 8 routers - Run Docker container as non-root user (appuser) - Make MINIO_SECURE configurable via environment variable - Add password complexity policy (12+ chars, upper/lower/digit/special) - Implement JWT token revocation via in-memory blacklist + reduce TTL to 15min - Replace xml.etree with defusedxml to prevent Billion Laughs attacks Low (18-20): - Add security headers to Nginx (CSP, X-Frame-Options, HSTS-ready, etc.) - Disable Swagger UI/ReDoc/OpenAPI in production - Restrict /health endpoint to internal networks via Nginx ACL Also: rewrite install.sh as interactive wizard for guided deployment, fix test-from-template validation error (technique_id UUID vs MITRE ID)
63 lines
3.0 KiB
Nginx Configuration File
63 lines
3.0 KiB
Nginx Configuration File
server {
|
|
listen 80;
|
|
server_name localhost;
|
|
root /usr/share/nginx/html;
|
|
index index.html;
|
|
|
|
# ── Security Headers ─────────────────────────────────────────────
|
|
add_header X-Content-Type-Options "nosniff" always;
|
|
add_header X-Frame-Options "DENY" always;
|
|
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
|
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
|
|
add_header X-XSS-Protection "0" always;
|
|
# HSTS — uncomment when using HTTPS (recommended in production)
|
|
# add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
|
|
|
# CSP: allow self + inline styles (React build) + data: URIs for fonts/images
|
|
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self' data:; connect-src 'self'; frame-ancestors 'none'; base-uri 'self'; form-action 'self';" always;
|
|
|
|
# Hide Nginx version
|
|
server_tokens off;
|
|
|
|
# ── Gzip compression ─────────────────────────────────────────────
|
|
gzip on;
|
|
gzip_types text/plain text/css application/json application/javascript text/xml application/xml;
|
|
|
|
# ── SPA routing ──────────────────────────────────────────────────
|
|
location / {
|
|
try_files $uri $uri/ /index.html;
|
|
}
|
|
|
|
# ── Cache static assets ──────────────────────────────────────────
|
|
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
|
|
expires 1y;
|
|
add_header Cache-Control "public, immutable";
|
|
}
|
|
|
|
# ── Proxy API requests to backend ────────────────────────────────
|
|
location /api/ {
|
|
proxy_pass http://backend:8000/api/;
|
|
proxy_set_header Host $host;
|
|
proxy_set_header X-Real-IP $remote_addr;
|
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
proxy_set_header X-Forwarded-Proto $scheme;
|
|
|
|
# Long-running operations (MITRE sync, data source imports) need more time
|
|
proxy_read_timeout 300s;
|
|
proxy_connect_timeout 10s;
|
|
proxy_send_timeout 300s;
|
|
}
|
|
|
|
# ── Health endpoint proxy (internal only) ────────────────────────
|
|
location /health {
|
|
# Only allow health checks from Docker internal network and localhost
|
|
allow 127.0.0.1;
|
|
allow 10.0.0.0/8;
|
|
allow 172.16.0.0/12;
|
|
allow 192.168.0.0/16;
|
|
deny all;
|
|
|
|
proxy_pass http://backend:8000/health;
|
|
}
|
|
}
|