Security Nice-to-Have: Dockerfile, Magic-Bytes, Path-Traversal, TABLE_MAP, Deps

- Dockerfile: non-root user appuser, chown /data + /app
- media_utils: validate_upload() Magic-Byte-Check (JPEG/PNG/GIF/WebP/MP4/WebM)
- media_utils: safe_media_path() Path-Traversal-Schutz beim Löschen
- diary/health/dogs: safe_media_path() statt os.path.join + lstrip
- diary: validate_upload() vor jedem Medien-Upload
- forum: _LIKE_TABLE dict statt dynamischer String-Interpolation
- requirements: uvicorn 0.34, PyJWT 2.10.1, pydantic 2.10.6, bcrypt 4.3, httpx 0.28.1, anthropic 0.49
- SW by-v319, APP_VER 307
This commit is contained in:
rene 2026-04-23 18:42:05 +02:00
parent 15f854d96c
commit 71e588a240
9 changed files with 100 additions and 29 deletions

View file

@ -8,7 +8,7 @@ from database import db
from auth import get_current_user
import ki as KI
import httpx
from media_utils import convert_media, extract_video_thumb
from media_utils import convert_media, extract_video_thumb, safe_media_path, validate_upload
router = APIRouter()
MEDIA_DIR = os.getenv("MEDIA_DIR", "/data/media")
@ -488,6 +488,10 @@ async def upload_media(dog_id: int, entry_id: int,
raise HTTPException(415, "Nur Bilder, Videos und PDFs erlaubt.")
raw_data = await file.read()
try:
validate_upload(raw_data, file.filename or "")
except ValueError as e:
raise HTTPException(415, str(e))
raw_data, ext = convert_media(raw_data, file.filename or "")
if not ext:
ext = ".jpg"
@ -539,9 +543,10 @@ async def delete_media_item(dog_id: int, entry_id: int, media_id: int,
).fetchone()
if not row:
raise HTTPException(404, "Medium nicht gefunden.")
file_path = os.path.join(MEDIA_DIR, row["url"].lstrip("/media/"))
try: os.remove(file_path)
except OSError: pass
file_path = safe_media_path(MEDIA_DIR, row["url"])
if file_path:
try: os.remove(file_path)
except OSError: pass
conn.execute("DELETE FROM diary_media WHERE id=?", (media_id,))
@ -556,9 +561,10 @@ async def delete_media_legacy(dog_id: int, entry_id: int, user=Depends(get_curre
if not row:
raise HTTPException(404, "Eintrag nicht gefunden.")
if row["media_url"]:
path = os.path.join(MEDIA_DIR, row["media_url"].lstrip("/media/"))
try: os.remove(path)
except OSError: pass
path = safe_media_path(MEDIA_DIR, row["media_url"])
if path:
try: os.remove(path)
except OSError: pass
conn.execute("UPDATE diary SET media_url=NULL WHERE id=?", (entry_id,))