fix(kiosk): TOCTOU-Race beim QR-Login (Audit-Finding K-1)
login_qr() las den Redis-Token per GET und löschte ihn danach separat per DELETE – zwei parallele Requests mit demselben QR-Token konnten beide vor dem Löschen lesen und je eine Session erzeugen (Doppel-Login statt echtem Einmal-Token). Fix: GETDEL (atomar seit Redis 6.2, Server läuft 8.0.2). K-2 (Cross-Tenant-Redeem) aus demselben Audit betrifft keinen realen Code-Pfad – company_id-Vergleich in login_qr() war bereits korrekt, und die Kiosk-Geräte-Enrollment "QR-Redeem"-Annahme existiert nicht als HTTP-Flow (Enrollment läuft ausschließlich über authentifizierte CLI). Verifiziert vor Weiterplanung der Android-Tablet-Kiosk-Architektur. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Dzdm3EWeNdYFUuXFRJryA1
This commit is contained in:
1 parent
2e27a7fcae
commit
d5b2fc75d6
1 file changed
+4
-4
@@ -256,15 +256,15 @@ class KioskAuthService:
|
||||
redis = get_async_redis()
|
||||
key = QR_TOKEN_PREFIX + qr_token
|
||||
try:
|
||||
data = await redis.get(key)
|
||||
# GETDEL statt GET+DELETE: atomar, sonst können zwei parallele
|
||||
# Requests denselben Token vor dem Löschen lesen (TOCTOU, Audit-
|
||||
# Finding K-1) und beide eine Session erzeugen.
|
||||
data = await redis.getdel(key)
|
||||
except Exception as exc:
|
||||
raise HTTPException(status_code=503, detail="QR-Login nicht verfügbar (Redis).") from exc
|
||||
if data is None:
|
||||
raise HTTPException(status_code=401, detail="QR-Code abgelaufen oder ungültig.")
|
||||
|
||||
# Einmalig: Token sofort löschen
|
||||
await redis.delete(key)
|
||||
|
||||
payload = json.loads(data)
|
||||
if str(payload.get("company_id")) != str(company_id):
|
||||
raise HTTPException(status_code=401, detail="QR-Code für falsches Unternehmen.")
|
||||
|
||||
Reference in new issue
Block a user