news 2026/10/19 5:35:00

面向大模型API场景的蜜罐系统设计与实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
面向大模型API场景的蜜罐系统设计与实现

这三四个月做的最有意思的一个内部项目,就是标题里这个“面向大模型API场景的蜜罐系统”。接了需求的时候我心里嘀咕了一句:现在连大模型API都需要养个假系统来钓鱼了?但等我翻完线上网关的访问日志,我承认,确实需要,而且比想象中更需要。

一句话解释这个项目:它是一套伪装成真实模型服务的诱饵接口。攻击者拿到泄露的API Key,或者用自动化工具扫到你的域名之后,第一反应一定是先请求一下/v1/models或者/v1/chat/completions看看服务是否存活。蜜罐就是干这个的——它会让攻击者看到一个“活着的”、“响应完全正常的”模型服务,让对方继续投入时间往下探测。与此同时,每一次请求的IP、指纹、请求体、攻击手法,全部被我们记录下来,用于溯源、情报积累和联动封禁。

这篇分享适合三类人看:正在给自家模型服务做安全加固的研发同学、做攻防演练想收集真实攻击样本的安全工程师,以及想低成本搭一套“钓鱼系统”来观察网络黑产手法的爱好者。我会从需求拆解、架构设计、核心实现、实操部署到排障避坑,把整个过程完整讲清楚,尽量做到看完就能照着搭。

1. 需求拆解与方案定位

1.1 大模型API面对的威胁是什么样

先说威胁模型。过去一年里,大模型API已经成为黑产的重点目标,原因很朴素:模型服务是按Token计费的,API Key就是真金白银。任何一个被泄露、被爬取、被误提交到公开仓库的Key,都是可以直接被滥用的“余额”。

我见过的攻击路径大概有这几种:

  • 全局扫描型:攻击者持有大量泄露的Key,用脚本遍历云厂商IP段和常见域名,挨个请求/v1/models测试可用性。
  • 针对性撞库型:知道目标公司用了某类模型网关,专门构造路径和认证头去探测内网风格接口。
  • 中转批发型:拿到可用Key之后,搭一个“中转站”,向下游客户转售模型访问能力,通过大量并发把额度刷爆。
  • 情报型:拿蜜罐当跳板,先探测接口的行为特征,判断后端接的是哪个厂商的模型,再决定是否进一步利用。

传统Web蜜罐能捕获一部分扫描流量,但很难骗过大模型场景的攻击者。因为攻击者已经形成了固定的“验证动作”——他们会直接发起一个带复杂Prompt的Chat请求,然后看返回内容是否真的“像模型”。如果只是返回一个静态HTML页面,对方半秒钟就识破了,后续的流量就断了。

1.2 为什么传统蜜罐方案不通用

传统蜜罐的核心能力是模拟服务指纹,常见做法是挂一个假的管理后台或者伪造一个登录页。这类方案在Web扫描场景里很好用,但在大模型API场景有一个致命短板:协议栈不匹配。

大模型API走的是JSON over HTTP,认证鉴权靠Authorization: Bearer sk-xxx,业务交互靠POST /v1/chat/completions传入model、messages,响应既有普通的JSON,也有text/event-stream的流式返回。传统蜜罐不会模拟这套协议,攻击者一个请求打过来,要么返回404,要么返回一个跟模型服务完全不搭边的页面,信任瞬间归零。

另外,大模型API蜜罐还有一个特殊点:它不只是要“看起来像”,还要“聊起来像”。攻击者会故意发一句测试内容来判断你是不是真模型。如果我们的假服务只会回固定字符串,第二次交互就暴露了。所以蜜罐得能生成动态且合理的模型响应。

1.3 蜜罐解决的核心问题

回到项目本身,这套蜜罐的价值集中在三个层面:

第一是前置预警。真实模型服务的攻击往往在消耗产生之后才发现,蜜罐相当于一个预警哨位,攻击者一旦触碰诱饵,我们立刻感知。

第二是攻击取证。攻击者的探测路径、尝试注入的Prompt、利用的工具指纹,都是真实攻击情报。这些数据比任何威胁情报平台上的样本都贴近我们的真实暴露面。

第三是消耗转移。攻击者以为在打正式API,实际上被引导到一个零成本的假服务上,既浪费时间又消耗不到我们真实额度。

1.4 方案选型:低交互还是高交互

蜜罐行业里有个简单的分类:低交互、中交互、高交互。低交互就是回几个固定响应包,纯骗扫描器;高交互是给攻击者一个完整可交互的真实环境。

大模型API蜜罐我建议定位在中低交互偏上的位置。核心原因有两个:

  • 高交互成本不可控。如果后端真的接了一个模型,攻击者可以通过多轮Prompt慢慢耗尽你的真额度。
  • 高交互有数据泄露风险。模型服务如果把内部知识或者系统Prompt都回给攻击者,那不是防御,是泄密。

所以这套系统只做“协议仿真”,不接真实模型。响应文本靠模板加随机化策略生成,足够让自动化脚本和大部分人工攻击者产生“这服务是活的”的错觉。

2. 整体设计思路与架构选型

2.1 核心思路:让诱饵“活”在真实链路里

蜜罐最大的忌讳是“太独立”。一个独立域名、独立IP、独立证书,看一眼就知道是个专用陷阱。但如果你把它藏在真实链路里,比如放在正式的API网关后面,和真实服务共享域名前缀、共用SSL证书、挂在同一个接入层后面,攻击者就很难区分了。

我们的做法是:申请一个独立的子域名,但让这个子域名的解析和主站走同一个边缘节点。用Nginx做流量分发,对外看起来就是同一套基础设施。攻击者扫描的是域名,看到的是同样的证书体系和相似的HTTP头,信任度一下就上来了。

2.2 系统总体架构

整个系统分为四层:

层级组件职责
流量接入层Nginx / OpenResty域名解析、TLS终止、按路径分发流量、简单限速
蜜罐仿真层FastAPI服务模拟模型API接口、校验Key、生成响应、采集日志
数据存储层Redis + Elasticsearch计数器、滑动窗口、请求日志存储和检索
联动处置层Shell脚本 + 告警渠道触发封禁、发送告警、同步威胁情报

流量接入层用Nginx是因为它太成熟了,配置一个反向代理只需要几行;此外OpenResty还能用Lua写一点轻逻辑,比如对明显恶意来源直接返回403,不必打到后面的仿真服务,减少无效日志。

蜜罐仿真层用FastAPI选型理由很简单:Python写起来快,Pydantic做请求体校验非常顺手,而且自带OpenAPI文档,方便内部调试。这个项目不追求高并发,不需要上Go或者Rust,一台2C4G的机器就已经绰绰有余。

数据存储层用Redis承担两个职责:一是做滑动窗口计数器,防止告警轰炸;二是存一些动态配置,比如要封禁的IP黑名单和假的Key列表。Elasticsearch主要做日志检索,因为我们想看某一类攻击源的请求序列,用ES的聚合查询比翻文本日志高效太多。但如果你的环境里没有ES,直接用JSON Lines日志加grep/awk也完全可以起步。

2.3 为什么对外伪装不能过度设计

设计阶段最想做的事情是把蜜罐做得“极其真实”,比如把token计费返回、模型列表、并发限制都加上。但实际操作下来,这里有个度要把握。

过度设计会带来两个问题:一是维护成本变高,真实模型API的响应结构经常更新,我们不可能一直跟着改;二是过度真实可能导致攻击者把蜜罐当成可用资源,长期占用不说,还会引来更多自动化工具刷量,把我们自己的日志系统打满。

所以我的建议是:协议层做到“符合主流客户端预期”,但业务层保留适度的模糊。比如/v1/chat/completions支持model、messages、temperature这些常用参数,但对tools、response_format这些新特性返回一个“错误”,反而更像一个版本稍旧的服务,攻击者不会怀疑。

3. 核心环节的实现细节

3.1 接口路径与认证头的仿真

公开的模型API风格高度统一,我们选取了三组最常被探测的路径:

  • GET /v1/models:列出可用模型,主要用于存活探测。
  • POST /v1/chat/completions:聊天补全,攻击者的主战场。
  • POST /v1/embeddings:向量化接口,黑产批发场景经常探测。

这三个路径覆盖了扫描器、测试脚本、中转站三种角色的核心需求。

认证方面,真实服务用的是Authorization: Bearer sk-...。蜜罐的校验逻辑我写了这样一个简单判定:

def verify_api_key(token: str) -> bool: if not token or not token.startswith("sk-"): return False if token in BLACKLIST_KEYS: return False if len(token) < 20: return False return True

逻辑要点是:只要格式符合且不在黑名单,就放行。我不能把校验做得太严格,否则攻击者拿一个老Key来撞,发现每次都是401,可能就觉得目标服务已经下线了。适当放宽校验,让大概率是恶意请求的流量进入蜜罐内部,是故意为之。

3.2 模型响应剧本:随机化与流式输出

响应生成是整个蜜罐的灵魂。我设计了三个层次的“剧本”:

默认响应:返回一个标准的ChatCompletion格式JSON,内容是一段通用的“服务正常”回答。

模型名映射:攻击者可能在请求里指定model: "gpt-4o"或者model: "deepseek-chat",蜜罐可以按模型名返回不同的系统回复风格,让下一次交互更可信。

流式响应:真实API默认流式返回的场景已经非常普遍,蜜罐必须支持。我实现了简单的SSE输出,把一个小回答拆成几段按时间吐出:

from fastapi.responses import StreamingResponse def fake_stream_chunk(token: str) -> str: return f'data: {{"choices":[{{"delta":{{"content":"{token}"}},"index":0}}]}}\n\n' async def stream_response(): for word in ["你好", ",", "我是", "一个", "智能助手"]: yield fake_stream_chunk(word) await asyncio.sleep(0.3) yield "data: [DONE]\n\n"

因为我们是仿真服务,内容生成不需要模型参与,完全靠预置语料池加随机选择。这里的诀窍是语料池要足够大,不能每次回话都是同一句“你好,我是智能助手”,否则攻击者做两次相同请求就识破了。

3.3 请求留痕与特征采集

记录什么信息直接决定了这套系统的分析价值。我的日志清单如下:

  • 时间戳(精确到毫秒)
  • 来源IP、端口
  • User-Agent、X-Forwarded-For
  • Authorization头的前32位(避免完整Key落盘)
  • 请求路径与完整请求体
  • 响应状态码、响应体大小、耗时
  • 蜜罐标识字段,方便和真实服务日志区分

请求体是比较敏感的内容。攻击者在蜜罐里发送的Prompt可能包含各种脏数据、注入尝试或者真实客户的数据。出于合规考虑,我不会把请求体原文直接落ES,而是做一次脱敏摘要:保留长度、关键词、是否含系统指令注入特征。等观察一段时间后,再决定是否人工提取部分关键样本。

def redact_body(body: dict) -> dict: prompts = [] for msg in body.get("messages", []): content = msg.get("content", "") prompts.append({ "role": msg.get("role", ""), "content_length": len(content), "content_snippet": content[:32], "has_injection": "@@" in content or "ignore previous" in content.lower(), }) return prompts

这段代码看起来简单,但has_injection这个字段帮了大忙。攻击者的Prompt注入尝试往往会出现“忽略之前的指令”“输出系统提示词”之类的写法,把这个特征记录成布尔字段,后面做统计分析非常方便。

3.4 告警与联动封禁

蜜罐本身不产生防御动作,它只负责发现。真正把价值放大的环节是告警和封禁。我的告警策略分了两级:

第一级:单次攻击识别。如果发现请求路径包含/admin、/actuator这类敏感路径,或者请求体中出现明显注入特征,立刻触发告警。

第二级:行为积累识别。三次以上对蜜罐的探测,或者同源IP在10分钟内调用超过20次,判定为活跃攻击源,进入封禁流程。

封禁不是我们去打防火墙改规则,而是给Nginx下发一条黑名单,由接入层统一拦截:

if ($http_x_forwarded_for ~* "^1\.2\.3\.4") { return 403; }

自动化流程写成一个脚本:从Redis里读取累积超阈值的IP,生成包含IP黑名单的Nginx配置文件片段,reload Nginx。整个过程几十行代码搞定,不需要额外基础组件。

4. 实操部署与试运行记录

4.1 部署拓扑与资源规划

这套系统的部署难度不高,我建议直接用一台独立的云主机,2核4G起步,带宽按1Mbps就够。域名方面,单独申请一个二级域名,比如honeypot-api.example.com,不要跟真实服务混用域名,避免误伤。

生产环境能用Docker Compose尽量用,整个系统就三个容器:nginx、honeypot-api、redis。Elasticsearch我建议按需再启,前期日志体量不大时,直接落到宿主机磁盘即可。

4.2 蜜罐服务的启动与配置

FastAPI服务的核心配置写在环境变量里,包括监听端口、允许的假Key列表、日志文件路径和告警Webhook地址:

export LISTEN_PORT=8001 export FAKE_KEYS="sk-honeypot-demo-key-001" export LOG_FILE="/var/log/honeypot/requests.jsonl" export ALERT_WEBHOOK="https://example.com/hook"

启动命令很简单:

uvicorn honeypot_app.main:app --host 0.0.0.0 --port 8001

4.3 Nginx流量分发配置

Nginx配置我放在这里,新增一个server块,专门处理蜜罐域名的流量:

server { listen 443 ssl; server_name honeypot-api.example.com; ssl_certificate /etc/nginx/certs/example.crt; ssl_certificate_key /etc/nginx/certs/example.key; access_log /var/log/nginx/honeypot_access.log combined; location / { proxy_pass http://127.0.0.1:8001; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Real-IP $remote_addr; } }

注意proxy_pass的写法,这里不要带URI尾缀,保证原始路径完整传给FastAPI,否则/v1/chat/completions会被改写。

4.4 上线后的流量观察

蜜罐上线第一周,效果比预期好很多。最直观的观察是:扫描器在发现/v1/models返回正常之后,会在几秒内立刻发起Chat请求。这说明攻击者的自动化流程非常依赖“先活着,再突破”的逻辑。

还有一种很典型的攻击模式:请求头里的UA是空的,但带了云厂商的默认User-Agent标志,一看就是从某云主机发起的批量化扫描。这类流量基本不会对话,只做路径枚举。

更复杂的情况是人工测试。有一次日志里出现了连续多轮对话,攻击者先问“你是谁”,又问“你背后的模型是什么”,最后尝试把系统指令套出来。我们的蜜罐因为语料池设计得不错,全程没有露馅,攻击者甚至尝试了三轮才离开。

4.5 数据回看与情报输出

日志落地之后,我写了一个简单的统计脚本,按小时聚合告警次数和攻击源数量,产出一个摘要表:

cat /var/log/honeypot/requests.jsonl | jq -r '.source_ip' | sort | uniq -c | sort -rn

用这个命令能快速看到top攻击源。后面我把这套统计逻辑集成到了临时面板里,日志一多,谁在扫、扫了什么路径、喜欢发什么Prompt,一览无余。

5. 常见问题与排查技巧实录

5.1 蜜罐流量突然断崖式下降

上线一段时间后,蜜罐访问量常常会骤降。可能的原因有两个:一是攻击者已经把该扫的扫完了,IP被全网标记;二是某云厂商的威胁情报系统把蜜罐域名标记为“C2/恶意资产”,导致后续扫描流量不再访问。

排查方法:先看DNS解析是否正常,再检查证书是否过期,然后用第三方网站查一下域名信誉。如果确实被标记了,短期别慌,等情报系统刷新即可;长期可以考虑换一个子域名或者把蜜罐放到另一个IP段去。

我的实际操作是准备了两套诱饵域名,按季度轮换,避免单点被情报污染。

5.2 蜜罐骗不过老练的攻击者

不是所有攻击者都靠自动化脚本,有些高水平的攻击者会逐步校验服务的真实性。他们会对比响应头里是否有真实厂商的标识,会测试超时不存在的模型名,甚至会在请求里故意加入一个不合法的JSON。

对付这类攻击者,我的经验是:不要在响应头里加任何多余的自定义头字段,响应时间尽量模拟真实模型的波动,并且支持一些“报错输出”。比如请求一个不存在的模型时,返回标准的model_not_found错误体,而不是简单回200。这是很多人容易忽略的细节。

我加了一个错误响应分支后,后续攻击者的停留时间明显变长了,有些人甚至开始尝试不同的模型名,说明他们认为这个服务是真实存在的。

5.3 告警轰炸导致真正重要的事件被淹没

蜜罐日志一多,告警就容易变成“狼来了”。连续几天告警不断,负责值班的同事最后连看都不想看了,真正重要的异常反而被淹没。

我的解决方案是给告警加了Redis滑动窗口。每个攻击源IP独立计数,相同IP在5分钟内最多触发一条告警,只有当一个IP在30分钟内触发超过5次时,才走紧急通知渠道。同时在告警内容里附上聚合摘要,比如“1.2.3.4在近30分钟内发起了23次探测,主要路径是/v1/models”,让值班人员一眼就能判断优先级。

5.4 蜜罐和真实服务互相干扰

最怕的一件事是蜜罐和真实服务配置串了,导致真实用户被引导到蜜罐接口上。这种情况一旦发生,影响的不只是用户体验,可能还会导致内部数据被当成诱饵记录,制造大量噪音。

规避方法:第一,蜜罐用独立域名和独立端口部署,不要复用真实服务的Nginx配置模板;第二,在日志里加一个静态的标记字段"honeypot": true,任何分析场景都先从日志中过滤掉这个字段;第三,写一个定时脚本,每天对比真实服务和蜜罐的访问日志,如果发现同一个请求源同时访问了两者,立刻告警,说明有配置混用或流量误配的风险。

5.5 请求体脱敏与合规风险

大模型API的请求体里经常包含业务数据和Prompt原文,直接落盘有合规风险。尤其是当攻击者把蜜罐当成真的服务来用,发送了一段真实的客户对话或者内部资料时,我们不能把这段内容原样存进日志。

我的做法是:对请求体中的文本字段一律截取前32个字符,同时对包含身份证号、手机号、邮箱等正则匹配的内容做加密存储。逻辑上所有日志都保留原始长度和哈希指纹,但只有拿到权限的人才能解开明文,这样既保留了分析价值,又避免敏感信息扩散。

写在最后的一点体会

做完这个项目最大的感受是:蜜罐的技术门槛真不高,难的是一直保持“像真的”。模型API是一个很年轻的服务形态,攻击者在变,防御手段也要跟着变。我建议准备做这个方向的朋友,先不要纠结于把系统架构搭得多么完整,而是先从最简单的/v1/models一个路径开始,让蜜罐“活下去”,让日志滚起来,再慢慢增加聊天补全、流式返回这些高阶能力。

另外说一个我自己反复踩的坑:千万不要把蜜罐的响应做得比线上真实服务还好。蜜罐的目的是拖住攻击者,不是让攻击者觉得“这个API真香”。我后来故意在蜜罐里加了响应延迟和偶发错误,结果反而看起来更像生产环境。这里面的度需要自己根据日志慢慢调。

如果你也想搭一套,建议先把日志分析和告警这两条链路做好再上线。蜜罐的价值不在于能骗住多少人,而在于每一次欺骗都被记下来、被用起来。但愿这个东西只在红队演练里被用到,永远不要接住真正的坏消息。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/19 5:34:10

蓝牙AoA室内定位原理与实战:从相位差到亚米级精度

从蓝牙5.1规范正式引入测向功能开始&#xff0c;蓝牙AoA&#xff08;到达角&#xff09;定位就一直被圈内人当成“下一代室内定位技术”来看待。但说实话&#xff0c;在真正上手跑过完整系统之前&#xff0c;我对它更多是观望态度——毕竟从纸面参数到现场稳定可是隔着无数坑。…

作者头像 李华
网站建设 2026/10/19 5:33:26

提示工程即黑箱辨识术:用控制论思维驯服大模型

做提示工程这件事&#xff0c;我前后折腾了一年多。最开始我以为它就是“把需求说清楚”&#xff0c;后来以为是“结构化的文字艺术”&#xff0c;再后来看了各种教程&#xff0c;开始研究角色、思维链、few-shot……直到某个晚上&#xff0c;我把一大堆 prompt 实验结果摊在表…

作者头像 李华
网站建设 2026/10/19 5:33:24

Spring Boot+大数据电影推荐系统毕设:从源码吃透到答辩通关

每年毕设季都能看到很多和电影推荐系统相关的题目&#xff0c;Spring Boot 大数据技术的组合更是高频出现。我帮人调试过几个同类项目&#xff0c;自己也完整搭过一个用于演示的模拟项目X。说句实话&#xff1a;这个题不难&#xff0c;但很烦。不难&#xff0c;是因为公开案例…

作者头像 李华
网站建设 2026/10/19 5:33:18

矩阵方法进阶:低秩近似、随机SVD与神经网络中的线性代数

最近终于把18.065的后半程啃完了&#xff0c;手上这份笔记正好覆盖第19到24讲。说实话&#xff0c;前半程学完SVD、最小二乘、四种基本子空间的时候&#xff0c;我觉得自己已经掌握了“矩阵方法”的全部家底&#xff0c;结果到了后半程才发现&#xff0c;那些分解和定理只是入场…

作者头像 李华
网站建设 2026/10/19 5:33:04

Spark SQL快速入门:调优、常用函数与UDF实践指南

最近我在重啃Spark SQL的快速入门&#xff0c;前面阶段还好&#xff0c;但到了第10到15节那部分&#xff0c;画风明显不一样了。这部分内容实际上是在讲三件事&#xff1a;调优、常用SQL函数、UDF开发。很多学习者也是从这一块开始产生明显的感受差异&#xff0c;SQL写得出来&a…

作者头像 李华
网站建设 2026/10/19 5:33:04

Spark SQL调优与UDF开发实战:从执行计划到数据倾斜

最近在补Spark SQL快速入门系列课程&#xff0c;正好刷到第10到15节&#xff0c;这几节把调优手段、常用SQL函数和UDF的开发串在一起看。以前用Spark SQL基本靠经验堆参数&#xff0c;数据量一上来就卡死&#xff0c;也不知道从哪看执行计划。学完这几节之后&#xff0c;我对“…

作者头像 李华