把大模型塞进安全测试流程这件事,我从最早的"图一乐"到现在的"离不开",中间踩的坑足够写满一个笔记本。AI 辅助漏洞挖掘听起来很唬人,实际干起来你会发现,模型本身只占三成工作量,剩下七成全是工程:Prompt 怎么写得让模型说人话、本地模型怎么跑得不卡、靶场怎么搭得能反复重置、插件怎么配才不把机器拖死,以及最容易被新手忽略的——渗透测试合规规范这条线到底该划在哪儿。这篇内容就是把我这一整套流程完整摊开:从 Ollama 本地模型部署、Prompt 工程的分层设计、Docker 靶场的网络规划,到 Burp Suite 的 AI 插件配置和流量降采样策略,最后落到合规授权与报告交付。适合已经会基本 Web 安全测试、想把 AI 接进工作流的同行,也适合刚入门、想照着搭一套练手环境的朋友。全程实操为主,参数、计算过程、踩坑记录都给到,能直接抄。
1. 整体方案设计与思路拆解
1.1 为什么我坚持把模型放在本地跑
先说结论:只要你的测试对象不是纯公开的演示站点,模型就必须本地化。原因不复杂。安全测试过程中采集到的请求和响应里,塞满了目标系统的业务字段、内部路径、会话标识、错误堆栈,甚至偶尔会有用户数据。把这些原文丢给在线 API,等于把测试目标的资产特征做了一次外发,这在任何一份授权书的保密条款里都是过不去的。我见过有同行图省事直接用在线接口跑批量分析,后来在报告评审阶段被问"数据流向哪里",场面相当尴尬。
成本也是一方面。一次完整的业务系统测试,光被动流量就可能上万条请求,真正值得送进模型分析的按 10% 采样也有上千条。每条请求加上响应片段、上下文说明,prompt 轻松破千 token,一天下来几百万 token 是常态。本地跑,边际成本约等于电费。
可控性是第三点。本地模型可以随时换、随时回滚、随时改系统提示词,不用等版本更新,也不用担心某天接口规则一变、返回格式全乱。在离线环境或者内网隔离环境里做测试时,本地模型更是唯一选择。我给自己的硬性要求是:模型服务必须能在断网状态下完整跑通整条链路,包括靶场、采集、推理、报告生成。
1.2 三层解耦:靶场层、采集层、推理层
整套方案我拆成三层,彼此通过标准接口通信,任何一层挂了都不影响另外两层单独验证。
| 层级 | 职责 | 典型组件 | 故障影响面 |
|---|---|---|---|
| 靶场层 | 提供可反复重置的测试目标 | 容器编排 + 演练镜像 | 只影响练习,不影响真实项目 |
| 采集层 | 抓取、筛选、投递流量 | 代理工具 + AI 插件 | 影响吞吐与准确性 |
| 推理层 | 语义分析与结论输出 | 本地模型服务 + 自建脚本 | 影响分析质量 |
这样拆的好处非常实际。模型换版本时,我只需要重跑一批固定的历史样本做回归对比,靶场和插件完全不用动;靶场镜像升级时,推理层的提示词也不用改。早期我是把三者揉在一起的,写了一个大脚本从头跑到尾,结果任何一处出问题都要全部重来,调试成本高得离谱。
层与层之间我统一用 HTTP + JSON 通信。看起来土,但换任何语言、任何工具都能接,日志也好抓。你要是用消息队列做解耦当然更优雅,可一个人干活的时候,多一个中间件就多一个半夜会挂的东西。
1.3 先划合规线,再谈技术落地
这条我放在最前面讲,是因为顺序错了会出大事。技术方案再漂亮,测试范围没写清楚,做出来的东西也不能用。我在动手前会固定确认四件事:书面授权是否覆盖了目标域名和 IP 段、测试时间窗是否明确、允许使用的技术手段清单是否有排除项、数据留存和销毁的要求是什么。
授权书里我最关注的三个字段是目标范围、时间窗口和禁止动作。范围要精确到子域名级别,不能用"某某系统"这种模糊表述;时间窗口要精确到小时,因为有些业务有固定的大促或结算时段,那个时间点做任何可能影响可用性的测试都是自找麻烦;禁止动作里通常会有"不得使用自动化扫描器全量跑"这类限制,这时候你的 AI 辅助分析反而成了优势——它是逐条读流量,不是发包,天然温和。
还有一点很多人忽略:模型分析产生的中间文件也属于测试数据。我在项目目录里固定建一个evidence/,所有请求样本、模型输出、人工复核记录都放里面,项目结束后按约定统一清理,并保留清理记录。这件事不难,但很少有人的流程里真的写了。
2. Prompt 工程:让模型当审稿人,别当扫描器
2.1 四段式提示词骨架,把不确定性压到最低
新手最容易犯的错,是把整个 HTTP 请求原文往模型一扔,配一句"帮我看看有没有漏洞"。这么干的结果八成是一堆泛泛而谈的套话,或者是毫无根据的高危断言。问题不在模型,在你没给它任务边界。
我现在固定用四段式骨架:角色设定 → 上下文材料 → 判定任务 → 输出契约。四段的分工必须清晰,混在一起模型就会跑偏。
角色设定解决的是"用什么视角看"。比如"你是一名负责代码与流量双维度评审的安全工程师,你的职责是找出可被验证的风险点,而不是罗列所有理论可能性"。这句话里"可被验证"四个字很关键,它会显著压低天马行空的臆测。
上下文材料段落要给出足够的判定依据,通常包括:请求方法、完整 URL 路径、关键请求头(脱敏后)、参数结构与取值类型、响应状态码、响应体片段(截断到 1500 字符以内)、以及这条请求属于哪个业务模块的说明。最后这一项经常被省略,但它对准确率影响很大——告诉模型"这是订单查询接口",它对参数语义的判断会准确得多。
判定任务段落只写一件事:让它判断这条交互里是否存在值得人工复核的风险信号,并按风险类别归类。不要一次让它干三件事,比如既判断风险又给修复建议又写报告段落,那样每件事都做不深。
输出契约就是格式约束,下一节详细说。
2.2 强制结构化输出,别让模型自由发挥
自由文本输出在批量处理里是灾难,你没法解析,也没法做统计。我要求模型必须返回严格的 JSON,字段固定:
{ "risk_level": "high|medium|low|none", "category": "注入类|越权类|信息泄露类|配置类|无", "evidence": "引用请求或响应中的具体片段,不超过80字", "reason": "判定理由,不超过120字", "need_manual_review": true }几个细节值得说。evidence字段强制要求引用原文片段,这一条是抑制幻觉最有效的手段——模型编不出原文里没有的字符串,一旦它开始瞎编,这个字段就会露馅。need_manual_review是给自己留的缓冲,因为模型判 none 不代表真的没问题,判 high 也不代表真有问题,这个布尔值本质上是让模型自己表达置信度。
字段长度限制也不是随便定的。不加限制的话,reason动辄两三百字,批量跑一千条就是几十万 token 的浪费,而且长文本里更容易夹带无关内容。80 字和 120 字这两个数字是我试了七八个不同长度后定下来的,既能说清楚,又不啰嗦。
还有个小技巧:在提示词末尾追加一句"如果上下文不足以支撑判断,risk_level必须填 none,reason填写'上下文不足'"。这一句能把模型在信息缺失时硬编答案的概率压下去一大截。
2.3 三个降低误报的实操手法
手法一:给负样本。在少样本提示里,除了给两三个"确实有问题"的例子,我还会给一到两个"看起来可疑但实际正常"的例子。比如一个返回 200 且响应体里有 SQL 关键字的请求,实际只是因为参数名恰好叫order_by,属于正常排序字段。模型看到反例后,对"关键字出现即判定注入"这种粗暴逻辑会明显收敛。
手法二:二次裁决。对第一次判定为 high 的样本,我会用另一套更严格的提示词再跑一遍,这次的上下文给得更全(完整响应体 + 相邻请求),任务是"尝试否定上一条判定,如果无法否定则维持"。两次结论不一致的直接进入人工队列。这个流程会让总耗时增加大约 30%,但把误报率压下来一半以上,值。
手法三:按业务模块分组投递。同一个接口的多条请求打包成一批送进去,让模型横向对比参数取值的差异,比单条孤立分析准确得多。典型的越权问题就是同一个接口不同用户 ID 的响应体差异,单条看完全正常,放在一起看一目了然。实测下来,分组投递对越权类的召回提升最明显。
注意:分组投递时一定要控制单批的 token 总量,超过模型上下文窗口后它会把前面内容默默截断,而且不会报错。这是最阴险的坑之一,你以为分析了十条,其实它只看了后三条。
3. Ollama 本地模型部署与参数调优
3.1 硬件与模型选型,先算显存再选参数
选型逻辑很简单:显存决定参数量,参数量决定分析质量。我按量化等级 Q4_K_M 估算,经验公式是参数量(B) × 0.6 ≈ 所需显存(GB),再留 1.5~2GB 给上下文缓存。
| 硬件档位 | 可用显存 | 推荐参数规模 | 量化 | 上下文 | 适用场景 |
|---|---|---|---|---|---|
| 入门 | 8GB | 7B | Q4_K_M | 4K | 单条流量分析、提示词调试 |
| 主流 | 16GB | 14B | Q4_K_M | 8K | 分组投递、二次裁决 |
| 进阶 | 24GB | 32B | Q4_K_M | 8K~16K | 长响应体、代码审计辅助 |
| 纯 CPU | 32GB 内存 | 7B Q4 | — | 4K | 离线环境,吞吐约 3~5 tok/s |
纯 CPU 跑 7B 我实测过,能出结果,但吞吐低到只适合离线应急。如果你打算做批量分析,一张 16GB 的卡是性价比拐点,14B 模型在 Q4 量化下大概占 9~10GB,剩 6GB 左右给上下文,8K 窗口刚好够用。
模型的语言能力要单独测。有些小参数模型英文很强,中文输出会夹生,判定理由写得像机翻。我的做法是先拿 50 条标注好的样本跑一遍,看中文表达的流畅度和 JSON 格式的合规率,格式不合规率超过 5% 就直接换模型,别浪费时间调提示词。
3.2 安装与容器化启动
原生安装最省事,一条命令搞定,但版本升级和回滚比较麻烦。我更倾向容器化,环境隔离,配置文件挂载到宿主机,随时可以整体删掉重来。
# 拉取并启动本地模型服务,仅监听回环地址,避免暴露到局域网 docker run -d \ --name local-llm \ --gpus all \ -p 127.0.0.1:11434:11434 \ -v /data/llm:/root/.ollama \ --restart unless-stopped \ ollama/ollama:latest # 验证服务是否就绪 curl -s http://127.0.0.1:11434/api/tags端口绑定这一行必须写成127.0.0.1:11434:11434,不能图省事写-p 11434:11434。后者会把服务暴露到所有网卡,同一个局域网里任何人都能调用你的模型,轻则被蹭算力,重则变成数据外泄的通道。这个细节我在不止一个环境里见过被忽略。
拉模型和调参:
# 拉取模型 docker exec -it local-llm ollama pull <model-name>:14b # 交互式测试,确认模型能正常响应 docker exec -it local-llm ollama run <model-name>:14b "用一句话说明什么是HTTP响应头"模型名这里我用占位符,你按自己实际拉取的名称替换。注意不要在生产目录里反复pull不同版本,磁盘占用涨得很快,定期docker system df看一眼。
3.3 关键参数:温度、上下文窗口、输出长度
三个参数决定输出质量,值得反复调。
temperature我固定在 0.1~0.2。安全分析是判断题不是创作题,需要的是稳定性——同一条请求跑十次,结论应该一致。温度超过 0.5 后,我观察到同一样本的正反结论摇摆率明显上升。做提示词调试阶段可以临时调到 0.7 找灵感,定稿后必须降回来。
num_ctx(上下文窗口)是最容易被忽视的参数。默认值往往是 2048 或 4096,当你投递分组流量时,超出的部分会被静默截断。我统一设成 8192,配合 14B 模型刚好。设置方法是在 API 请求体里传options,或者用 Modelfile 固化。
num_predict(最大输出长度)设成 400 足够。我们的输出契约里所有字段加起来也就 300 字左右,设太大会让模型有空间啰嗦,反而拖慢速度。有次我忘了设,模型在reason里洋洋洒洒写了五百字,单条耗时翻了三倍。
# 通过 API 指定参数的一次完整调用 curl -s http://127.0.0.1:11434/api/generate -d '{ "model": "<model-name>:14b", "prompt": "你的四段式提示词放这里", "stream": false, "options": { "temperature": 0.15, "num_ctx": 8192, "num_predict": 400, "top_p": 0.9, "repeat_penalty": 1.1 } }'stream必须设成false。批量处理场景下流式输出没有任何意义,反而增加解析复杂度。repeat_penalty稍微给一点能减少模型在reason字段里重复同一句话的情况。
3.4 吞吐估算与批量处理脚本
这一步决定了你的流程能不能在项目周期内跑完,必须提前算。
以 14B Q4 模型在 16GB 显卡上为例,实测生成速度约 35~45 tok/s。单条请求平均消耗:prompt 约 1200 token,输出约 250 token。注意 prompt 的处理速度比生成快得多(通常是数倍),所以实际耗时主要由输出部分决定:250 ÷ 40 ≈ 6.3 秒/条,加上 prompt 处理约 2 秒,单条约 8 秒。
那么一天 8 小时不间断,单并发能处理 3600 条左右。如果你的项目有一万条流量需要分析,要么上两条并发(显存允许的话),要么老老实实做降采样。这就是为什么下一章要专门讲采样策略——永远不要试图分析全部流量。
批量处理脚本的核心结构是:读队列 → 拼提示词 → 调用 API → 解析 JSON → 失败重试 → 落盘。失败重试我设 2 次,间隔 3 秒。JSON 解析失败是最常见的失败类型,这时候不要简单重试同一提示词,而是追加一句"请只输出 JSON,不要输出任何解释文字"再重试,成功率会高很多。
import json, time, requests API = "http://127.0.0.1:11434/api/generate" MODEL = "<model-name>:14b" def analyze(prompt, retry=2): for attempt in range(retry + 1): try: r = requests.post(API, json={ "model": MODEL, "prompt": prompt, "stream": False, "options": {"temperature": 0.15, "num_ctx": 8192, "num_predict": 400} }, timeout=180) text = r.json().get("response", "").strip() # 剥离模型可能包上的 Markdown 代码块标记 if text.startswith("```"): text = text.strip("`") text = text[text.find("{"):] return json.loads(text) except Exception: if attempt == retry: return {"risk_level": "none", "reason": "解析失败", "need_manual_review": True} time.sleep(3)这段脚本看着简陋,但稳定。关键点在异常处理上——解析失败不要抛异常中断整个队列,而是记一条待人工复核,继续往下跑。批量任务最怕的就是半夜跑到第 800 条挂了,第二天起来还得从头来。
4. Docker 靶场搭建与网络隔离
4.1 靶场选型:按练习目标挑,别贪多
练手环境的选择取决于你要练什么。我一般准备三类:
第一类是综合 Web 演练镜像,覆盖注入、XSS、文件包含、越权等常见场景,适合验证整条链路是否通畅,也适合当模型的样本来源。第二类是 API 专项靶场,专门练 REST 接口的参数篡改和越权,这类和 AI 辅助分析结合度最高,因为接口返回的 JSON 结构规整,模型容易理解。第三类是自己写的小 Demo,故意留几个已知问题,用来做提示词回归测试——这是最有用的一类,因为答案是你自己定的,模型判得准不准一测便知。
我强烈建议搭第三类。找一个周末写个几百行的示例服务,故意在参数拼接、权限校验、错误回显三个地方留口子,然后把它的流量当黄金样本来调提示词。没有标准答案的话,你永远不知道自己是在优化还是在瞎调。
4.2 网络规划:让靶场只在宿主机可见
这是整个搭建环节里安全属性最强的一步。靶场镜像本身就是带漏洞的,绝对不能暴露到公网或者办公网。我的做法是建一个专用 bridge 网络,只做宿主机回环映射。
# 创建专用网络,指定子网避免和办公网段冲突 docker network create --driver bridge \ --subnet 172.28.0.0/24 \ lab-net子网选 172.28 段是因为 172.17 常被 Docker 默认网络占用,192.168 段又太容易和办公网撞车。撞车的后果很烦人:容器内访问外网时路由混乱,或者你在浏览器里打开某个地址结果跳到了同事的机器上。
端口映射的写法同样重要:
docker run -d --name lab-target \ --network lab-net \ -p 127.0.0.1:8080:80 \ --memory 512m --cpus 1.0 \ lab/target-image:latest127.0.0.1:这个前缀是硬性要求。--memory和--cpus限流也是必须的——有些演练镜像在收到大量请求时会疯狂吃内存,不限制的话宿主机直接卡死,我经历过一次,SSH 都连不上,只能强制重启。
4.3 用 compose 编排多容器靶场
真实的演练环境往往不止一个容器,可能还有数据库、缓存、反向代理。用 compose 编排,一次启动,方便重置。
services: web: image: lab/target-image:latest ports: - "127.0.0.1:8080:80" networks: [lab-net] depends_on: [db] mem_limit: 512m cpus: 1.0 db: image: lab/target-db:latest networks: [lab-net] environment: - TZ=Asia/Shanghai mem_limit: 768m networks: lab-net: external: true数据库不映射任何端口到宿主机,只在lab-net内部可达。这样即使宿主机上有其他服务在跑,也不会误连。external: true表示复用前面手动创建的网络,好处是网络的生命周期和容器解耦,docker compose down不会把网络一起删掉,重置时省一步。
4.4 一键重置与快照
演练靶场被玩坏是常态,用过几次数据库里全是脏数据,判定结果就不准了。我给自己写了个重置脚本,每次开始新一轮测试前跑一遍:
#!/bin/bash set -e docker compose down -v --remove-orphans docker compose up -d sleep 5 curl -s -o /dev/null -w "target status: %{http_code}\n" http://127.0.0.1:8080/-v参数会连数据卷一起删,这是关键——不加的话数据库里的旧数据还在,等于没重置。--remove-orphans清理掉 compose 文件里已经不存在的旧容器,防止端口冲突。
重置后一定要做一次健康检查(就是那行 curl),确认状态码正常再开始测试。我有一次没检查就开始跑批量分析,结果容器启动失败了,脚本老老实实分析了五十条 502 响应,白跑半小时。
5. AI 插件接入与流量降采样策略
5.1 插件配置的关键几项
Burp Suite 的 AI 助手插件(社区里习惯叫 BurpGPT)配置项不多,但每一项填错都会让你怀疑人生。核心是上游服务地址、模型名、超时时间、并发数四项。
上游服务地址填本地模型服务的兼容接口,通常是http://127.0.0.1:11434/v1。这里有个坑:容器化部署时,如果你的代理工具也跑在容器里,127.0.0.1指向的是容器自身而不是宿主机,得改成宿主机的内网地址或者用host.docker.internal。我建议代理工具直接跑在宿主机上,少一层网络转换少一类问题。
超时时间我设 180 秒。听起来很长,但本地 14B 模型在上下文吃满、显卡又有其他负载的时候,单次响应超过 60 秒是常有的事。设短了插件会不停超时重试,反而把模型队列堵死。
并发数必须是 1。这条我吃了大亏。早期设成 4,想着快一点,结果四条请求同时打到模型服务,显存直接爆掉,服务进程被系统杀掉,插件那边一片报错。本地模型服务和云端不一样,它没有弹性扩容,并发就是硬抗显存。
5.2 降采样:只把值得看的流量送进模型
前面算过吞吐,一天单并发 3600 条。真实项目流量远超这个量级,必须做筛选。我的筛选规则按优先级排:
第一优先,状态码异常。5xx、403、401、302 跳转到登录页的,全部送分析。这些是风险信号最密集的地方。
第二优先,参数值含特殊字符。引号、分号、尖括号、../、${、' or 1=1这类模式命中的请求,无论状态码是什么都送。
第三优先,响应长度异常。同一接口的历史响应长度中位数如果是 800 字节,某条响应突然变成 12000 字节,大概率是错误信息泄露或者数据越界返回。这个判断需要先跑一遍流量统计建立基线,值得花时间做。
第四优先,响应体含关键词。stack trace、SQL syntax、Exception、/home/、/var/www、root:等等。这一条容易误报,但成本低,可以放宽送。
剩下的普通 200 响应,只按接口维度采样——每个接口取前 3 条和后 3 条,中间的跳过。这样既覆盖了接口的通用形态,又不会把预算耗在重复流量上。
这套规则跑下来,我实测的送检比例大概在 8%~15%,一个中等规模项目两千条左右,单并发跑一晚上足够。
5.3 去重与指纹
降采样之后还要去重。同一个接口被调用两百次,参数结构一模一样,只是 ID 不同,分析一百遍结论都一样,纯浪费。
指纹的计算方式我用方法 + 路径(去掉数字段落)+ 参数名有序列表。比如/api/user/12345/detail?uid=1&type=2归一到/api/user/{id}/detail?type,uid。同一指纹只送一次,另外保留一条参数值样本用于展示差异。这个去重做完,通常还能再砍掉 40% 的量。
注意:去重时不要按参数值去重,只按参数结构。有些问题恰恰藏在罕见取值里,比如某个参数只在传空值时才出现越权,按值去重会把它筛掉。
6. 常见问题与排查实录
6.1 问题速查表
| 现象 | 最可能原因 | 排查动作 | 处理方式 |
|---|---|---|---|
| 插件请求全部超时 | 服务只监听回环,插件在容器内 | curl宿主机地址 vs 容器内地址 | 改上游地址为宿主机可达地址 |
| 模型返回空字符串 | num_predict太小或上下文溢出 | 看 API 返回的eval_count | 调大num_predict,缩小单批上下文 |
| 输出夹带大段解释文字 | 输出契约不够强硬 | 检查提示词末尾约束句 | 追加"只输出 JSON"并要求示例 |
| JSON 解析失败率高 | 模型包了代码块标记 | 看原始返回文本 | 脚本里做strip预处理 |
| 分析跑一半服务挂掉 | 显存溢出,被系统杀掉 | dmesg查看 OOM 记录 | 并发降到 1,缩短上下文 |
| 误报占比超过一半 | 上下文给太少或提示词太宽松 | 抽 20 条人工核对 | 加负样本,加"上下文不足返回 none" |
| 靶场容器起不来 | 端口被占用或子网冲突 | docker ps -a看退出码 | 换端口,检查 bridge 子网 |
| 靶场数据没重置 | down时没加-v | 检查数据卷 | 重置命令加-v |
6.2 几个只有踩过才知道的坑
坑一:模型对中文参数名的理解明显偏弱。早期我用中文写业务模块说明,模型对中文参数名的语义判断经常出错,把正常的搜索参数判成注入。后来改成"参数名 + 英文注释"的混合写法,准确率上来不少。如果你的目标系统参数名本身就是中文拼音缩写,建议在上下文里补一句这个参数的业务含义。
坑二:长响应体截断位置很关键。截取响应体时不要简单取前 1500 字符,因为很多错误堆栈在响应末尾。我的做法是取前 800 + 后 700,中间用省略标记断开。这个改动让错误信息泄露类的召回提升非常明显。
坑三:日志里别记完整 prompt。调试阶段我习惯把每次请求的完整 prompt 落盘,方便复现。后来发现这些日志文件单日能到几百 MB,而且里面全是未脱敏的原始流量。现在我只记 prompt 的哈希值和 token 数,需要复现时用哈希去原始样本库里找。
坑四:模型换版本必须跑回归。同一个模型的不同版本号,判定风格可能完全不一样。我维护了一个 200 条的黄金样本集,每个样本都有人工标注的正确结论,换模型前先跑一遍,看格式合规率和结论一致率。低于 85% 一致率的不上线。这个样本集是整个流程里最值钱的资产,比任何提示词模板都值得维护。
坑五:别指望模型发现逻辑越权。越权、业务流程绕过这类问题,本质上需要理解业务语义和权限模型,靠单条流量分析基本无效。模型的强项是识别模式化的风险信号——错误信息泄露、明显的注入特征、响应里多返回了不该返回的字段。把它的能力边界想清楚,期望值管理好,用起来才顺。我现在把模型定位成"初审员",它的产出是给人工复核排优先级,不是下结论。
7. 合规规范与报告交付
7.1 授权链条要闭环
动手前的授权确认,我列成一个固定清单,逐项打勾才开工:授权书是否由目标系统的权属方出具、授权范围是否精确到具体域名和 IP、测试时间窗是否写明、允许的技术手段是否列明、是否有明确的联系人、数据处置要求是否写明。这六项缺任何一项,我都不会开始实际测试。
特别说一下"允许的技术手段"。很多授权书里会写"禁止使用自动化扫描工具",这时候你要确认 AI 辅助流量分析算不算在内。我的做法是在项目启动沟通时就把方案讲清楚:不主动发包、只分析已产生的流量、分析过程在本地完成、不向任何第三方传输数据。这四点讲明白,绝大多数情况下对方都能接受,因为它比传统扫描器温和得多。
7.2 数据脱敏与留存
脱敏我做三件事:文本替换、结构保留、可逆映射单独存放。具体是指把身份证号、手机号、邮箱、真实姓名替换成占位符,但保持长度和格式不变(这样不影响模型对数据类型的判断),映射表加密后存在本地,项目结束后随证据目录一起销毁。
留存策略按项目定,但至少要保证两件事:原始流量和模型输出分开存放,销毁时有记录。我见过有团队把原始流量永久留着当"样本库",这在很多授权条款里是明确违规的,真要留必须先做彻底脱敏并取得书面同意。
7.3 报告里怎么写 AI 的产出
报告里我从不写"AI 发现某漏洞"这种表述。AI 的产出是线索,结论必须是人工复核过的。我的写法是:在附录里单独列一节"辅助分析记录",说明使用了本地模型对流量做了初审,列出初审标记为需复核的条目数、人工复核后确认的条目数、以及初审的误报情况。这种写法既体现了方法,又明确了责任归属在人工。
正文里每个确认的问题,都要有完整的复现路径:请求原文(脱敏后)、响应关键片段、判定依据、影响说明、修复建议。模型给的reason只能当参考,不能直接抄进报告——它的措辞往往太笼统,甲方看了会觉得你敷衍。
最后分享一个我在流程里固定加的小环节:每个项目结束后,把这次人工确认的问题样本,脱敏后回填到黄金样本集里。跑过五六个项目之后,你手里的样本集就会变成一套相当可靠的评测基准,后面无论换模型还是改提示词,都有客观参照。这件事没有捷径,只能一条条攒,但它是把"AI 辅助"从玩具变成工具的唯一路径。