Files
MABEA/deploy/nginx_mabea.conf.template
patrickandClaude Sonnet 5 ceddeb1bf4
CI / backend-tests (push) Failing after 19s
CI / frontend-build (push) Successful in 25s
Multi-Agent-Review: Race Conditions, DB-Indizes, TLS/Security-Härtung
Konsolidierte Funde aus postgres-/sql-/jwt-/owasp-top10-expert-Review:

- Race Conditions gefixt: doppelte aktive Kontrolle (SAVEPOINT + partieller
  Unique-Index), doppelte Mindermengen-Genehmigung (FOR UPDATE + Unique-Index),
  Lost-Update bei Nachfüllung (FOR UPDATE auf Fehlbestand/Objektposition).
- Migration 0007: partielle Unique-Indizes als DB-Sicherheitsnetz + fehlende
  FK-Indizes (fehlbestand.material_id, kontrolle(objekt_id,status),
  zustaendigkeit, benutzer_rolle.rolle, objektposition.ablaufdatum u.a.).
- Connection-Pool explizit begrenzt (pool_size=5, max_overflow=5) - ohne das
  könnte jeder uvicorn-Worker den Postgres max_connections-Wert sprengen.
- Timing-Angriff bei Login-Enumeration gefixt (konstante Antwortzeit über
  Dummy-Hash), JWT-Decode verlangt jetzt exp/sub-Claims.
- App-seitiges Rate-Limiting (slowapi, 5/min) auf /auth/login als Verteidigung
  in der Tiefe zusätzlich zum nginx-Limit.
- nginx: TLS mit selbstsigniertem Zertifikat (LAN-Betrieb, keine Domain),
  HSTS, Content-Security-Policy, Permissions-Policy ergänzt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-04 18:47:06 +02:00

64 lines
2.7 KiB
Plaintext

# limit_req_zone gehört in den http-Kontext (hier: via sites-enabled-Include-Kette
# bereits innerhalb von http{}, aber außerhalb des server{}-Blocks nötig).
# Grober Schutz gegen Brute-Force auf Login, ergänzt (nicht ersetzt) die
# App-seitige Rate-Begrenzung (slowapi, siehe backend/app/core/rate_limit.py).
limit_req_zone $binary_remote_addr zone=mabea_login:10m rate=5r/m;
# HTTP -> HTTPS Redirect. Selbstsigniertes Zertifikat (Karte owasp-Review: LAN-
# Betrieb ohne öffentliche Domain, kein Let's Encrypt möglich) - Browser zeigen
# beim ersten Zugriff eine Warnung, bis das Zertifikat manuell akzeptiert wird.
server {
listen 80;
server_name __APP_DOMAIN__;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name __APP_DOMAIN__;
ssl_certificate /etc/nginx/ssl/mabea.crt;
ssl_certificate_key /etc/nginx/ssl/mabea.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
# Basis-Hardening-Header (Review-Fund owasp-top10-expert).
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
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;
# CSP erlaubt nur same-origin (PWA lädt keine externen Skripte/Fonts) plus
# Kamera-Zugriff für den Barcode-Scanner (Karte 10). connect-src 'self'
# deckt auch API-Aufrufe ab, da Frontend/API dieselbe Origin teilen (siehe
# location-Blöcke unten). Owasp-Review-Fund: CSP fehlte komplett.
add_header Content-Security-Policy "default-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; script-src 'self'; connect-src 'self'; frame-ancestors 'none'" always;
add_header Permissions-Policy "camera=(self)" always;
location /api/v1/auth/login {
limit_req zone=mabea_login burst=5 nodelay;
proxy_pass http://127.0.0.1:8000;
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;
}
location /api/ {
proxy_pass http://127.0.0.1:8000;
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;
}
# React-PWA (Sprint 7): statische Build-Ausgabe von frontend/dist.
# try_files statt 404 bei Client-Routen, da react-router-dom im Browser routet.
root /var/www/mabea;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
}