securite: #87 T6-T8 fin dette — deps qualifiées, semgrep, Secure auto, CORS
This commit is contained in:
+27
-3
@@ -260,12 +260,19 @@ async def lifespan(app: FastAPI):
|
||||
# BUG-037: refuse to expose an unauthenticated instance on a public bind.
|
||||
_guard_insecure_auth()
|
||||
|
||||
# #87 T3 : avertir quand les cookies d'auth circulent sans flag Secure
|
||||
# sur un bind non-loopback (transactions observables en clair).
|
||||
# #87 T3/T8 : avertir quand les cookies d'auth circulent sans flag Secure
|
||||
# sur un bind non-loopback (transactions observables en clair). Avec
|
||||
# `OBSIGATE_SECURE_COOKIES=auto` (défaut) + `OBSIGATE_TRUST_PROXY=true`,
|
||||
# le flag suit `X-Forwarded-Proto` : pas d'avertissement, le https du
|
||||
# reverse proxy est honoré.
|
||||
from backend.auth.middleware import bind_host_from_argv, is_auth_enabled, is_loopback_host
|
||||
from backend.auth.router import is_secure_cookies
|
||||
from backend.services.net import is_trusted_proxy
|
||||
|
||||
if is_auth_enabled() and not is_secure_cookies() and not is_loopback_host(bind_host_from_argv()):
|
||||
secure_mode = os.environ.get("OBSIGATE_SECURE_COOKIES", "auto").lower()
|
||||
proxy_secure = secure_mode == "auto" and is_trusted_proxy()
|
||||
if (is_auth_enabled() and not is_secure_cookies()
|
||||
and not is_loopback_host(bind_host_from_argv()) and not proxy_secure):
|
||||
logger.warning(
|
||||
"Cookies d'authentification sans flag `Secure` sur un bind non-loopback : "
|
||||
"activez TLS et posez OBSIGATE_SECURE_COOKIES=true en production."
|
||||
@@ -388,6 +395,7 @@ async def _service_error_handler(request: Request, exc: ServiceError):
|
||||
# GZip compression — reduces bandwidth by ~70% for text responses
|
||||
# Custom wrapper: skip compression for SSE streams (/api/events)
|
||||
from fastapi.middleware.gzip import GZipMiddleware
|
||||
from starlette.middleware.cors import CORSMiddleware
|
||||
from starlette.types import Receive, Scope, Send
|
||||
|
||||
|
||||
@@ -418,6 +426,22 @@ app.add_middleware(SSESafeGZipMiddleware, minimum_size=1000)
|
||||
# Security headers on all responses
|
||||
app.add_middleware(SecurityHeadersMiddleware)
|
||||
|
||||
# Explicit same-origin CORS policy (#87 T8 — finit BUG-034).
|
||||
# `allow_origins=[]` : le navigateur n'émet aucun `Access-Control-Allow-*`,
|
||||
# donc toute lecture cross-origin est refusée (défense explicite, plus
|
||||
# seulement l'absence de middleware). Sûr pour tous les clients : web
|
||||
# (same-origin), desktop Tauri (la webview est redirigée same-origin sur
|
||||
# http://127.0.0.1:<port>, voir frontend/js/desktop.js) et API directe
|
||||
# (curl/scripts, CORS non appliqué hors navigateur). Ajouté en dernier :
|
||||
# le plus externe, les preflights court-circuitent avant tout le reste.
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=[],
|
||||
allow_credentials=False,
|
||||
allow_methods=["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
|
||||
# Auth router
|
||||
# Multi-format export (HTML / MD bundle / ePub) — voir backend.routers.files_media (#85 T6c).
|
||||
from backend.ai_routes import router as ai_router
|
||||
|
||||
Reference in New Issue
Block a user