☰
AI写代码之后,安全审计怎么跟上?从漏洞盲区到实战流程
2026/10/17 3:20:13 网站建设 项目流程

“AI写代码快,谁来看安全?”这个问题,最近在我所在的技术社群里被反复抛出来。AI辅助编程工具确实把“出码速度”拉高了一个台阶,但从仓库里长出来的代码,安全责任并不会跟着AI一起自动清零。作为在代码审计和安全测试里泡了多年的老开发,我想把这段时间观察到的坑、跑通的流程、以及踩过的雷,认真拆一遍。

这篇文章不是劝退你用AI写代码,恰恰相反,它是写给那些已经在用、准备用、以及被要求“赶紧用上AI”的开发者和管理者。我会从AI生成代码最常见的几个安全盲区聊起,给出可落地的审查维度、工具链选型、以及一套能嵌进日常开发的实操流程。最后是我自己踩过的一些真实案例和排查心得,希望能帮你少交学费。

1. 先看清AI代码的安全欠账在哪

1.1 三个最隐蔽的坑:幻觉、局部视角、跳过安全细节

AI写代码和人类新手写代码,有一个非常像的地方:它会把“看起来正确”当作“真正正确”。

先说幻觉。AI会一本正经地推荐不存在的库、已经废弃的API、甚至张冠李戴的函数签名。我让人工智能生成过一个文件上传接口,它直接返回了基于用户文件名拼接服务器路径的代码,理由是这个“简洁高效”。如果照单全收,路径穿越漏洞就顺着仓库进了生产环境。更麻烦的是,AI给的依赖版本往往不是最新的,而旧版本里经常带着公开的CVE漏洞。

再说局部视角。AI没有你业务的全局上下文,它不知道当前登录用户是谁,不知道这个接口是不是只有管理员才能调,不知道订单数据到底属于哪个租户。它只会按照Prompt里的字面需求,老老实实写出“功能正确”的代码。至于越权、敏感数据泄露、水平权限绕过,这些需要业务语义才能发现的问题,AI基本无能为力。

最后是安全细节的缺失。让AI写登录接口,很多模型会直接给你一个MD5加密,因为它训练数据里这种写法太多了;让AI写一个查询接口,它大概率不会主动做分页、限流、参数边界校验。不是说AI故意写烂代码,而是它的训练目标偏向“补全代码”,不是“构建生产级安全系统”。

1.2 从高频搜索词看群体焦虑

我翻了一下最近的搜索热词,发现事情比想象中更普遍。“代码诊断插件”“安全测试”“web安全”“AI安全”“示例代码讲解”这些词热度很高,背后其实就是三拨人在找答案。

第一拨是刚接触AI编程的开发者,他们搜“示例代码”“代码诊断插件”,想知道AI生成的代码到底能不能信,出了问题怎么查。第二拨是团队里负责安全的人,他们在搜“安全测试”“代码审计工具”,想找到适合放到CI/CD里的自动化方案。第三拨是被老板要求“提效”的技术管理者,他们搜“AI编程提示词”“AI大模型本地部署配置”,本质上是在找一条既能用AI提效、又不会把公司数据喂给外部模型的路径。

这三拨人的焦虑是同一个问题的不同切面:AI把写代码的速度拉起来了,但代码审查、安全测试、上线前的风险评估,这些环节并没有自动跟上。速度越快,安全债务累积得就越快,这不是危言耸听,是正在发生的现实。

2. 给AI代码做安全体检,要盯住这五个维度

2.1 依赖与供应链安全

AI写代码时特别爱推荐第三方库,这是供应链风险的第一入口。攻击者常用的手法叫“依赖混淆攻击”:在公开仓库里注册一个和你内部私有包同名或高度相似的包,名字稍微改一个字母,版本号完全相同。你的团队如果没注意,AI又恰好推荐了这个“平替”,一条pip install或npm install下去,恶意代码就进来了。

对抗手段其实不复杂,但必须养成习惯。第一,所有AI推荐的依赖,都要人工确认包名、仓库地址、作者信息,最好再去官方文档看一眼。第二,锁定依赖版本,Python项目用poetry.lock或requirements.txt精确版本,Node项目用package-lock.json,不要用^或者>=这种宽松范围。第三,把漏洞扫描接入CI/CD,npm audit、pip-audit、safety、OWASP Dependency-Check这类工具都能干这件事。我个人的习惯是每周在CI里跑一次全量依赖扫描,再盯一眼有没有新增的高危CVE。

我曾经处理过一次典型的依赖混淆问题:AI推荐了一个名为python-jwt的包,项目组没人核实,直接装了上去。后来代码跑起来老是有奇怪的出网请求,一查才发现这个包和正规的PyJWT根本不是一回事,它会在导入时悄悄回传环境变量。那次之后,凡是AI给出的依赖名单,我要求必须附上官方链接和版本锁定记录。

2.2 输入校验与注入攻击面

任何把用户输入直接拼进代码的逻辑,都是AI生成代码的高危雷区。我自己见过太多AI写出来的这段式代码:

# 危险示范:直接把用户输入拼进SQL username = request.args.get("username") cursor.execute(f"SELECT * FROM users WHERE name = '{username}'")

看起来逻辑没错,但一个包含' OR 1=1 --的用户名就能把整张用户表拖走。同样的问题还会出现在命令执行里,AI经常生成类似os.system(f"ping {host}")的代码,如果host没过滤,那等于给攻击者开了一个远程命令执行的口子。

安全的写法不是“多过滤几个字符”,而是从根本上消除拼接:

# 安全写法:参数化查询,永远不拼SQL cursor.execute("SELECT * FROM users WHERE name = %s", (username,))
# 安全写法:通过参数列表传递,而不是拼接命令字符串 subprocess.run(["ping", host], timeout=5)

审查AI生成代码时,我会重点搜这几个模式:SQL字符串拼接、os.system、exec()、eval()、反序列化、以及直接使用用户输入构造URL。一个简单的排查方法是:把所有从请求、表单、上传文件、外部API进来的一律视为“不可信输入”,只要下面紧跟了数据库操作、命令执行、文件读写,就停下来重点审查。这个“输入溯源”的思路,比单纯用扫描器更管用。

2.3 密钥硬编码与敏感信息泄露

AI训练数据里到处都是“为了方便演示把密钥写在代码里”的坏习惯。尤其在生成示例代码、配置文件、测试脚本时,AI非常喜欢直接硬编码AccessKey、数据库密码、API Token。你在审查时要养成一个条件反射:看到字符串里出现sk-、AKIA、password =、SECRET_KEY =,马上标记为高风险。

处理方式有几个层面。第一,用扫描工具兜底,gitleaks、trufflehog都能在CI里扫描历史提交和新增代码,一旦发现疑似密钥,直接让流水线失败。第二,在团队规范里明确:所有密钥必须从环境变量或配置中心读取。第三,如果发现密钥已经提交到Git历史,不要只删掉当前文件,要用git filter-repo这类工具清洗历史,并立刻轮换密钥。很多团队只删当前代码,老版本里密钥还挂着,这就是埋雷。

2.4 权限边界与越权控制

越权是AI生成代码里最容易被忽略的一类问题。因为AI看不到你的业务模型,它只知道“这个接口能查到订单信息”,不知道“这个订单只能由所属用户查看”。于是就会出现下面的“功能正确但安全不合格”的接口:

@app.route("/api/order/<order_id>") def get_order(order_id): order = db.query(Order).filter(Order.id == order_id).first() return order.to_dict()

这版代码如果上线,任何登录用户只要遍历order_id,就能看到别人的订单,典型水平越权。修复的核心是在数据访问前做归属校验:

@app.route("/api/order/<order_id>") def get_order(order_id): order = db.query(Order).filter(Order.id == order_id).first() if not order or order.user_id != current_user.id: abort(403) return order.to_dict()

审查这类问题时,我常用的方法是画一条“数据访问链路”:用户输入什么、代码用什么查询、最终返回了什么数据,中间有没有任何环节校验“当前用户对这条数据拥有权限”。AI生成的代码里如果完全没有这条链路,那基本就要补上所有权校验。垂直越权也一样,管理员接口必须显式校验角色,不能只靠路由前缀隐藏。

2.5 内容合规与License

“安全”不止是漏洞和攻击,还包括合规。现在很多团队用AI生成接口文案、用户协议、客服话术,甚至直接生成面向C端的内容。这些内容如果没有审核机制,AI一本正经地输出违规、歧视性、误导性的文案,风险一点不比代码漏洞小。我在内容系统里见过AI生成的“拜登电解铝生产”都不存在,AI胡编的“行业排名第一”被客户截图投诉。

代码侧还有一个容易被忽略的License问题。AI训练数据里包含大量开源代码,它生成出来的代码片段可能携带GPL、AGPL等传染性许可证。如果你们是商业闭源项目,混入这类代码会有法律风险。所以我的建议是:用license-checker、FOSSA这类工具扫描生产依赖和关键源码片段的License,内部列一个“允许清单”和“禁止清单”,交给法务背书的清单比技术自己瞎判断靠谱得多。

3. 把AI写代码真正纳入安全研发流程

3.1 一套可落地的AI代码安全审查流程

与其指望AI自己写出安全的代码,不如把“AI生成”改成“人机合作生成”,核心原则是:AI出初稿,人做安全和业务审查,自动化工具做兜底。

我推荐这个四步流:

  1. AI生成初稿。开发者写清楚需求和约束,AI产出代码,但不要急着提交。
  2. 自动扫描前置。本地或CI先跑一遍:格式检查、SAST扫描、依赖漏洞扫描、密钥扫描。这一步能拦住大部分低级问题。
  3. 人工语义审查。开发者重点看输入校验、权限校验、敏感操作审计这三块。尤其要回答一个问题:“这段代码如果暴露在公网,攻击者最可能从哪三处下手?”
  4. 提交后监控。合并进主干后,继续跑动态安全测试(DAST)和运行时监控,看有没有异常出网请求、异常文件读写。

这个流程看起来多花了几步,但大多数检查是工具自动跑的,真正需要人工花精力的是第三步,通常也就多花十到二十分钟。把它和Code Review结合,安全责任自然就落到了人机协作的边界上,而不是悬在空中。

3.2 工具链怎么搭最省心

安全工具不要追求大而全,要“贴合开发流程”。我目前比较顺手的一套组合如下:

场景工具说明
IDE实时检查SonarLint、ESLint + eslint-plugin-security写代码的同时就能看到潜在问题提示
Python静态扫描Bandit检测危险函数调用、注入、硬编码密码等
多语言语义分析Semgrep、CodeQL支持自定义规则,能匹配越权、错误拼接等模式
依赖漏洞扫描npm audit、pip-audit、Trivy、OWASP Dependency-Check接入CI,每次构建自动跑
密钥泄露检测Gitleaks、TruffleHog扫描Git历史和新增内容
动态安全测试OWASP ZAP、Burp Suite对上线前的Web应用跑一轮自动化渗透

这里要重点说下Semgrep,它最大的好处是规则可以沉淀。比如你在审查中发现AI特别爱写eval(input())这种危险模式,直接在Semgrep里写一条规则,以后只要有人提交类似代码,CI直接拦截。这种“把审查经验固化成规则”的做法,才是AI时代安全工具的正确用法——AI每天在变,你的规则库也得跟着变。

3.3 把安全要求写进Prompt,从源头减少问题

依赖事后扫描和人工审查的同时,我更推荐在源头就压缩风险。方法很简单:给AI的Prompt里明确写安全约束,而不是只写功能需求。我常用的模板长这样:

请生成一个用户注册接口,要求如下: 1. 所有外部输入必须做类型和长度校验,并说明可能的攻击路径 2. 禁止拼接SQL,必须使用参数化查询 3. 密码使用bcrypt加密,禁止明文存储 4. 敏感信息(密钥、连接串)必须通过环境变量读取,禁止硬编码 5. 输出代码前,先列出一份这段代码最可能被攻击的3个风险点清单

最后一条非常关键。让AI先列风险点,再写代码,它会更早进入安全模式。实测下来,加了这条要求后,生成代码里出现低级注入和硬编码的概率明显降低。

另外一个技巧是和AI做“差分审查”:让AI生成两版实现,一版是“普通写法”,一版是“生产级安全写法”,然后对比两者差异。这个对比本身就是极好的安全教学,我常拿它来给新人做Code Review培训。

4. 我踩过的坑和排查实录

4.1 三个真实案例复盘

第一个案例,是AI生成内部工具时把SSRF漏洞带进了内网。需求是“输入一个URL,生成截图”,AI给出的代码直接请求用户提供的URL并用weasyprint渲染HTML。如果用户传入http://127.0.0.1:3306或者云厂商的元数据地址,就能探测内网资源。排查时我用Semgrep搜“requests.get”和动态URL,发现这个接口完全没限制协议和IP段。修复方案是:只允许HTTP/HTTPS协议、解析域名后检查IP是否在内网保留段、禁止访问云元数据地址。

第二个案例,是依赖包名撞车。团队用AI生成的脚本需要解析JWT,AI推荐了python-jwt,直接装上了启动脚本。后来该脚本在测试环境里每十分钟向外发送一次心跳包,流量特征异常,追查下来才发现装错了包。那次之后我们定了硬规矩:AI推荐的依赖包,必须由人工去官方仓库确认真实性,同时所有锁文件必须提交并定期审计。

第三个案例,是AI自动补全的“查询订单”接口存在水平越权。这个接口是我亲眼看着它生成的:登录、鉴权、参数校验都有,唯独在数据查询时没有做“订单归属用户”校验。也就是说,用户A登录后,只要把订单ID改成别人的,就能看到别人的订单。当时是动态安全测试里通过越权用例发现的。修复后,我把“数据访问必须校验归属权”这条规则写进了Semgrep的规则库,防止同类问题再次漏网。

这里也提醒一句:用AI编程工具时,代码片段默认会发送到模型服务端。如果你们公司代码高度敏感,最好用本地部署的大模型来承接编程辅助,或者至少和模型服务商确认清楚数据隔离和合规条款。这是现在很多团队忽略的“看不见的安全边界”。

4.2 避坑心得与效率技巧

踩过几次坑之后,我形成了几条原则。

第一,永远不要相信AI说“已经修好了”。让它修改一个安全问题,它会很乐意地说“已修复”,但如果你不重新跑一遍安全扫描和不安全模式检索,很可能只是换了个写法,问题本质还在。我的习惯是:AI改完代码后,一定重新执行一次静态扫描、依赖扫描、以及“输入溯源”审查,才算闭环。

第二,安全自动化要前置,不要放在上线前。把扫描放在开发者的本地或PR阶段,成本是最低的。等代码合并到主干再扫,修复成本就指数级上升。我见过太多团队上线前跑一次安全测试,发现一堆问题然后加班修复,那个过程非常痛苦,还没有效率。

第三,建立“AI安全负面清单”。把我们和AI协作过程中踩过的坑、发现的高危模式、禁用的API,整理成团队文档。新人在使用AI写代码时先过一遍这个清单,能直接避开80%的低级问题。这份清单同时也是给AI提示词做约束的最佳素材。

第四,让AI自己帮忙写安全测试用例。与其只让它写业务代码,不如让它“写完功能后,再写攻击用例来打自己”。让AI生成针对这段代码的边界case、非法输入、越权尝试,然后你再拿这些用例去跑动态测试。AI生成的攻击用例质量参差不齐,但能给你提供不少灵感,尤其是动态安全测试脚本的覆盖度能被明显补强。

我个人最近一年最大的变化是:习惯了把AI当成一个“面试者”,而不是“免检员工”。它出初稿,我负责提问、抽查和验证。这个过程会让代码产出速度更快,同时安全底线不打折。如果你也想在一个有AI辅助的团队里推进安全工作,不妨从今晚就开始做一件事:把今天AI帮你写的那段代码,从头到尾按“输入源头、权限边界、危险函数”三个角度重新读一遍。大概率会有收获。

最后再分享一个小技巧:给AI加一句“请解释每一处安全设计”,你会发现它为了解释,必须先思考安全逻辑。这种“解释型约束”比我试过的其它任何Prompt技巧都更能压低风险代码的产生率。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询