ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

用Agent Skill实现安全审计自动化:从原理到实战

用Agent Skill实现安全审计自动化:从原理到实战 最近两个月我一直在折腾 Agent Skill核心需求只有一个把安全审计这件事从“靠肉眼一行行读代码”变成“让 AI 按固定流程去扫”。结果越做越深security-audit-skill 从我手里一个实验性质的小脚本慢慢长成了我现在每天都会用的审计工具。如果你也在用 Claude Code、Codex、OpenCode 这类带 Skill 机制的 AI 编程环境或者你只是好奇“安全审计怎么和 Agent 结合”这篇文章应该能给你一份可以照着抄的作业。先说结论安全审计非常适合做成 Skill因为它有固定流程、有可枚举的检查项、有大量重复性劳动。把流程和规则固化进 Skill 之后AI 不再是一个只会聊天的上下文机器而是一个懂得“先看入口、再追数据流、最后出报告”的审计助手。下面我会从 Skill 的原理、目录设计、规则组织、实操流程到踩坑记录全部展开内容偏实践代码和目录结构可以直接复制去改。1. 先搞懂一件事Agent Skill 到底是什么1.1 Skill 不是插件也不只是一段 prompt我见过很多朋友对 Skill 有误解觉得它就是把一段很长的 prompt 塞给模型。实际上 Skill 更像是一套“岗位说明书 作业手册 工具包”的组合。在 Claude Code、Codex 这类 Agent 环境里Skill 通常是一个有固定结构的目录核心是 SKILL.md 文件。它告诉 Agent你什么时候该启用这个技能、启用之后按什么步骤干活、每一步要参考哪些文件、可以调用哪些脚本。和普通 prompt 最大的区别在于Skill 是一等公民可以被复用、被版本管理、被多个项目共享。你写好一个 security-audit-skill放在某个公共目录里以后任何项目都能加载它。打个比方普通 prompt 相当于你口头告诉实习生“去检查一下代码安全”实习生凭感觉发挥而 Skill 相当于你扔给他一本老师傅的笔记上面写着先看哪里、最常出问题的 50 个点是什么、每个问题怎么确认、报告格式怎么填。模型还是那个模型但有了这本笔记干活质量完全是两个级别。1.2 安全审计为什么天生适合 Skill 化安全审计是一个典型的“知识密集 流程固定 重复度高”的工作。一个合格的代码审计基本绕不开这几步先摸清项目用了什么框架和技术栈再找外部输入入口接着追踪数据流到危险函数最后判断是否可以利用。这套流程放在人身上需要几年经验才能形成肌肉记忆但如果把它变成规则文件模型很快就能按图索骥。而且安全审计里有大量机械性检查有没有硬编码密钥、依赖版本是否过低、是否调用了危险函数。这些事让 AI 去做速度比我快得多漏检率也低得多。我最初做这个 Skill 的动机很简单——不想再手动 grep 密钥了但后来发现它能做的事远超预期。另外安全审计的结果要求极度“结构化”问题等级、文件位置、风险类型、修复建议。这正好是模型擅长的输出格式。你给它一套模板它就能稳定地产出统一格式的报告这对后续跟踪修复非常有价值。2. security-audit-skill 的整体设计与目录结构2.1 一个能落地的 Skill 目录长什么样我自己的 security-audit-skill 目录结构如下你可以直接参考security-audit-skill/ ├── SKILL.md ├── rules/ │ ├── 01-injection.md │ ├── 02-authentication.md │ ├── 03-secrets-hardcoding.md │ ├── 04-dependency-management.md │ ├── 05-file-and-command.md │ └── 06-owasp-top10.md ├── prompts/ │ ├── audit-flow.md │ └── report-template.md ├── scripts/ │ ├── scan_secrets.sh │ ├── scan_python_sinks.py │ └── scan_node_sinks.js ├── examples/ │ ├── report-sample.md │ └── threat-model-sample.md └── references/ ├── cwe-list.md └── dependency-audit-commands.md每个目录都有明确用途rules 放检测规则prompts 放审计流程和报告模板scripts 放真正会执行的扫描脚本examples 放输出样例references 放模型需要查询的参考知识。这里有一个我踩出来的经验规则文件和提示词必须分开。如果把规则全部堆进 SKILL.md文件会变得很长Agent 在调用时上下文消耗严重而且不利于单独维护某条规则。分开之后SKILL.md 只负责“调度”具体知识在需要时按需读取。2.2 SKILL.md 怎么写元信息与触发逻辑SKILL.md 是整个 Skill 的入口Agent 首先要读它来决定是否启用这个技能所以开头的 description 设计非常关键。我最初的版本写得很含糊结果经常该触发时不触发。后来改成下面这样的结构命中率基本能到 90% 以上--- name: security-audit-skill description: 当用户要求进行代码安全审计、漏洞扫描、渗透测试辅助、安全代码评审、 依赖安全检查、密钥泄露排查时启用此技能。适用于 Python、JavaScript、 TypeScript、Java、PHP、Go 等项目。 --- # Security Audit Workflow 1. 识别项目技术栈和入口文件 2. 构建基础威胁模型 3. 按规则逐项扫描 4. 汇总分级并输出审计报告 5. 对确认的问题给出修复建议注意 description 里我写了多个触发场景安全审计、漏洞扫描、渗透测试辅助、安全代码评审。这样设计是因为不同用户表达习惯不一样有人说“帮我看看代码安全”有人说“扫一下有没有漏洞”还有人说“这个项目能做渗透测试吗”。Agent 靠语义匹配触发 Skill触发词越全命中率越高。至于 SKILL.md 里的工作流部分原则是“只写步骤不写细节”。细节都放在 prompts/audit-flow.md 里避免主文件过于臃肿。2.3 规则文件怎么组织按风险类型还是按技术栈规则文件的组织方式我纠结了很久。按风险类型分注入、认证、加密等的好处是通用性强任何语言都能用按技术栈分Python 规则、JavaScript 规则的好处是精确但维护成本直线上升。最终我采用混合方案通用规则放前面技术栈专属规则放在对应语言章节。比如 01-injection.md 里同时覆盖 SQL 注入、命令注入、模板注入但分语言给出不同的危险函数——Python 看 eval/exec/subprocessJavaScript 看 child_process/Function 构造器Java 看 Runtime.exec。每条规则文件内部也有固定格式这是我反复迭代后确定的## 风险类型 命令注入 ## 风险等级 高 ## 触发关键词 subprocess.call, subprocess.Popen, subprocess.run, os.system, eval, exec ## 验证方式 1. 找到触发关键词 2. 向上回溯 5 层函数调用 3. 确认参数是否来自外部输入request、body、query、files 4. 只有外部输入未经过滤到达危险函数才判定为漏洞 ## 修复建议 使用 shlex.quote 或参数数组形式禁止直接拼接 shell 命令这里最关键的是“验证方式”。模型看到 eval 就报漏洞那是新手水平真正合格的审计必须确认数据流从 source 到 sink 是否连通。我把这条验证逻辑写进规则就是逼着模型不要只看表面而是追踪调用链。2.4 脚本为什么必不可少规则文件能给模型知识但真正执行高频机械检查时脚本比模型更可靠、更快、更省 token。比如找硬编码密钥用正则脚本扫一遍比让模型逐个文件读要高效得多。我写了一个简单的密钥扫描脚本#!/bin/bash # scan_secrets.sh grep -rnEi \ --include*.py --include*.js --include*.ts \ --include*.java --include*.php --include*.go \ --include*.env* \ -e (api[_-]?key|secret|token|password|passwd|private[_-]?key)\s*[:]\s*[\][A-Za-z0-9_\-]{16,}[\] \ . 2/dev/null | head -100SKILL.md 里的工作流会指示 Agent先跑这个脚本拿到候选列表再对每一个候选用规则里的验证方式人工判断。脚本负责筛模型负责判两者配合比单纯让模型一个文件一个文件翻效率至少高出一倍。3. 审计流程与提示词设计从扫描到修复建议的完整闭环3.1 阶段一项目画像与威胁建模任何安全审计都不能上来就 grep那是无头苍蝇。我设计的流程第一步是“项目画像”先让 Agent 读取 README、package.json / requirements.txt / pom.xml 这类依赖清单识别项目类型、框架版本、核心功能。这个阶段不追求找漏洞而是要建立全局认知。项目画像完成后Agent 要输出一份简短的威胁建模结果。所谓威胁建模说白了就是回答三个问题这个系统接收哪些外部输入这些输入会流向哪里系统里最值钱的数据是什么举个例子如果你审一个 Flask 商城后端那么所有 route 函数里拿 request.args、request.json、request.files 的地方都是潜在输入点而 MySQL 查询、模板渲染、文件操作都是潜在出口。我把输入点和出口列出来后面审计就有明确方向了。威胁建模做得越完整后面的检查就越有的放矢。3.2 阶段二重点文件扫描与漏洞模式匹配第二阶段是真正干活的阶段。我会让 Agent 按规则目录逐项扫描每扫描一类风险就执行一次固定的循环用 grep 或脚本找出所有命中关键词的位置逐个读取上下文确认是否存在外部输入追踪数据流判断是否满足漏洞触发条件满足则记录到临时结果不满足就跳过并注明原因这里要特别注意优先级。代码扫描最忌讳“平均用力”我通常给 Agent 设置一条隐式规则优先审计路由处理函数、工具类、数据库操作类、文件上传下载模块、鉴权模块这五类文件。业务逻辑文件和配置文件次之。这样可以把有限的上下文窗口用在刀刃上。对需要深度追踪的文件我建议使用 ast-grep 这类结构化匹配工具辅助。模型可以直接读取文件片段但整段读取很费 token而且容易迷失在无关代码里。合理方式是先用 ast-grep 定位函数定义和调用关系再精准读取相关代码块。3.3 阶段三结果分级与报告输出审计结果必须分级这是行业共识也是报告是否有用的分水岭。我采用通用五级制Critical、High、Medium、Low、Info。但真正重要的不是标签而是判定逻辑。我在 prompts/audit-flow.md 里明确写了几条硬性标准Critical无条件可被远程利用且影响系统核心资产如直接命令执行、数据库拖库High需要一定前提才能利用但利用成本低如拼接 SQL 且参数可控、硬编码云厂商密钥Medium泄露敏感信息或需要管理员权限辅助才能利用Low代码不规范存在安全隐患但当前利用条件苛刻每一条审计结果我要求 Agent 按统一模板输出编号等级位置风险类型证据修复建议模板里的证据不能只写“调用了 eval”必须写清楚调用链从哪个输入点进来的、经过了哪些变量、最终在哪个文件第几行触发。这个要求看起来苛刻但效果立竿见影——报告直接可以发给开发团队他们照着证据就能定位问题。3.4 阶段四修复建议与回归验证审计报告只是第一步真正让 skill 有价值的是它能给出可落地的修复方案。我的做法是不只给建议而是尽量给出标准写法。比如 Python 代码里发现 SQL 拼接推荐修复方案是# 错误写法 cursor.execute(SELECT * FROM users WHERE username username ) # 推荐写法 cursor.execute(SELECT * FROM users WHERE username %s, (username,))再比如 Node.js 里发现 child_process.exec 拼接用户输入推荐修复方案是改用 execFile 加参数数组// 错误写法 exec(ls -la userInput, callback) // 推荐写法 execFile(ls, [-la, userInput], callback)回归验证是我后加的流程但非常值得做。修复完成后让 Agent 再跑一遍同一规则确认同类漏洞已经消失。这一步防止了“修了一个洞旁边还留着十个同款洞”的尴尬。4. 实操手记我在三个真实项目里跑这个 Skill 的效果4.1 项目 AFlask 商城后端第一个实战项目是一个小型 Flask 商城大约 8000 行代码。这项目我比较熟之前人工审过一轮所以拿来做对标测试。跑完第一版审计Skill 报告了 11 个问题其中我人工确认真正有效的是 8 个。最典型的两个问题是登录接口里直接把参数拼进 SQL以及一个管理后台接口使用 eval 处理配置项。这两条都属于 Critical 级别和人工审计发现完全一致。比较惊喜的是Skill 还发现了一个我人工漏掉的问题工具类函数里有个 base64 解码后直接 pickle.loads 的逻辑攻击者可以构造恶意序列化数据实现 RCE。这条我当时确实没想到说明规则文件覆盖做得越细越能查漏补缺。4.2 项目 BNode.js API 服务第二个项目是一个 Node.js API 服务特点是外部依赖特别多package.json 里满满的依赖项。这里 Skill 的价值主要体现在依赖审计联动上。我在 references/dependency-audit-commands.md 里预置了 npm audit、pip-audit、trivy 的常用命令。Agent 会在扫描阶段自动执行npm audit --json结果发现了一个 High 级别的原型污染漏洞对应依赖是某工具包的旧版本需要升级到 4.17.21 以上。另外脚本扫描密钥时发现 .env 文件被提交到了仓库而且里面包含真实的云厂商 AccessKey。这类问题人工审容易漏脚本扫基本一抓一个准。4.3 项目 C遗留 PHP 项目第三个项目是历史遗留的 PHP 项目代码量不小很多老式写法。这个项目让我意识到一个现实问题老项目里的安全问题太多如果全报反而让报告失去重点。第一次跑Skill 哗啦啦报了 40 多个问题但我和同事复核后真正能被利用的只有 60% 左右其他都是理论风险要么入口被封死要么利用条件极度苛刻。后来我给规则加了一条“可在利用条件中标记为 hard 的问题降级处理”的逻辑并且在报告中增加“无法确认利用链”的中间状态误报率明显降下来了。4.4 三条经验总结剥掉技术细节这三个项目给我留下几条印象很深的经验第一Skill 的规则越细越能挖出人工遗漏的问题第二脚本筛候选、模型做判断是最佳组合单靠一边都不行第三老项目要控制误报策略分级逻辑要允许“存疑”状态不要非黑即白。5. 常见问题与排查技巧实录5.1 Skill 没有触发或者触发了但行为不对最常遇到的问题就是 Skill 不生效。我排查过几次原因基本都出在 description 上。如果你发现 Agent 忽略了这个 Skill先检查 description 里的触发场景是否覆盖了用户的表达方式。比如用户说“帮我看看这段代码有没有安全问题”如果 description 里只有“安全审计”四个字模型可能就没反应过来。还有一个容易被忽略的点多个 Skill 可能同时命中Agent 会做优先级排序。如果你发现行为被别的 Skill 抢占可以在 SKILL.md 的 description 里加上“优先于通用代码审查类技能”这类表述或者调整 Skill 目录的加载顺序。5.2 误报太多怎么办误报高是所有静态审计工具的通病Skill 也一样。最有效的降误报手段是我前面反复强调的“验证方式必须包含数据流追踪”。只匹配关键词就是高误报必须确认外部输入能一路传到危险函数才算漏洞。如果误报还是高可以在规则里加一条“证据不足时标记为 Low 或存疑”而不是直接消掉。这样既保留线索又不干扰人工复核。我自己的标准是真正写进主报告的 High 及以上问题必须要有完整的 source-to-sink 调用链证据。5.3 上下文窗口不够用大型项目跑审计最怕的就是上下文爆掉。刚开始我让 Agent 一次性扫描整个项目目录结果跑到一半就懵了中间结果丢失报告残缺不全。后来我改成按模块分块扫描入口模块、认证模块、业务模块、工具模块每个模块单独跑一轮每轮产出一个小报告最后再汇总成本次审计主报告。中间过程保留在临时文件里不占上下文。实测下来即使 5 万行的项目也能稳定跑完整个流程。关键判断依据是“不重要的文件绝不整段读入上下文”只提取关键信息。5.4 如何持续维护规则库判断一个 security-audit-skill 好不好用关键是规则库是否持续更新。我会定期把新出现的公开漏洞类型、常见绕过手法、以及我审计中发现的未覆盖场景补充进 rules 目录。每新增一条规则都经过同类项目测试确保它真的能发现问题并且误报率可控。我还会在 references/cwe-list.md 里维护一个需重点关注清单把多年经验浓缩成列表比如不要在日志里输出敏感字段、不要用可逆算法存密码、不要信任前端传来的 role 字段、token 过期时间不要设 30 天以上。这些细节虽然不属于标准漏洞模型但实战价值非常高。最后说一点个人体会。我用 security-audit-skill 并不是为了取代安全工程师恰恰相反它是把安全工程师从重复劳动里解放出来把时间花在真正需要人类判断的地方业务逻辑漏洞、权限模型设计、以及那些规则库里还没有的未知攻击面。做这个 Skill 最深的感受是它的价值天花板不在模型参数大小而在于规则沉淀的厚度。你每踩过一个坑、每发现一个真实漏洞把它们总结成一条规则写回去这个 Skill 就会比之前更聪明一点。这件事越做越上瘾。
返回列表