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:
Viktor Barzin 2026-02-08 19:42:30 +00:00
parent e431eaf2aa
commit 0a9a83507e
No known key found for this signature in database
GPG key ID: 0EB088298288D958
8 changed files with 133 additions and 32 deletions

View file

@ -5,9 +5,15 @@ import os
_logger = logging.getLogger(__name__)
APP_ENV = os.getenv("APP_ENV", "development")
# Authentik OIDC Configuration
AUTHENTIK_URL = os.getenv("AUTHENTIK_URL", "https://authentik.viktorbarzin.me")
OIDC_CLIENT_ID = os.getenv("OIDC_CLIENT_ID", "5AJKRgcdgVm1OyApBzFkadDFfStW9a555zwv2MOe")
OIDC_CLIENT_ID = os.getenv("OIDC_CLIENT_ID", "")
if APP_ENV == "production" and not OIDC_CLIENT_ID:
raise RuntimeError("OIDC_CLIENT_ID must be set in production")
if not OIDC_CLIENT_ID:
_logger.warning("OIDC_CLIENT_ID not set; OIDC login will not work")
OIDC_METADATA_URL = (
f"{AUTHENTIK_URL}/application/o/wrongmove/.well-known/openid-configuration"
)
@ -27,6 +33,8 @@ WEBAUTHN_ORIGIN = os.getenv("WEBAUTHN_ORIGIN", "https://localhost")
# JWT Configuration (for passkey-issued tokens)
JWT_SECRET = os.getenv("JWT_SECRET", "change-me-in-production")
if JWT_SECRET == "change-me-in-production":
if APP_ENV == "production":
raise RuntimeError("JWT_SECRET must be changed from default in production")
_logger.warning("JWT_SECRET is using the default value. Set JWT_SECRET env var in production.")
JWT_ALGORITHM = os.getenv("JWT_ALGORITHM", "HS256")
JWT_EXPIRATION_HOURS = int(os.getenv("JWT_EXPIRATION_HOURS", "24"))