Harden backend security: IDOR fix, error sanitization, rate limiter fallback, security headers
- Fix task status IDOR by adding ownership check; suppress traceback/error in production - Passkey routes: return generic error messages for internal exceptions, keep ValueError for user-facing - JWT_SECRET and OIDC_CLIENT_ID: raise RuntimeError in production when using defaults - Rate limiter: add in-memory fallback counter when Redis is unavailable - Fix X-Forwarded-For IP spoofing with trusted_proxy_depth (rightmost-N selection) - Add SecurityHeadersMiddleware (X-Content-Type-Options, X-Frame-Options, CSP, conditional HSTS) - CORS: add PUT/DELETE methods for POI routes - POI input validation: field length and coordinate range constraints - QueryParameters: add min_sqm <= max_sqm validation
This commit is contained in:
parent
e431eaf2aa
commit
0a9a83507e
8 changed files with 133 additions and 32 deletions
|
|
@ -44,9 +44,11 @@ async def register_begin(body: RegisterBeginRequest) -> RegisterBeginResponse:
|
|||
body.email, user_repo
|
||||
)
|
||||
return RegisterBeginResponse(options=options, session_id=session_id)
|
||||
except Exception as e:
|
||||
logger.error(f"Registration begin failed: {e}")
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
except Exception:
|
||||
logger.exception("Registration begin failed")
|
||||
raise HTTPException(status_code=400, detail="Registration failed. Please try again.")
|
||||
|
||||
|
||||
@passkey_router.post("/register/complete", response_model=AuthTokenResponse)
|
||||
|
|
@ -60,9 +62,9 @@ async def register_complete(body: CeremonyCompleteRequest) -> AuthTokenResponse:
|
|||
return AuthTokenResponse(token=token)
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
except Exception as e:
|
||||
logger.error(f"Registration complete failed: {e}")
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
except Exception:
|
||||
logger.exception("Registration complete failed")
|
||||
raise HTTPException(status_code=400, detail="Registration could not be completed.")
|
||||
|
||||
|
||||
@passkey_router.post("/login/begin", response_model=LoginBeginResponse)
|
||||
|
|
@ -72,9 +74,11 @@ async def login_begin() -> LoginBeginResponse:
|
|||
user_repo = UserRepository(engine)
|
||||
options, session_id = passkey_service.begin_authentication(user_repo)
|
||||
return LoginBeginResponse(options=options, session_id=session_id)
|
||||
except Exception as e:
|
||||
logger.error(f"Login begin failed: {e}")
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
except Exception:
|
||||
logger.exception("Login begin failed")
|
||||
raise HTTPException(status_code=400, detail="Login initiation failed. Please try again.")
|
||||
|
||||
|
||||
@passkey_router.post("/login/complete", response_model=AuthTokenResponse)
|
||||
|
|
@ -88,6 +92,6 @@ async def login_complete(body: CeremonyCompleteRequest) -> AuthTokenResponse:
|
|||
return AuthTokenResponse(token=token)
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
except Exception as e:
|
||||
logger.error(f"Login complete failed: {e}")
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
except Exception:
|
||||
logger.exception("Login complete failed")
|
||||
raise HTTPException(status_code=400, detail="Login could not be completed.")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue