使用 AI 做代码审计实战:从审计思路、提示词到落地流程一篇讲清
摘要
随着大模型能力的不断提升,AI 已经不再只是“帮我解释一段代码”或者“帮我写一个函数”的辅助工具,而是逐渐进入代码审计、安全评审、漏洞排查和研发质量治理等更复杂的工程场景。对于开发者和安全工程师来说,AI 代码审计并不是让模型“自动找漏洞”,而是把大模型作为一个高效的辅助分析器,用来提升阅读代码、梳理调用链、识别风险点、生成修复建议、补充测试用例和沉淀审计报告的效率。
本文将围绕“如何使用 AI 做代码审计”展开,系统介绍 AI 代码审计的适用场景、基本流程、提示词设计、常见漏洞审计方法、实战示例、审计报告写法、与传统 SAST 工具的结合方式,以及企业落地时需要关注的安全边界。文章不追求把 AI 神化,而是从真实工程实践出发,说明 AI 在代码审计中能做什么、不能做什么、应该怎么用、如何降低误报和漏报。适合开发人员、安全工程师、架构师、测试人员以及希望提升代码质量的技术负责人阅读。
关键词
AI代码审计、大模型、代码安全、SAST、漏洞分析、提示词工程、安全评审、研发质量
一、为什么要用 AI 做代码审计?
代码审计一直是软件安全和软件质量保障中的重要环节。传统代码审计通常依赖三类方式:
第一类是人工审计。安全工程师或资深开发人员手动阅读代码,结合业务逻辑、框架特性和安全经验判断是否存在漏洞。这种方式准确率较高,但非常依赖经验,效率也比较低。面对大型项目时,人工审计往往很难覆盖全部代码。
第二类是静态分析工具,也就是常说的 SAST。比如 SonarQube、Checkmarx、Fortify、Semgrep、CodeQL 等工具都可以对代码进行规则化扫描,自动发现 SQL 注入、路径穿越、硬编码密钥、不安全函数调用等问题。这类工具适合规模化扫描,但问题也很明显:误报较多、上下文理解有限、对业务逻辑漏洞识别能力不足。
第三类是动态测试和渗透测试。通过运行系统、构造输入、观察响应来发现问题。这类方式更贴近真实攻击面,但通常需要环境、数据和交互流程配合,且不一定能定位到具体代码原因。
AI 代码审计的出现,并不是要替代上述方法,而是给代码审计增加一个新的辅助层。大模型擅长阅读自然语言和代码,能够快速理解上下文、解释调用关系、总结风险点、生成修复建议。这些能力正好可以弥补传统工具在“理解代码意图”和“解释问题原因”方面的不足。
举个简单例子,传统扫描工具可能告诉你:
存在潜在 SQL 注入风险:userId 参数拼接到了 SQL 字符串中。
但 AI 可以进一步帮你分析:
该方法从 HTTP 请求参数中读取 userId,未进行类型校验,随后直接拼接到 SQL 语句中。
如果攻击者传入异常字符串,可能改变 SQL 查询语义。
建议使用参数化查询,并在进入 service 层之前校验 userId 是否为数字类型。
也就是说,AI 的价值不只是“发现问题”,更在于“解释问题、串联上下文、生成修复方案、沉淀审计文档”。
二、AI 代码审计适合哪些场景?
AI 代码审计适合的场景非常多,但并不是所有场景都适合完全依赖 AI。下面按实际工作中的常见需求进行分类。
1. 新项目接手时的安全摸底
当我们接手一个陌生项目时,通常需要快速了解:
- 项目使用什么技术栈;
- 入口文件在哪里;
- 权限认证怎么做;
- 数据库访问层在哪里;
- 外部接口调用在哪里;
- 文件上传、下载、导入导出功能在哪里;
- 是否存在定时任务、消息队列、异步任务等后台逻辑。
这些信息靠人工梳理需要较长时间,而 AI 可以快速阅读目录结构并生成项目安全画像。
示例提示词:
请以安全审计视角分析当前项目结构,重点关注:
1. 用户输入入口;
2. 身份认证和权限控制;
3. 数据库访问层;
4. 文件上传和文件下载;
5. 外部命令执行;
6. 第三方接口调用;
7. 可能涉及敏感信息的位置。
请先只读分析,不要修改任何代码。
2. 提交代码前的安全评审
在日常开发中,我们经常需要审查某次 Git diff 是否引入安全问题。AI 非常适合做这种“增量审计”。
示例提示词:
请审查当前 Git diff,重点关注是否引入以下问题:
1. 未授权访问;
2. 参数校验缺失;
3. SQL 注入;
4. 路径穿越;
5. 敏感信息泄露;
6. 日志打印敏感字段;
7. 异常处理不当。
请按“风险等级、问题位置、原因分析、修复建议”的格式输出。
这种用法非常适合和代码提交、Merge Request、Pull Request 流程结合。
3. 针对高危模块的专项审计
有些模块天然风险较高,例如:
- 登录认证;
- 权限校验;
- 文件上传;
- 文件下载;
- 支付回调;
- 订单状态流转;
- 管理后台;
- 数据导入导出;
- WebHook;
- OpenAPI;
- RPC 接口;
- 反序列化;
- 模板渲染;
- 命令执行;
- SSRF 相关请求转发。
这类模块即使用了扫描工具,也需要人工深入看业务逻辑。AI 可以帮助我们梳理调用链、识别输入输出边界、列出攻击面和修复建议。
4. 老旧系统安全治理
很多企业系统历史较长,代码风格不统一,缺少文档,开发人员也可能已经变动。安全治理时,最困难的是“没人说得清这个系统怎么跑”。
AI 在这里可以发挥很大作用:
- 自动生成模块说明;
- 梳理接口和数据库表关系;
- 识别重复代码和危险函数;
- 汇总硬编码配置;
- 帮助生成整改计划;
- 输出审计报告初稿。
5. 安全知识不足的开发团队
很多业务开发并不是安全专家。让每个开发者都熟练掌握所有漏洞原理并不现实,但可以把 AI 当作安全助手,让它在代码提交前做一轮辅助检查。
例如开发者可以在提交前输入:
请从安全角度检查我刚刚修改的代码,告诉我是否有明显风险。
如果有风险,请用开发者能理解的方式解释原因,并给出最小改动修复方案。
这并不能替代专业安全团队,但可以显著降低低级安全问题进入主干分支的概率。
三、AI 代码审计不能做什么?
在强调 AI 能力之前,必须先讲清楚边界。
AI 不是万能审计工具,也不是自动漏洞挖掘神器。它在代码审计中存在以下局限。
1. AI 可能误报
AI 有时会把理论上存在的问题判断成真实漏洞。例如看到字符串拼接就认为一定存在 SQL 注入,但实际上参数可能在上游已经做了严格白名单校验。
因此,AI 给出的结论必须经过人工确认。
2. AI 可能漏报
AI 的上下文有限,尤其是在没有完整项目、没有运行环境、没有数据库结构、没有配置文件的情况下,可能看不到关键风险点。
例如权限校验可能在 AOP、Filter、Interceptor、网关或配置文件中完成。如果模型只看 Controller,就可能误判。
3. AI 不理解全部业务语义
很多业务逻辑漏洞并不是代码语法问题,而是业务规则问题。例如:
- 优惠券重复领取;
- 订单越权查看;
- 审批流程绕过;
- 退款金额大于支付金额;
- 用户可以修改不属于自己的资源;
- 状态机流转缺少约束。
这些问题需要业务背景。AI 可以帮助分析,但前提是我们要提供足够的业务规则说明。
4. AI 不应该直接操作生产代码
如果使用 Agent 类工具做代码审计,一定要避免让 AI 在未确认的情况下直接修改重要代码。尤其不能在生产环境、生产服务器、敏感仓库中使用自动执行模式。
正确方式是:
- 先只读分析;
- 输出审计结论;
- 人工确认问题;
- 再让 AI 给修复建议;
- 最后由开发者审查 diff 并提交。
四、AI 代码审计的标准流程
一个比较稳妥的 AI 代码审计流程可以分为七步。
第一步:明确审计目标
不要一上来就说:
帮我审计这个项目。
这个提示太宽泛,AI 很容易泛泛而谈。
更好的方式是明确范围:
请审计用户登录和权限校验相关代码,重点关注:
1. 是否存在认证绕过;
2. 是否存在越权访问;
3. Token 校验是否完整;
4. 登录失败处理是否安全;
5. 是否存在敏感信息泄露。
请先输出审计思路,再开始分析。
审计目标越明确,结果越可用。
第二步:让 AI 先梳理结构
在分析漏洞前,先让 AI 理解项目。
请先阅读项目结构,找出与认证、权限、用户管理相关的文件。
暂时不要判断漏洞,只输出相关文件列表和作用说明。
这样可以避免模型过早下结论。
第三步:识别输入入口
代码审计的核心是数据流。用户输入从哪里进入系统?经过哪些处理?最后流向哪里?
常见输入入口包括:
- HTTP 请求参数;
- Header;
- Cookie;
- JSON Body;
- 文件上传内容;
- URL path variable;
- 消息队列消息;
- 定时任务读取的数据;
- 第三方回调参数;
- RPC 入参;
- 命令行参数;
- 配置文件;
- 环境变量。
提示词:
请找出当前模块所有外部输入入口,并整理为表格:
字段包括:入口位置、参数名称、来源、后续调用链、最终流向、是否有校验。
第四步:跟踪危险流向
危险流向通常包括:
- SQL 查询;
- 文件路径;
- 系统命令;
- 模板渲染;
- 反序列化;
- HTTP 请求转发;
- 日志输出;
- 响应输出;
- 权限判断;
- 加密解密;
- 反射调用。
提示词:
请跟踪这些用户输入最终流向哪些敏感操作,例如 SQL、文件系统、命令执行、HTTP 请求、模板渲染和日志输出。
如果发现风险,请说明完整数据流。
第五步:判断是否有防护
不能只看危险函数,还要看是否存在防护措施。例如:
- 是否有参数化查询;
- 是否有白名单;
- 是否有鉴权;
- 是否有权限校验;
- 是否有路径规范化;
- 是否限制文件类型;
- 是否限制文件大小;
- 是否过滤敏感日志;
- 是否有 CSRF 防护;
- 是否有重放保护;
- 是否校验签名。
提示词:
请不要只根据危险函数下结论。
请同时检查是否存在有效防护,例如白名单、参数化查询、权限校验、路径规范化和签名校验。
最后再判断风险是否成立。
第六步:输出审计结论
建议要求 AI 按固定格式输出,方便后续整理报告。
请按以下格式输出审计结果:
## 问题 1:标题
- 风险等级:
- 影响位置:
- 问题描述:
- 触发条件:
- 数据流:
- 影响范围:
- 修复建议:
- 是否需要人工确认:
第七步:生成修复建议和测试用例
审计不是为了“指出问题”,而是为了“解决问题”。好的审计流程应该包含修复方案和验证方式。
请针对上述问题给出最小改动修复方案,并补充对应的单元测试思路。
注意不要改变现有接口行为。
五、常见漏洞类型的 AI 审计方法
下面从常见风险类型出发,说明如何使用 AI 辅助审计。
1. SQL 注入审计
SQL 注入是最常见的输入流向数据库风险。AI 审计时需要关注:
- 是否存在字符串拼接 SQL;
- 是否使用参数化查询;
- ORM 是否正确绑定参数;
- 排序字段、表名、列名是否可控;
- MyBatis
${}和#{}是否混用不当; - 是否存在动态 SQL 拼接;
- 是否有白名单校验。
示例提示词:
请审计当前项目中的数据库查询代码,重点关注 SQL 注入风险。
请特别检查:
1. 字符串拼接 SQL;
2. MyBatis XML 中的 ${};
3. 动态 order by;
4. 动态表名或字段名;
5. 原生 SQL 查询;
6. 参数是否经过白名单校验。
容易被忽略的是 order by 场景。例如:
String sql = "select * from user order by " + sortField;
即使 sortField 不是普通查询条件,也可能改变 SQL 语义。修复方式通常是白名单映射:
private static final Map<String, String> SORT_FIELD_MAP = Map.of(
"name", "name",
"createdTime", "created_time",
"id", "id"
);
String column = SORT_FIELD_MAP.get(sortField);
if (column == null) {
throw new IllegalArgumentException("Invalid sort field");
}
String sql = "select * from user order by " + column;
这里不能简单使用参数占位符替代表名或列名,因为数据库参数化通常只适用于值,不适用于 SQL 结构。因此 AI 审计时必须让它区分“值参数”和“结构参数”。
2. 越权访问审计
越权是业务系统中最常见、也最容易漏掉的问题。它不是语法漏洞,而是权限逻辑漏洞。
常见越权类型包括:
- 用户 A 查看用户 B 的订单;
- 普通用户访问管理员接口;
- 子账号操作主账号资源;
- 租户 A 访问租户 B 数据;
- 只校验登录,不校验资源归属;
- 前端隐藏按钮,但后端没有校验;
- 接口只根据传入 userId 查询数据。
提示词:
请审计当前接口是否存在越权访问风险。
重点关注:
1. Controller 是否从请求参数中直接接收 userId、tenantId、orgId;
2. Service 层是否校验资源归属;
3. 是否只判断登录状态,没有判断操作权限;
4. 管理员接口是否有角色校验;
5. 多租户数据查询是否强制带租户条件。
典型风险代码:
@GetMapping("/order/detail")
public Order getOrder(@RequestParam Long orderId) {
return orderService.getById(orderId);
}
如果这里没有判断订单是否属于当前用户,就可能存在越权。
修复示例:
@GetMapping("/order/detail")
public Order getOrder(@RequestParam Long orderId) {
Long currentUserId = SecurityContext.getCurrentUserId();
return orderService.getByIdAndUserId(orderId, currentUserId);
}
AI 审计时要注意,权限校验可能不在当前方法里,而在注解、拦截器、AOP 或网关中。因此提示词中要明确要求它查找全局鉴权机制。
3. 文件上传审计
文件上传是高危功能。AI 审计时应关注:
- 是否限制文件大小;
- 是否校验扩展名;
- 是否校验 MIME Type;
- 是否校验真实文件内容;
- 是否使用随机文件名;
- 是否允许覆盖已有文件;
- 是否上传到 Web 可执行目录;
- 是否支持压缩包上传;
- 是否存在 Zip Slip;
- 是否对图片进行安全处理;
- 是否存储原始文件名;
- 是否记录上传者和访问权限。
提示词:
请审计文件上传功能,重点关注:
1. 文件类型校验是否可靠;
2. 文件名是否可控;
3. 保存路径是否可控;
4. 是否限制文件大小;
5. 是否可能上传可执行脚本;
6. 是否可能覆盖已有文件;
7. 是否存在压缩包路径穿越风险。
典型风险代码:
String fileName = file.getOriginalFilename();
file.transferTo(new File(uploadDir + "/" + fileName));
风险点包括:
fileName可能包含路径;- 可能覆盖已有文件;
- 文件扩展名可伪造;
- 可能上传到可访问目录。
更安全的处理方式:
String originalName = file.getOriginalFilename();
String ext = getSafeExtension(originalName);
if (!ALLOWED_EXTENSIONS.contains(ext)) {
throw new IllegalArgumentException("Unsupported file type");
}
String safeName = UUID.randomUUID().toString() + "." + ext;
Path target = Paths.get(uploadDir).resolve(safeName).normalize();
if (!target.startsWith(Paths.get(uploadDir))) {
throw new SecurityException("Invalid upload path");
}
file.transferTo(target.toFile());
AI 可以帮助识别这类问题,但最终仍需要结合实际部署方式判断风险。例如文件上传到对象存储和上传到 Web 根目录,风险是不一样的。
4. 文件下载与路径穿越审计
文件下载经常出现路径穿越问题。典型风险是用户可以通过参数控制文件路径。
风险代码:
@GetMapping("/download")
public void download(String fileName, HttpServletResponse response) throws IOException {
File file = new File(baseDir + "/" + fileName);
Files.copy(file.toPath(), response.getOutputStream());
}
如果用户传入特殊路径,可能读取非预期文件。
提示词:
请审计文件下载接口是否存在路径穿越风险。
重点关注:
1. 用户是否可以控制文件名或路径;
2. 是否进行了路径 normalize;
3. 是否校验最终路径必须位于 baseDir 内;
4. 是否允许下载任意后缀;
5. 是否有权限校验。
安全写法:
Path basePath = Paths.get(baseDir).toAbsolutePath().normalize();
Path targetPath = basePath.resolve(fileName).normalize();
if (!targetPath.startsWith(basePath)) {
throw new SecurityException("Invalid file path");
}
这里的关键点是:不能只过滤字符串中的 ../,而应该进行路径规范化后判断最终路径是否仍在允许目录下。
5. 命令执行审计
命令执行风险通常出现在系统运维、文件转换、视频处理、压缩解压、脚本调用等场景。
风险代码:
Runtime.getRuntime().exec("ping " + host);
如果 host 来自用户输入,就可能导致命令参数被污染。
提示词:
请审计项目中所有系统命令执行点,重点关注:
1. Runtime.exec;
2. ProcessBuilder;
3. shell 脚本调用;
4. Python subprocess;
5. Node.js child_process;
6. 用户输入是否进入命令参数;
7. 是否使用白名单限制。
建议修复方式:
- 避免调用 shell;
- 使用参数数组;
- 对参数做白名单;
- 限制命令范围;
- 不允许用户控制完整命令;
- 使用专门库替代系统命令。
例如:
ProcessBuilder pb = new ProcessBuilder("ping", "-c", "4", host);
同时还要校验 host:
if (!host.matches("^[a-zA-Z0-9.-]+$")) {
throw new IllegalArgumentException("Invalid host");
}
AI 在审计命令执行时很有帮助,因为它可以全局搜索危险 API,并分析参数来源。
6. SSRF 审计
SSRF 通常发生在服务端根据用户输入发起 HTTP 请求的场景,例如:
- 图片抓取;
- URL 预览;
- WebHook;
- 文件导入;
- 代理转发;
- 第三方接口回调测试;
- PDF 转换;
- 远程资源下载。
提示词:
请审计项目中所有服务端 HTTP 请求发起点,重点关注 SSRF 风险。
请检查:
1. URL 是否来自用户输入;
2. 是否限制协议为 http/https;
3. 是否禁止访问内网地址;
4. 是否处理重定向;
5. 是否校验 DNS 解析结果;
6. 是否存在代理转发接口;
7. 是否限制响应大小和超时时间。
常见风险代码:
String url = request.getParameter("url");
String result = restTemplate.getForObject(url, String.class);
安全修复思路包括:
- 只允许访问白名单域名;
- 禁止访问内网 IP;
- 禁止 file、gopher 等非预期协议;
- 限制重定向;
- DNS 解析后检查 IP;
- 设置超时;
- 限制响应大小;
- 不返回完整错误信息。
这里要注意,SSRF 的安全校验比较复杂,AI 给出的修复代码需要人工仔细审查。
7. 敏感信息泄露审计
敏感信息泄露包括:
- 代码中硬编码密码;
- 日志打印 token;
- 返回接口包含手机号、身份证、银行卡;
- 异常堆栈直接返回前端;
- 配置文件泄露密钥;
- Git 历史中存在 secret;
- 测试数据包含真实用户信息。
提示词:
请审计项目中可能存在的敏感信息泄露问题。
重点关注:
1. 配置文件中的密钥;
2. 日志中打印密码、token、cookie、身份证、手机号;
3. 接口响应是否返回过多用户信息;
4. 异常信息是否直接暴露;
5. 测试文件中是否包含真实凭据。
常见风险代码:
log.info("login request: {}", loginRequest);
如果 loginRequest 中包含密码,就可能泄露。
更好的方式:
log.info("login request username={}", loginRequest.getUsername());
或者对敏感字段脱敏:
log.info("user phone={}", maskPhone(phone));
AI 很适合做这类审计,因为它可以帮助我们从大量代码中找出日志打印和配置项。
8. 反序列化审计
反序列化风险在 Java、PHP、Python、Node.js 等语言中都可能出现。审计时要关注:
- 是否反序列化不可信输入;
- 是否使用危险库;
- 是否允许动态类型;
- 是否存在 gadget 链依赖;
- 是否有签名校验;
- 是否限制类型白名单。
提示词:
请审计项目中所有反序列化相关代码,重点关注:
1. Java ObjectInputStream;
2. Fastjson、Jackson 多态类型;
3. Python pickle;
4. PHP unserialize;
5. Node.js serialize/deserialize;
6. 反序列化数据是否来自用户输入;
7. 是否有类型白名单和签名校验。
这类问题往往和依赖版本、配置方式强相关。AI 可以帮助定位风险点,但最终判断要结合依赖版本和运行配置。
六、AI 代码审计提示词模板
下面给出一些可以直接复制使用的提示词模板。
1. 项目安全画像模板
你现在是一名代码安全审计工程师。
请以只读方式分析当前项目,输出项目安全画像。
要求:
1. 判断项目技术栈;
2. 找出主要入口文件;
3. 梳理认证和权限控制机制;
4. 找出数据库访问层;
5. 找出文件上传、下载、导入导出功能;
6. 找出外部 HTTP 请求调用点;
7. 找出系统命令执行点;
8. 找出配置文件和敏感信息位置;
9. 不要修改任何文件;
10. 输出后给出下一步审计建议。
2. Git Diff 审计模板
请审计当前 Git diff,判断本次改动是否引入安全风险。
重点关注:
1. 权限校验是否缺失;
2. 用户输入是否进入 SQL、文件路径、命令、HTTP 请求;
3. 是否新增敏感日志;
4. 是否新增硬编码密钥;
5. 是否新增不安全依赖;
6. 是否改变认证逻辑;
7. 是否改变数据权限范围。
输出格式:
- 风险等级
- 文件位置
- 问题描述
- 成立条件
- 修复建议
- 是否需要人工确认
3. 接口越权审计模板
请审计当前模块的接口越权风险。
请逐个接口分析:
1. 接口路径;
2. 是否需要登录;
3. 是否需要角色权限;
4. 是否校验资源归属;
5. 是否直接使用用户传入的 userId、tenantId、orgId;
6. 是否存在水平越权;
7. 是否存在垂直越权;
8. 修复建议。
请不要只看 Controller,也要检查 Service、DAO、注解、拦截器和 AOP。
4. 数据流审计模板
请对以下参数进行数据流分析:
参数名称:xxx
入口位置:xxx
请分析:
1. 参数从哪里进入;
2. 经过哪些函数;
3. 是否经过校验;
4. 最终流向哪里;
5. 是否进入敏感操作;
6. 风险是否成立;
7. 如果成立,如何修复。
5. 审计报告生成模板
请根据以上审计结果生成一份正式代码审计报告。
报告结构:
1. 审计背景;
2. 审计范围;
3. 审计方法;
4. 风险总览;
5. 问题详情;
6. 修复建议;
7. 复测建议;
8. 总结。
要求语言正式、客观,适合提交给研发团队和项目负责人。
七、AI 与传统安全工具如何结合?
AI 代码审计不是替代 SAST,而是和 SAST 形成互补。
一个推荐流程是:
1. 先用 SAST 做全量扫描
使用 SonarQube、Semgrep、CodeQL 等工具先做全量扫描,得到初步风险列表。
2. 再让 AI 分析扫描结果
把扫描结果交给 AI,让它帮助分类:
请分析这份 SAST 扫描结果,帮我完成:
1. 去除明显误报;
2. 按风险等级排序;
3. 合并重复问题;
4. 判断哪些问题需要优先修复;
5. 为每类问题给出修复建议。
3. 对高危问题做人工确认
高危问题必须人工确认,尤其是:
- 认证绕过;
- 越权;
- SQL 注入;
- 任意文件读取;
- 命令执行;
- SSRF;
- 敏感信息泄露;
- 供应链风险。
4. 让 AI 生成修复代码
确认问题成立后,可以让 AI 生成最小改动方案。
这个问题确认成立。
请给出最小改动修复方案,要求:
1. 不改变接口协议;
2. 不影响现有业务逻辑;
3. 补充单元测试;
4. 说明修复前后的行为差异。
5. 再用测试和扫描工具复测
修复后不能只相信 AI,需要重新运行:
- 单元测试;
- 集成测试;
- SAST 扫描;
- 关键接口手工验证;
- 安全回归测试。
八、AI 代码审计实战示例
假设有如下 Java Controller:
@RestController
@RequestMapping("/api/report")
public class ReportController {
@GetMapping("/download")
public void download(@RequestParam String fileName,
HttpServletResponse response) throws IOException {
String baseDir = "/data/reports/";
File file = new File(baseDir + fileName);
response.setHeader("Content-Disposition", "attachment; filename=" + fileName);
Files.copy(file.toPath(), response.getOutputStream());
}
}
我们可以给 AI 的提示词是:
请审计这段文件下载代码,判断是否存在安全风险。
请从用户输入、文件路径、权限校验、响应头、安全修复几个角度分析。
AI 应该能识别出以下问题:
fileName来自用户输入;- 直接拼接到文件路径;
- 没有路径规范化;
- 没有判断最终文件是否位于
/data/reports/下; - 没有权限校验;
- 响应头中直接使用原始文件名,可能存在响应头注入风险;
- 未处理文件不存在和异常情况。
更安全的修复示例:
@RestController
@RequestMapping("/api/report")
public class ReportController {
private static final Path BASE_DIR = Paths.get("/data/reports/").toAbsolutePath().normalize();
@GetMapping("/download")
public void download(@RequestParam String fileName,
HttpServletResponse response) throws IOException {
if (fileName == null || fileName.contains("\r") || fileName.contains("\n")) {
throw new IllegalArgumentException("Invalid file name");
}
Path targetPath = BASE_DIR.resolve(fileName).normalize();
if (!targetPath.startsWith(BASE_DIR)) {
throw new SecurityException("Invalid file path");
}
if (!Files.exists(targetPath) || !Files.isRegularFile(targetPath)) {
throw new FileNotFoundException("File not found");
}
String safeDownloadName = targetPath.getFileName().toString();
response.setHeader(
"Content-Disposition",
"attachment; filename=\"" + safeDownloadName.replace("\"", "") + "\""
);
Files.copy(targetPath, response.getOutputStream());
}
}
不过这还不是最终答案。实际项目中还应该继续确认:
- 当前用户是否有权限下载该报表;
- 报表文件是否与用户、部门、租户绑定;
- 是否应该通过文件 ID 查询数据库,而不是直接传文件名;
- 是否需要审计日志;
- 是否限制下载频率;
- 是否需要对敏感报表加水印或脱敏。
这就是 AI 代码审计的重要原则:AI 可以快速发现技术风险,但业务安全需要结合真实业务规则判断。
九、如何降低 AI 审计误报?
AI 审计误报不可避免,但可以通过方法降低。
1. 提供完整上下文
不要只给一个函数,尽量提供:
- Controller;
- Service;
- DAO;
- 配置;
- 权限注解;
- 拦截器;
- 数据库表结构;
- 业务规则。
上下文越完整,AI 判断越准确。
2. 要求 AI 说明“成立条件”
不要让 AI 只输出“存在漏洞”,而要让它说明漏洞成立需要哪些条件。
请不要直接下结论。
对于每个风险,请说明:
1. 风险成立需要哪些前提条件;
2. 当前代码中哪些证据支持该判断;
3. 还缺少哪些信息需要人工确认。
3. 要求区分“疑似风险”和“确认风险”
请将问题分为两类:
1. 已确认风险:根据当前代码可以确认成立;
2. 疑似风险:需要更多上下文或运行环境确认。
4. 让 AI 做反向验证
请尝试反驳你刚才的漏洞判断。
如果代码中存在防护措施,请指出。
如果证据不足,请降低风险等级。
这个方法非常实用,可以减少 AI 过度自信。
十、如何降低 AI 审计漏报?
1. 分模块审计
不要一次性让 AI 审计整个大型项目。可以按模块拆分:
- 登录模块;
- 用户模块;
- 权限模块;
- 文件模块;
- 支付模块;
- 管理后台;
- 数据导入导出模块。
2. 按漏洞类型审计
同一个模块可以多轮审计:
第一轮看越权;
第二轮看 SQL 注入;
第三轮看文件风险;
第四轮看日志和敏感信息;
第五轮看异常处理。
3. 结合搜索关键词
可以让 AI 搜索危险函数和关键字:
请在项目中搜索以下关键词,并分析是否存在安全风险:
Runtime.exec
ProcessBuilder
ObjectInputStream
@RequestParam
MultipartFile
RestTemplate
WebClient
FileInputStream
FileOutputStream
createNativeQuery
${}
4. 使用清单化方法
代码审计最好有 checklist。AI 很适合按照清单逐项检查。
示例:
请按照以下 checklist 审计当前模块:
1. 是否有身份认证;
2. 是否有权限校验;
3. 是否校验资源归属;
4. 是否校验输入参数;
5. 是否存在危险函数;
6. 是否打印敏感日志;
7. 是否正确处理异常;
8. 是否有单元测试覆盖;
9. 是否有审计日志;
10. 是否符合最小权限原则。
十一、企业落地 AI 代码审计的建议
如果是在企业内部推广 AI 代码审计,不能只靠个人习惯,而应该形成流程。
1. 建立统一提示词模板
安全团队可以沉淀一套标准模板,例如:
- Java Web 审计模板;
- Spring Boot 权限审计模板;
- MyBatis SQL 审计模板;
- 文件上传审计模板;
- 前端安全审计模板;
- Python Flask 审计模板;
- Node.js Express 审计模板;
- Go Gin 审计模板。
这样开发人员不用自己写提示词,只需要套用模板即可。
2. 建立安全规则库
把企业内部常见问题整理成规则:
- Controller 不允许直接信任 userId;
- 所有下载必须基于文件 ID;
- 管理接口必须带角色注解;
- 日志不允许打印 token;
- SQL 排序字段必须白名单;
- 文件上传必须走统一组件;
- 外部 URL 请求必须经过 SSRF 防护组件。
然后让 AI 按规则库审计。
3. 接入代码评审流程
可以在 Pull Request 中增加 AI 审计环节:
- 开发提交代码;
- CI 运行测试和 SAST;
- AI 分析 diff 和扫描结果;
- 输出安全审查评论;
- 安全人员或负责人确认;
- 合并代码。
4. 保留人工最终决策
AI 可以提出建议,但不应该拥有最终合并权限。尤其是安全问题的风险等级、修复优先级和是否上线,必须由人来判断。
5. 注意代码和数据安全
企业使用 AI 审计时必须关注:
- 是否允许代码上传到外部模型;
- 是否包含商业机密;
- 是否包含客户数据;
- 是否包含密钥;
- 是否需要私有化部署;
- 是否需要脱敏;
- 是否符合合规要求。
如果项目敏感,应优先考虑内网模型、私有化模型或本地审计工具。
十二、AI 代码审计报告怎么写?
一份好的代码审计报告不应该只是漏洞列表,而应该让研发团队知道问题在哪里、为什么危险、怎么修、如何验证。
推荐结构如下。
1. 审计背景
说明为什么做本次审计,例如:
本次审计针对 XX 系统近期版本变更进行安全评估,重点关注用户权限、文件处理、数据库访问和敏感信息保护等方面,目的是在上线前识别潜在安全风险。
2. 审计范围
列出审计模块:
审计范围包括:
1. 用户登录模块;
2. 订单查询模块;
3. 报表下载模块;
4. 管理后台接口;
5. 文件上传功能。
3. 审计方法
说明使用了哪些方式:
本次审计采用人工代码阅读、AI 辅助分析、静态扫描结果复核、关键调用链追踪等方式,对高风险接口进行重点检查。
4. 风险总览
可以用表格:
| 序号 | 风险名称 | 等级 | 影响模块 | 状态 |
|---|---|---|---|---|
| 1 | 报表下载存在路径穿越风险 | 高 | 报表模块 | 待修复 |
| 2 | 订单详情接口缺少资源归属校验 | 高 | 订单模块 | 待确认 |
| 3 | 登录日志打印敏感参数 | 中 | 登录模块 | 待修复 |
5. 问题详情
每个问题按固定格式写:
## 问题 1:报表下载存在路径穿越风险
- 风险等级:高
- 影响位置:ReportController.download
- 问题描述:接口直接使用用户传入的 fileName 拼接本地文件路径,未进行路径规范化和目录边界校验。
- 风险影响:攻击者可能尝试读取非预期目录下的文件。
- 修复建议:
1. 使用 Path.resolve 和 normalize;
2. 判断最终路径必须位于报表目录下;
3. 使用文件 ID 查询数据库,不直接暴露文件名;
4. 增加用户权限校验。
- 复测建议:构造异常文件名,验证接口是否拒绝访问。
6. 总结
总结整体风险:
本次审计发现系统整体权限控制框架较完整,但在部分业务接口中仍存在资源归属校验不足的问题。建议后续统一封装权限校验组件,并将文件上传下载、外部 URL 请求等高风险能力收敛到公共安全组件中。
十三、AI 代码审计的最佳实践
结合实际使用经验,建议遵守以下原则。
1. 不要让 AI 直接得结论
先让它梳理结构,再找入口,再分析数据流,最后判断风险。
2. 不要一次审计太大范围
大型项目要拆模块、拆漏洞类型、拆调用链。
3. 不要只问“有没有漏洞”
要问:
- 输入从哪里来;
- 有没有校验;
- 流向哪里;
- 防护是否有效;
- 风险成立条件是什么;
- 缺少哪些证据;
- 如何修复;
- 如何复测。
4. 不要忽视业务逻辑
AI 不知道你的真实业务规则。越权、支付、审批、订单、优惠券、退款等场景必须补充业务背景。
5. 不要跳过复测
修复建议必须经过测试验证。AI 说修好了,不等于真的修好了。
6. 不要上传敏感代码
涉及商业机密、客户数据、密钥、生产配置的代码,应先脱敏或使用企业认可的安全环境。
十四、一个完整的 AI 审计工作流示例
下面给出一个可以直接应用到项目中的完整工作流。
第一步:新建审计分支
git checkout -b security-audit-ai
第二步:查看项目状态
git status
第三步:让 AI 生成项目安全画像
请只读分析当前项目,生成项目安全画像,重点找出认证、权限、数据库、文件处理、外部请求和敏感配置相关模块。
第四步:选择高风险模块
例如 AI 发现存在文件下载模块,就继续:
请专项审计文件下载模块,重点关注路径穿越、越权下载、响应头注入和敏感文件泄露。
第五步:让 AI 输出风险列表
请将发现的问题按风险等级排序,并区分“确认风险”和“疑似风险”。
第六步:人工确认高危问题
开发者或安全人员阅读代码,确认 AI 判断是否成立。
第七步:生成修复方案
问题 1 已确认成立,请给出最小改动修复方案,并说明是否需要补充单元测试。
第八步:审查修改
git diff
第九步:运行测试
mvn test
或者:
npm test
第十步:生成审计报告
请根据本次审计过程生成一份正式审计报告,适合提交给项目组。
十五、总结
AI 代码审计不是让大模型“自动替我们找漏洞”,而是把大模型引入代码安全流程,让它承担重复性、结构化、辅助性的分析工作。它可以帮助我们快速理解项目、梳理调用链、识别危险函数、分析数据流、生成修复建议、补充测试思路和整理审计报告。
但 AI 不是安全专家的替代品。它可能误报,也可能漏报;它可以理解代码片段,但不一定理解完整业务;它可以给出修复建议,但不能替代人工评审和测试验证。因此,正确的使用方式应该是:
- 用 AI 提升审计效率;
- 用人工判断风险是否成立;
- 用测试验证修复是否有效;
- 用流程保证结果可追踪;
- 用安全边界保护代码和数据。
未来,AI 代码审计很可能会成为研发流程中的标准环节。它不会取代开发者和安全工程师,而是让安全能力更早进入开发阶段,让更多问题在提交前、合并前、上线前被发现和修复。
对于个人开发者来说,可以从 Git diff 审计、模块安全检查、日志敏感信息检查这些低成本场景开始。对于团队来说,可以逐步沉淀提示词模板、安全规则库、审计报告模板,并把 AI 审计接入 CI/CD 和代码评审流程中。
一句话总结:AI 代码审计的核心不是“让 AI 代替人做安全”,而是“让 AI 帮人更快、更系统、更有依据地做安全”。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)