From 2f5fe8baaa2fd345a822a8b3e060843b44bcd10d Mon Sep 17 00:00:00 2001 From: qing <1776177662@qq.com> Date: Mon, 3 Aug 2026 23:42:32 +0800 Subject: [PATCH] =?UTF-8?q?docs(security):=20=E6=96=B0=E5=A2=9E=20libhttp?= =?UTF-8?q?=20=E6=A8=A1=E5=9D=97=E5=AE=89=E5=85=A8=E5=AE=A1=E8=AE=A1?= =?UTF-8?q?=E6=8A=A5=E5=91=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../libhttp_SECURITY_AUDIT_20260803.md | 107 ++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 docs/security/libhttp_SECURITY_AUDIT_20260803.md diff --git a/docs/security/libhttp_SECURITY_AUDIT_20260803.md b/docs/security/libhttp_SECURITY_AUDIT_20260803.md new file mode 100644 index 0000000..a0fd93c --- /dev/null +++ b/docs/security/libhttp_SECURITY_AUDIT_20260803.md @@ -0,0 +1,107 @@ +# libhttp 安全审计报告 + +**审计日期**: 2026-08-03 +**审计范围**: `libhttp/inc/us/`、`libhttp/src/`(HttpServer 6 个拆分 TU + HttpClient + 遗留 WebSocketServer/WebSocketClient) +**代码版本**: dev_qing 分支 + +--- + +## 修复进度 + +| 优先级 | 总数 | 已修复 | 部分修复 | 未修复 | +|--------|------|--------|----------|--------| +| P0 | 0 | 0 | 0 | 0 | +| P1 | 6 | 0 | 0 | 6 | +| P2 | 4 | 0 | 0 | 4 | +| **合计** | **10** | **0** | **0** | **10** | + +--- + +## 🟠 P1 — 高危问题 + +| # | 问题 | 状态 | 说明 | +|---|------|------|------| +| P1-1 | 请求体大小限制不可配置 + 超限无 413 | ❌ 未修复 | `Session::doRead`(`HttpServer_Request.cpp` L167-183)用 `http::async_read(stream, buffer_, request_, ...)` 直接把整个请求体读入 `http::request`。依赖 Beast 默认 `body_limit`(1MB,硬编码不可配置),与 WAF 的 10MB 不一致;**超限时 `http::error::body_limit` 走错误分支直接断开连接,不返回 413**(对应全局审计 P1-5) | +| P1-2 | HttpClient 响应无大小限制 | ❌ 未修复 | `HttpClient::write_callback`(`HttpClient.cpp` L329-334)把下游响应 `append` 进 `full_response` 无上限,超大响应可导致 OOM(`request_stream_sync` L63-81) | +| P1-3 | WebSocket 消息无大小限制 | ❌ 未修复 | `Session::onWsRead`(`HttpServer_WsSession.cpp` L88-111)把整条 WS 消息读入内存,依赖 Beast 默认 `read_message_max`(16MB)不可配置;超大消息可被恶意客户端推送导致 OOM | +| P1-4 | 服务器无读写超时(Slowloris) | ❌ 未修复 | 入站 `stream_`(`beast::tcp_stream`)**从未设置 `expires_after`**(仅代理后端设了超时)。攻击者建立连接后缓慢发送 HTTP 头,可无限占用连接与线程,Slowloris/连接耗尽(对应全局审计 P2-4) | +| P1-5 | 静态文件目录路径遍历 | ❌ 未修复 | `handleRequest`(`HttpServer_Request.cpp` L94-119)直接 `static_directory_ + target_path` 拼接文件路径,未校验 `..`/空字节/编码遍历。设置 `setStaticDirectory` 的服务可被 `GET /../../etc/passwd` 越权读取 | +| P1-6 | 发送队列无界(慢消费者 OOM) | ❌ 未修复 | `ws_send_queue_`、`proxy_to_backend_queue_`、`proxy_to_client_queue_`(`HttpServer_WsSession.cpp` L8-16/L362-367/L438-443)均为无界 `std::deque`。若客户端消费慢,服务端持续入队可导致内存耗尽 | + +--- + +## 🟡 P2 — 中危问题 + +| # | 问题 | 状态 | 说明 | +|---|------|------|------| +| P2-1 | CORS 反射任意 Origin | ❌ 未修复 | OPTIONS 预检(`HttpServer_Request.cpp` L73-74)把 `Access-Control-Allow-Origin` 直接设为请求的 `Origin` 值,任意来源均被放行,无白名单校验(对应全局审计 P2-3 根因) | +| P2-2 | TLS 客户端一律不校验证书 | ❌ 未修复 | `HttpClient.cpp` L131 与 WS 代理 `HttpServer_WsSession.cpp` L243 均 `set_verify_mode(asio::ssl::verify_none)`。对内部后端可接受,但库内不留逃生口,无法在需要校验时启用 | +| P2-3 | WebSocket 握手无 Origin/CSWSH 校验 | ❌ 未修复 | libhttp 对任意 `ws`/`ws_proxy` upgrade 请求直接握手,不校验 `Origin`/`Sec-WebSocket-Protocol`。若后端依赖 Cookie 鉴权,存在跨站 WebSocket 劫持(CSWSH)风险(gateway 的 `ws_proxy` 依赖握手回调鉴权,属应用层缓解) | +| P2-4 | HttpClient `ws_recv` 忽略 timeout 参数 | ❌ 未修复 | `HttpClient.cpp` L220-221 `(void)timeout_ms;` 丢弃超时参数,`ws_recv` 会**无限阻塞**。后端挂起时调用线程永久卡死 | +| P2-5 | 反向代理后端连接建立后无超时 | ❌ 未修复 | 代理后端握手成功后 `proxy_tcp_stream_->expires_never()`(`HttpServer_WsSession.cpp` L262/L287),双向读写无超时,慢后端可长期占用连接 | +| P2-6 | 无连接数限制 | ❌ 未修复 | `Listener::doAccept`(`HttpServer_Listener.cpp` L23-48)无限接受连接,每连接一个 Session,无最大连接数上限,可被连接耗尽 | + +--- + +## 🔵 P3 — 低危问题 + +| # | 问题 | 状态 | 说明 | +|---|------|------|------| +| P3-1 | 遗留 WebSocketServer/WebSocketClient 未构建 | ❌ 未修复 | `WebSocketServer.cpp`/`WebSocketClient.cpp` 仅被 CMakeLists.txt 引用,**Makefile 未编译**,与 `HttpClient` 混用。其实现存在缺陷(无超时、`disconnectClient` 不真正关闭连接 L344-352、`onRead` 对错误路径未关闭),建议删除或维护 | +| P3-2 | CMakeLists.txt 过时 | ❌ 未修复 | CMakeLists 仍引用旧文件路径(`inc/us/HttpServer.hpp` 等)与旧拆分前源码,与 Makefile 实际构建不一致,易误导 | + +--- + +## ✅ 已有安全机制 + +1. ✅ **Beast 默认头/体限制**: `http::async_read` 使用 Beast 默认 `header_limit`(8KB) + `body_limit`(1MB),超限拒绝暴力请求 +2. ✅ **TLS 服务端密码套件受限**: `initSSLContext`(`HttpServer.cpp` L30-62)禁用 `!aNULL:!MD5:!DSS`,仅允许强套件 +3. ✅ **TLS 服务端禁用 SSLv2/v3**: `no_sslv2 | no_sslv3`(`HttpServer.cpp` L36-37) +4. ✅ **会话生命周期管理**: `enable_shared_from_this` + `close()` 析构,连接关闭时清理 WS 代理队列 +5. ✅ **代理后端连接超时**: 建立连接阶段设 `expires_after(10s)`(`HttpServer_WsSession.cpp` L225/L253) +6. ✅ **WS 消息顺序保持**: 写队列串行化,避免并发写交错 +7. ✅ **WS 代理握手鉴权回调**: `ws_proxy` 支持 `WsProxyHandshakeHandler` 在 upgrade 阶段授权(gateway 用于 admin-only 控制) + +--- + +## 修复路线图 + +### 立即(24小时) +- [ ] P1-1 请求体大小限制:`doRead` 改用 `http::request_parser` + `body_limit()`,`HttpServer` 增加 `setMaxBodySize()`(对齐 WAF 10MB),超限返回 413 而非断开 +- [ ] P1-2 HttpClient 响应上限:`write_callback` 累计超过上限即失败,返回错误 +- [ ] P1-4 服务器读超时:入站 `stream_` 设置 `expires_after`(首字节/头+体超时),防 Slowloris + +### 短期(72小时) +- [ ] P1-3 WS 消息大小限制:设置 `read_message_max`(可配置) +- [ ] P1-5 静态文件路径遍历:拼接前校验 `target_path` 拒绝 `..`/空字节/编码遍历 +- [ ] P1-6 发送队列上限:`ws_send_queue_`/代理队列设最大值,超限断开慢消费者 +- [ ] P2-1 CORS 白名单:origin 白名单校验,替代反射任意 Origin + +### 中期 +- [ ] P2-3 WS 握手 Origin 校验(防 CSWSH) +- [ ] P2-4 `ws_recv` 实现超时(用 `io_context` + timer 或 `async_read` + 私有超时) +- [ ] P2-5 代理后端读写超时 + 空闲保活 +- [ ] P2-6 最大连接数限制 +- [ ] P2-2 TLS 校验可配置(至少提供 `verify_peer` 选项) +- [ ] P3-1 删除或维护遗留 WebSocketServer/WebSocketClient +- [ ] P3-2 同步 CMakeLists.txt 与 Makefile + +--- + +## 代码位置索引 + +| 功能 | 文件 | 行号 | +|------|------|------| +| 请求读入(无体限制) | `src/HttpServer_Request.cpp` | L167-183 | +| 请求处理/静态文件 | `src/HttpServer_Request.cpp` | L7-137, L94-119 | +| CORS 反射 Origin | `src/HttpServer_Request.cpp` | L73-74 | +| WS 读消息(无大小限制) | `src/HttpServer_WsSession.cpp` | L88-111 | +| WS 发送队列/代理队列 | `src/HttpServer_WsSession.cpp` | L8-16, L362-367, L438-443 | +| 代理后端超时 | `src/HttpServer_WsSession.cpp` | L225, L253, L262, L287 | +| 代理 TLS verify_none | `src/HttpServer_WsSession.cpp` | L243 | +| 连接接受(无限制) | `src/HttpServer_Listener.cpp` | L23-48 | +| TLS 服务端配置 | `src/HttpServer.cpp` | L30-62 | +| HttpClient 响应无上限 | `src/HttpClient.cpp` | L63-81, L329-334 | +| HttpClient TLS verify_none | `src/HttpClient.cpp` | L131 | +| HttpClient ws_recv 忽略超时 | `src/HttpClient.cpp` | L220-221 | +| 遗留 WS 实现(未构建) | `src/WebSocketServer.cpp`、`src/WebSocketClient.cpp` | 全篇 | \ No newline at end of file