1. 当 Host 头变成路径BadHost 到底在攻击什么CVE-2026-48710代号 BadHost是 Starlette 在重建request.url时对 Host 头缺乏字符校验导致的主机头注入漏洞。它能让一个远程请求在中间件眼里是/evil在路由匹配时却命中/admin从而绕过几乎所有基于request.url.path的权限判断。受影响的是 Starlette ≤ 1.0.0修复版本为 1.0.1。FastAPI、vLLM、LiteLLM、MCP 服务器、Ray Serve、BentoML 这些 Python AI 生态里的常客只要间接依赖了旧版 Starlette就都在这条攻击链的射程内。这个漏洞适合谁关注如果你正在用 FastAPI 写 AI 网关、用 LiteLLM 做多模型代理、用 vLLM 暴露推理接口或者用 FastMCP 搭 Agent 工具服务那它就不是别人的漏洞。它的触发成本极低一个?字符就能让鉴权中间件失效。更麻烦的是很多开发者根本不知道request.url是基于用户可控的 Host 头重建出来的误以为它和scope[path]一样可信。我试过在本地起一个最小 FastAPI 服务复现从正常请求被 403 拦截到加上Host: 127.0.0.1:8000/?后直接返回敏感数据整个过程不到五分钟。这篇文章会带你走完复现、加固、验证三步并给出一个可复制的settings.json骨架把 TaoToken 统一 Key 通道接进来让请求校验和模型调用都收敛到同一条可控链路上。2. 复现环境与 TaoToken 前置准备2.1 最小复现服务先搭一个有漏洞的服务用request.url.path做权限判断这是最典型的错误写法。# vulnerable_app.py from fastapi import FastAPI, Request, HTTPException from starlette.middleware.base import BaseHTTPMiddleware app FastAPI(titleBadHost Vulnerable Demo) class PathBasedAuthMiddleware(BaseHTTPMiddleware): async def dispatch(self, request: Request, call_next): protected_paths [/admin, /internal] for path in protected_paths: if request.url.path.startswith(path): if request.client.host ! 127.0.0.1: raise HTTPException(status_code403, detailForbidden) return await call_next(request) app.add_middleware(PathBasedAuthMiddleware) app.get(/) async def public_endpoint(): return {message: public} app.get(/admin) async def admin_endpoint(): return {message: Sensitive admin data, api_key: sk-xxxx} app.get(/internal/config) async def internal_config(): return {config: internal service configurations}安装并启动pip install fastapi0.115.0 starlette1.0.0 uvicorn uvicorn vulnerable_app:app --host 0.0.0.0 --port 80002.2 TaoToken 统一 Key 通道准备复现完之后我们需要一条可控的模型调用链路来验证加固效果。TaoToken 提供统一的 Key 与 API 通道官网入口是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 基址为 https://taotoken.net/api 。你需要先在控制台创建一个 API Key控制台地址是 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite Key 管理页在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 模型对话调试页在 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentchatutm_campaignrewrite 。拿到 Key 之后我们把它写进一个settings.json作为服务端统一读取的配置骨架。这个文件同时承载三件事Host 白名单、TaoToken 通道参数、以及请求校验开关。3. 可复制的 settings.json 与反向代理加固骨架3.1 settings.json 加固骨架{ server: { allowed_hosts: [yourdomain.com, localhost, 127.0.0.1], reject_host_special_chars: true, trusted_proxy_ips: [127.0.0.1] }, taotoken: { base_url: https://taotoken.net/api, api_key_env: TAOTOKEN_API_KEY, default_model: claude-sonnet-4-20250514, timeout_seconds: 60, max_retries: 2 }, security: { use_scope_path_for_auth: true, enable_host_middleware: true, log_invalid_host: true } }几个关键点allowed_hosts是白名单不在列表里的 Host 直接拒绝reject_host_special_chars打开后任何包含/ ? # \空格或控制字符的 Host 头都会被 400 掉use_scope_path_for_auth强制权限判断走request.scope[path]而不是request.url.path。taotoken.api_key_env指向环境变量名避免把 Key 硬编码进文件。3.2 安全中间件实现# secure_middleware.py import json import os from fastapi import Request, JSONResponse from starlette.middleware.base import BaseHTTPMiddleware with open(settings.json, r, encodingutf-8) as f: CONFIG json.load(f) SPECIAL_CHARS set(/?#\\ \t\n\r) class SecureHostMiddleware(BaseHTTPMiddleware): async def dispatch(self, request: Request, call_next): host request.headers.get(host, ) if CONFIG[server][reject_host_special_chars]: if any(c in host for c in SPECIAL_CHARS): if CONFIG[security][log_invalid_host]: print(f[BadHost] rejected host{host!r}) return JSONResponse( status_code400, content{error: Invalid Host header} ) hostname host.split(:)[0] if hostname not in CONFIG[server][allowed_hosts]: return JSONResponse( status_code400, content{error: Host not allowed} ) return await call_next(request)权限判断部分改成# 错误易受 BadHost 影响 if request.url.path.startswith(/admin): # 正确使用 ASGI scope 原始路径 if request.scope[path].startswith(/admin):3.3 Nginx 反向代理加固server { listen 80; server_name yourdomain.com; if ($host ~* [/?#\\ \t\n\r]) { return 400; } location / { proxy_pass http://127.0.0.1:8000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }Nginx 在入口就把非法 Host 拦掉ASGI 服务只接受来自127.0.0.1的流量形成双层防护。4. 验证请求从恶意 Host 到 TaoToken 通道校验4.1 复现恶意 Host 注入先确认漏洞存在。正常请求curl -i http://127.0.0.1:8000/admin返回 403。加上恶意 Hostcurl -i http://127.0.0.1:8000/admin -H Host: 127.0.0.1:8000/?在未修复的 Starlette 1.0.0 上这会返回 200 和敏感数据。原因是request.url.path被重建为/中间件认为它不在保护列表里而路由匹配用的是scope[path]仍然是/admin。4.2 加固后验证升级 Starlette 并挂上SecureHostMiddleware后同样的恶意请求curl -i http://127.0.0.1:8000/admin -H Host: 127.0.0.1:8000/?返回 400Invalid Host header。正常请求curl -i http://127.0.0.1:8000/admin -H Host: 127.0.0.1:8000返回 403权限判断依然生效。4.3 TaoToken 通道校验加固完成后用 TaoToken 统一 Key 通道做一次端到端验证确认模型调用链路正常。先导出 Keyexport TAOTOKEN_API_KEY你的Key然后用 Python 发一个最小请求import os import json import urllib.request with open(settings.json, r, encodingutf-8) as f: cfg json.load(f) api_key os.environ[cfg[taotoken][api_key_env]] url f{cfg[taotoken][base_url]}/v1/chat/completions payload { model: cfg[taotoken][default_model], messages: [{role: user, content: ping}], max_tokens: 16 } req urllib.request.Request( url, datajson.dumps(payload).encode(), headers{ Authorization: fBearer {api_key}, Content-Type: application/json }, methodPOST ) with urllib.request.urlopen(req, timeoutcfg[taotoken][timeout_seconds]) as resp: print(resp.status) print(resp.read().decode()[:200])返回 200 和模型响应说明 TaoToken 通道可用。你也可以在模型对话页 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentchatutm_campaignrewrite 手动发一条消息做交叉验证。5. 本篇常见错排查升级后仍然被绕过检查是否有多层中间件顺序问题。SecureHostMiddleware必须加在权限中间件之前否则权限判断先执行恶意 Host 已经生效。用app.add_middleware时注意后添加的先执行。Nginx 返回 400 但服务端没日志说明请求在代理层就被拦了这是预期行为。如果想让服务端也记录把 Nginx 的return 400改成proxy_pass并在应用层拦截但这样会牺牲一层防护。request.scope[path]和request.url.path在正常请求下不一致正常请求下两者应该一致。如果不一致说明有代理做了路径重写检查proxy_set_header和X-Forwarded-Prefix配置。TaoToken 请求返回 401确认TAOTOKEN_API_KEY环境变量已导出且 Key 没有多余空格。可以在 API Keys 页 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 重新生成一个测试 Key。pip 升级 Starlette 后 FastAPI 报版本冲突FastAPI 对 Starlette 有版本上限约束。先升级 FastAPI 到最新版再升级 Starlette。如果仍有冲突用pip install starlette1.0.1 --upgrade --force-reinstall强制覆盖然后跑一遍测试。LiteLLM 代理场景LiteLLM 1.74.2 到 1.83.6 受 BadHost 与 CVE-2026-42271 利用链影响升级到 1.83.7 以上。升级后检查/mcp-rest/test/connection端点是否已加认证。6. 把校验链路收敛到 TaoToken 统一通道BadHost 的核心教训不是升级一个库而是不要信任任何用户可控输入重建出来的对象。request.url是重建的request.headers[host]是用户可控的只有scope[path]和scope[server]才是 ASGI 服务器解析后的原始值。把权限判断、日志记录、限流策略全部切到scope上是这次加固的底线。对于长期跑编码任务和 Agent 服务的团队建议把模型调用也收敛到统一通道。TaoToken 的 Coding Plan 入口在 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 适合需要稳定长连接的场景。Claude Code 相关接入参考 https://taotoken.net/claudecode-anthropic?utm_sourcetaotoken_aicg_blog_endutm_contentclaudecode-anthropicutm_campaignrewrite 。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 里面有完整的请求示例和错误码说明。最后留一个实操建议把settings.json里的allowed_hosts和taotoken.base_url做成环境变量覆盖这样本地调试、预发、生产可以用同一份代码只换配置。我踩过的坑是把allowed_hosts写死成localhost结果容器里跑的时候 Host 是服务名直接被自己的中间件拦了。
企业数字化 ERP 产品动态
相关推荐
Cursor Rules 快速上手:用 TaoToken 统一 Key 让 Agent 不再瞎改代码 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 19:02:42
拒绝拖期:怎么做网页定时提醒与建站报价避坑指南 拒绝拖期:怎么做网页定时提醒与建站报价避坑指南 改个需求建站公司拖一周,这种憋屈事儿谁没经历过?明明只是加个简单的倒计时或者定时弹窗,对方却以“排期满了”“技术难度大”为由,让你再等三天。这时候你心里肯定在打鼓:是不是我给的 建站报价… · 2026/9/27 19:02:42
网页建站的费用避坑指南:从域名到服务器的真实成本拆解 网页建站的费用避坑指南:从域名到服务器的真实成本拆解 刚接手一个外贸独立站项目,甲方盯着报价单直拍桌子:为什么我的域名才几十块,服务器却要花大几千?这就是典型的 域名服务器搞不懂… · 2026/9/27 20:14:08
联邦学习在拼多多API中的应用:2025隐私计算新范式与TaoToken配置实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 20:13:50
四川网站推广优化速查手册:被黑挂马后这样修才不白做 四川网站推广优化速查手册:被黑挂马后这样修才不白做 网站被黑挂马,首页突然变成博彩页面,后台密码改了也进不去?别慌,这种时候最忌讳盲目重装系统。我见过太多四川本地的企业站,因为不懂底层逻辑,花了大价钱找“黑客”删链,结果没三天又复发。今天这… · 2026/9/27 20:13:44
目前广泛应用的AI编程工具配 TaoToken:统一 Key 接入与 settings.json 配置骨架 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 20:13:44
零代码穿透:微信一键接入 OpenClaw 教程(TaoToken 统一 Key 配置版) /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 20:13:37
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现 简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01
汕头网站建设制作厂家避坑指南:5大注意事项救急 汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习 简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现 简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01
汕头网站建设制作厂家避坑指南:5大注意事项救急 汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习 简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01