From 15f854d96cbc8782a4398792e725880f11cb0ded Mon Sep 17 00:00:00 2001 From: rene Date: Thu, 23 Apr 2026 18:34:05 +0200 Subject: [PATCH] Session 2026-04-23: Security, Content-Schutz, Wiki-Temperament-Migration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Security (9 Fixes): - JWT_SECRET Pflicht-Check beim Start (Production) - Rate-Limit: Login (10/5min), Register (5/h), KI-Training (10/h), Giftköder (3/h) - KI-Training-Endpoint: Auth-Pflicht hinzugefügt - Private Profile aus Freunde-Suche gefiltert - OG-Tags XSS mit html.escape() gesichert - Globales File-Upload-Limit 20 MB (Middleware) - E-Mail-Maskierung für Moderatoren im Admin-Panel - IP-Blocklist in ratelimit.py Content-Schutz (4 Schichten): - robots.txt: /api/ komplett Disallow, SSR-Seiten Allow - Rate-Limit auf /api/wiki/rassen (60/min) + Detail (30/min) - Honeypot /api/wiki/trap + unsichtbarer Link in index.html - Wasserzeichen in KI-Enricher-Prompt Wiki Temperament-Migration: - 60-Wort Übersetzungsmap EN→DE - Datenmüll-Filter (hunderasse, dog breed etc.) - translate_existing_temperaments() + Admin-Button - SW by-v318, APP_VER 306 --- backend/auth.py | 6 ++ backend/main.py | 37 +++++++-- backend/ratelimit.py | 34 +++++++- backend/routes/admin.py | 15 +++- backend/routes/auth.py | 9 +- backend/routes/friends.py | 1 + backend/routes/ki.py | 13 +-- backend/routes/poison.py | 7 +- backend/routes/wiki.py | 20 ++++- backend/scraper/breed_enricher.py | 134 +++++++++++++++++++++++++++++- backend/static/index.html | 4 + backend/static/js/app.js | 2 +- backend/static/js/pages/admin.js | 27 ++++++ backend/static/robots.txt | 26 +----- backend/static/sw.js | 2 +- 15 files changed, 284 insertions(+), 53 deletions(-) diff --git a/backend/auth.py b/backend/auth.py index fad4d47..2b60a52 100644 --- a/backend/auth.py +++ b/backend/auth.py @@ -18,6 +18,12 @@ JWT_SECRET = os.getenv("JWT_SECRET", "change-me-in-production") JWT_ALGO = "HS256" JWT_EXPIRY = int(os.getenv("JWT_EXPIRY_DAYS", "30")) +if JWT_SECRET == "change-me-in-production" and os.getenv("ENV") == "production": + raise RuntimeError( + "SICHERHEITSFEHLER: JWT_SECRET ist nicht gesetzt. " + "Bitte JWT_SECRET in .env setzen und Container neu starten." + ) + security = HTTPBearer(auto_error=False) diff --git a/backend/main.py b/backend/main.py index a6c16aa..efdadb6 100644 --- a/backend/main.py +++ b/backend/main.py @@ -3,11 +3,13 @@ BAN YARO — FastAPI Hauptanwendung """ import os +import html import logging from collections import deque from fastapi import FastAPI, Request from fastapi.staticfiles import StaticFiles from fastapi.responses import FileResponse, JSONResponse +from starlette.middleware.base import BaseHTTPMiddleware from contextlib import asynccontextmanager from database import init_db @@ -61,6 +63,22 @@ app = FastAPI( redoc_url = None, ) +# Globales File-Upload-Limit (20 MB) +_MAX_UPLOAD_BYTES = 20 * 1024 * 1024 + +class _UploadSizeMiddleware(BaseHTTPMiddleware): + async def dispatch(self, request: Request, call_next): + if request.method in ("POST", "PUT", "PATCH"): + cl = request.headers.get("content-length") + if cl and int(cl) > _MAX_UPLOAD_BYTES: + return JSONResponse( + status_code=413, + content={"detail": f"Datei zu groß (max. {_MAX_UPLOAD_BYTES // 1024 // 1024} MB)."} + ) + return await call_next(request) + +app.add_middleware(_UploadSizeMiddleware) + # ------------------------------------------------------------------ # API-Router registrieren (werden nach und nach hinzugefügt) @@ -649,24 +667,25 @@ async def public_dog_page(dog_id: int): except Exception: pass - html = f""" + _s = html.escape # XSS-Schutz für OG-Meta-Tags + _html = f""" - {_og_name} — Ban Yaro - + {_s(_og_name)} — Ban Yaro + - - + + - + - - + +