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
This commit is contained in:
@@ -63,7 +63,19 @@ PGCONF
|
||||
grep -q "conf.d/\*.conf" "${PG_CONF_DIR}/postgresql.conf" || \
|
||||
echo "include_dir = 'conf.d'" >> "${PG_CONF_DIR}/postgresql.conf"
|
||||
|
||||
echo "== nginx Reverse-Proxy Config (inkl. Security-Header) =="
|
||||
echo "== TLS: selbstsigniertes Zertifikat (LAN-Betrieb ohne Domain, Karte owasp-Review) =="
|
||||
mkdir -p /etc/nginx/ssl
|
||||
if [ ! -f /etc/nginx/ssl/mabea.crt ]; then
|
||||
openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \
|
||||
-keyout /etc/nginx/ssl/mabea.key -out /etc/nginx/ssl/mabea.crt \
|
||||
-subj "/CN=${APP_DOMAIN}"
|
||||
chmod 600 /etc/nginx/ssl/mabea.key
|
||||
echo "Selbstsigniertes Zertifikat erzeugt (10 Jahre gültig) - Browser warnen beim ersten Zugriff, bis manuell akzeptiert/importiert."
|
||||
else
|
||||
echo "Zertifikat existiert bereits, überspringe."
|
||||
fi
|
||||
|
||||
echo "== nginx Reverse-Proxy Config (inkl. Security-Header, TLS) =="
|
||||
sed -e "s/__APP_DOMAIN__/${APP_DOMAIN}/g" \
|
||||
"$(dirname "$0")/nginx_mabea.conf.template" > /etc/nginx/sites-available/mabea.conf
|
||||
ln -sf /etc/nginx/sites-available/mabea.conf /etc/nginx/sites-enabled/mabea.conf
|
||||
@@ -94,5 +106,7 @@ echo "Zugangsdaten liegen (chmod 600) in ${CRED_FILE} – NICHT auf stdout ausge
|
||||
echo "DATABASE_URL von dort in backend/.env auf dem Server übernehmen (siehe backend/example.env)."
|
||||
echo "Backend selbst ist noch nicht deployt – siehe deploy/mabea-backend.service.template für den späteren systemd-Dienst."
|
||||
echo
|
||||
echo "Hinweis: nginx läuft aktuell nur über Port 80 (kein TLS). Für echten Betrieb vor Domain-Vergabe"
|
||||
echo "TLS nachziehen (Let's Encrypt bei Domain, sonst selbstsigniertes Zertifikat fürs LAN)."
|
||||
echo "nginx läuft über HTTPS mit selbstsigniertem Zertifikat (Port 80 leitet auf 443 um)."
|
||||
echo "Browser warnen beim ersten Zugriff - Zertifikat manuell akzeptieren/importieren."
|
||||
echo "Sobald eine echte Domain feststeht: ssl_certificate/-key in /etc/nginx/sites-available/mabea.conf"
|
||||
echo "auf ein Let's-Encrypt-Zertifikat umstellen (certbot)."
|
||||
|
||||
@@ -1,18 +1,39 @@
|
||||
# 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
|
||||
# Rate-Begrenzung/Lockout auf Anwendungsebene, die noch aussteht (Review-Fund).
|
||||
# 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;
|
||||
}
|
||||
|
||||
# Basis-Hardening-Header (Review-Fund owasp-top10-expert). Sobald TLS aktiv ist,
|
||||
# zusätzlich Strict-Transport-Security ergänzen.
|
||||
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;
|
||||
|
||||
Reference in New Issue
Block a user