security: harden admin password change and production session headers

This commit is contained in:
2026-02-07 21:37:55 +08:00
parent 7997a97a9a
commit 08864e51ba
26 changed files with 159 additions and 59 deletions

36
app.py
View File

@@ -135,6 +135,33 @@ def _is_api_or_health_path(path: str) -> bool:
return raw.startswith("/api/") or raw.startswith("/yuyx/api/") or raw == "/health"
def _request_uses_https() -> bool:
try:
if bool(request.is_secure):
return True
except Exception:
pass
try:
forwarded_proto = str(request.headers.get("X-Forwarded-Proto", "") or "").split(",", 1)[0].strip().lower()
if forwarded_proto == "https":
return True
except Exception:
pass
return False
_SECURITY_RESPONSE_HEADERS = {
"X-Content-Type-Options": "nosniff",
"X-Frame-Options": "SAMEORIGIN",
"Referrer-Policy": "strict-origin-when-cross-origin",
"Permissions-Policy": "camera=(), microphone=(), geolocation=(), payment=()",
}
_SECURITY_CSP_HEADER = str(os.environ.get("SECURITY_CONTENT_SECURITY_POLICY", "") or "").strip()
_HASHED_STATIC_ASSET_RE = re.compile(r".*-[a-z0-9_-]{8,}\.(?:js|css|woff2?|ttf|svg|png|jpe?g|webp)$", re.IGNORECASE)
@@ -238,6 +265,15 @@ def ensure_csrf_cookie(response):
samesite=config.SESSION_COOKIE_SAMESITE,
)
for header_name, header_value in _SECURITY_RESPONSE_HEADERS.items():
response.headers.setdefault(header_name, header_value)
if _request_uses_https():
response.headers.setdefault("Strict-Transport-Security", "max-age=31536000; includeSubDomains")
if _SECURITY_CSP_HEADER:
response.headers.setdefault("Content-Security-Policy", _SECURITY_CSP_HEADER)
_record_request_metric_after_response(response)
return response