Repository navigation
fix(security): Web Admin 登录限流、会话与 API 表面安全加固 - #307
Merged
Merged
Conversation
- Resolve client IP by walking X-Forwarded-For right-to-left and taking the rightmost untrusted hop; client-supplied XFF values can no longer bypass login throttling or pin bans on arbitrary IPs - Replace prefix-string trusted-proxy check with ipaddress is_private/is_loopback so public ranges like 172.64.0.0/10 are no longer trusted (RFC1918 is 172.16.0.0/12) - Cap the login failure/ban trackers and sweep expired entries so forged source IPs cannot grow web process memory unboundedly - Add absolute session lifetime WEB_ADMIN_SESSION_MAX_AGE_HOURS (default 168h): sliding renewal can no longer extend a session past creation + max age; existing sessions are invalidated on upgrade - Store only the SHA-256 hash of session ids in web_admin_sessions.db; plaintext ids stay in the browser cookie - Keep the frontend authenticated state when the logout request fails, and tell the admin the session is still valid instead of showing a logged-out UI - docs/admin/web-admin.md: recommend overwrite semantics for X-Forwarded-For (proxy_set_header X-Forwarded-For $remote_addr) and add an nginx limit_req example for /ops/
- Serve CSP, X-Frame-Options, X-Content-Type-Options and Referrer-Policy on every Web Admin response (static pages and API) - Stop exposing /docs, /redoc and /openapi.json on the admin API; the public machine contract for llm-configuration keeps being exported in-process by scripts/ci/export_llm_configuration_openapi.py
- Tieba sync has real side effects (external fetching, pool rewrite), so it is now triggered with POST instead of GET, restoring the GET-has-no-side-effects assumption behind the same-origin check exemption; the frontend consumes the progress stream with fetch + AbortController (EventSource only supports GET) and aborts it when the page scope is disposed - Stop echoing internal exception text in 5xx responses of tieba peek and wordcloud rendering (may contain server paths); clients get a generic message while the real exception goes to the service log - Tieba thread links accept only http/https; any other scheme returned upstream falls back to the canonical thread URL
- Cap both login trackers at 4096 entries with oldest-key eviction: the fails table previously stopped tracking new sources at capacity (a throttling vacuum for brute force), and the bans table had no cap at all; comment now matches behavior - Treat a corrupted session created_at as expired (delete + 401) instead of fail-open - Log tieba peek 502 failures with logger.exception for traceback parity with the wordcloud routes - Drop the dead app.openapi enrich monkeypatch: no HTTP entry remains since the docs endpoints were hidden, and the in-process export path is unaffected - docs: configuration.md gains the WEB_ADMIN_SESSION_MAX_AGE_HOURS row; web-admin.md and the client_ip docstring now state the trusted-proxy assumption (a public front proxy such as a CDN/LB makes the limiter key the proxy egress; never bind the admin directly to an untrusted L2 network)
Owner
Author
|
评审汇合(Deep-CR 五透镜 + 独立 Tier-1 CR + 交叉复核)后的修复轮,新 head: 七轨评审结论:无 Blocking。交叉复核按规则保留置信度 ≥80 且确属本变更的发现,本 PR 侧已修复:
验证:ruff 全过;pytest 2925 全过(含新增的逐出/上限/损坏行用例)。 记录在案的取舍:多级代理链取跳的算法语义维持现状(仅文档声明边界,不引入可配置可信代理列表)。 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
概述
Web Admin 安全加固专项,源自一轮后台全面排查中的安全专项发现。与前端大修 PR 拆分评审,两者文件零重叠。
commits:
fix(security): login throttle and session hardening— XFF 解析改为从右往左取最右一个非内网跳(伪造请求头无法再绕过限流或定向封禁管理员);信任代理判定从前缀字符串改为ipaddress标准库(172.一刀切收敛到 RFC1918 实际的 172.16.0.0/12,Cloudflare 的 172.64+ 不再被误信);登录失败/封禁记录增加容量上限与过期清扫;新增会话绝对寿命WEB_ADMIN_SESSION_MAX_AGE_HOURS(默认 168h);会话 id 落库改存 SHA-256;前端退出登录失败时保留登录态并如实提示。fix(security): add security headers, hide API docs— 全站响应统一下发 CSP /X-Frame-Options/X-Content-Type-Options/Referrer-Policy;管理 API 不再暴露/docs、/redoc、/openapi.json(LLM 配置的公开机器契约继续由scripts/ci/export_llm_configuration_openapi.py在进程内导出)。fix(security): tieba sync via POST, sanitize 5xx— 贴吧同步改为 POST(恢复"GET 无副作用"语义,前端改用 fetch + AbortController 消费进度流并在离开页面时主动断开);贴吧 peek 与词云渲染的 5xx 不再回显内部异常文本;贴吧帖链只接受 http/https scheme。升级影响
X-Forwarded-For改为覆盖语义(proxy_set_header X-Forwarded-For $remote_addr;)并按docs/admin/web-admin.md补充limit_req。旧文档的追加语义在新代码下仍能正确解析(从右往左取值),不强制立刻改。验证
.venv/bin/ruff check .全过;pytest tests/unit2923 全过(含新增test_client_ip.py、test_auth_security.py、test_app_security.py、test_tieba_sync_route.py与 crawler 用例)。node --test56/56、vite build成功(旧工具链基线)。scripts/check/deep-cr-trigger.sh dev:trigger=true(persistence + web-admin,24 files / 707 行),按仓库流程组织 Deep-CR 与独立 CR,结论汇总后请求人工合并。CHANGELOG 草稿
修复
172.前缀信任范围收敛到 RFC1918 实际的 172.16.0.0/12/docs、/redoc、/openapi.json端点不再对外暴露;LLM 配置的公开机器契约继续由 CI 脚本在进程内导出(docs/dev/llm-configuration.openapi.json)X-Frame-Options、X-Content-Type-Options、Referrer-Policy变更
WEB_ADMIN_SESSION_MAX_AGE_HOURS,默认 168 小时):自创建起超过该时长必须重新登录,滑动续期不能突破该上限;会话 id 落库改存 SHA-256 哈希。升级后所有存量登录态失效,需重新登录一次X-Forwarded-For改为覆盖语义(proxy_set_header X-Forwarded-For $remote_addr;),并补充 nginxlimit_req限流建议,详见 docs/admin/web-admin.md