Session 2026-04-23: Security, Content-Schutz, Wiki-Temperament-Migration
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
This commit is contained in:
parent
0f5f1c4c30
commit
15f854d96c
15 changed files with 284 additions and 53 deletions
|
|
@ -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"""<!DOCTYPE html>
|
||||
_s = html.escape # XSS-Schutz für OG-Meta-Tags
|
||||
_html = f"""<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{_og_name} — Ban Yaro</title>
|
||||
<meta name="description" content="{_og_desc}">
|
||||
<title>{_s(_og_name)} — Ban Yaro</title>
|
||||
<meta name="description" content="{_s(_og_desc)}">
|
||||
<meta name="robots" content="noindex">
|
||||
<meta property="og:type" content="profile">
|
||||
<meta property="og:title" content="{_og_name} — Ban Yaro">
|
||||
<meta property="og:description" content="{_og_desc}">
|
||||
<meta property="og:title" content="{_s(_og_name)} — Ban Yaro">
|
||||
<meta property="og:description" content="{_s(_og_desc)}">
|
||||
<meta property="og:url" content="https://banyaro.app/hund/{dog_id}">
|
||||
<meta property="og:image" content="{_og_img}">
|
||||
<meta property="og:image" content="{_s(_og_img)}">
|
||||
<meta property="og:locale" content="de_DE">
|
||||
<meta property="og:site_name" content="Ban Yaro">
|
||||
<meta name="twitter:card" content="summary">
|
||||
<meta name="twitter:title" content="{_og_name} — Ban Yaro">
|
||||
<meta name="twitter:image" content="{_og_img}">
|
||||
<meta name="twitter:title" content="{_s(_og_name)} — Ban Yaro">
|
||||
<meta name="twitter:image" content="{_s(_og_img)}">
|
||||
<link rel="stylesheet" href="/css/design-system.css">
|
||||
<link rel="stylesheet" href="/css/components.css">
|
||||
<style>
|
||||
|
|
@ -947,7 +966,7 @@ async def public_dog_page(dog_id: int):
|
|||
</body>
|
||||
</html>"""
|
||||
from fastapi.responses import HTMLResponse
|
||||
return HTMLResponse(content=html)
|
||||
return HTMLResponse(content=_html)
|
||||
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue