vibe coding
Vibe Coding 问题解决篇:AI扫描出一堆安全问题怎么办
Vibe Coding

问题解决篇:AI扫描出一堆安全问题怎么办

你让 AI 给项目做一次安全检查。

它扫完,甩给你一份报告。

十几条,前面一排红色的“高危”。

你一条都看不懂。

于是你说:那你全修了吧。

这句话,是这件事里最贵的一句。

它一条条往下修,报告上的红色确实清光了。

至于哪几条本来就不成立、哪几条在修的时候顺手弄坏了别的东西,你不知道。

报告变干净了,这是你唯一看得见的事。

一天一个 vibe coding 小技巧,今天就讲清楚:安全扫描之后,到底该怎么处理。

先说一句,这一篇几乎全是能直接复制给 AI 的原话,你不用自己琢磨该怎么开口。想要原版的,看到最后我告诉你怎么拿。

一、先把“发现风险”和“确认漏洞”分开

扫描报出来的每一条,说的都是同一件事:这个地方看着可疑。

它没说这个地方真的能被打穿。

举个最常见的。它报某个位置接收了用户提交的内容,可能被恶意利用。

这句话本身没错。错的是把它当成结论。

一条提醒成不成立,得往后再看三件事——框架有没有自动拦截,代码有没有再次校验,这段内容最后被送到了哪里。

三件都没查清以前,它只能叫“待核实的问题”。

所以扫描结果不是判决书,是一份待核实的清单。

不查清就开修,代价长这样。

那个位置,框架其实早就挡住了。AI 不知道,又在登录那儿加了一层,还把规则写严了。

报告上的红色少了一个。

第二天,手机号里带个空格的老用户,全被挡在门外。

那个漏洞根本不存在,坏掉的登录倒是真的。

这不是说扫描结果不重要。

恰恰相反,真正危险的那几项,很可能就藏在里面。

只是你不能看见“高危”两个字,就让 AI 不分真假地全部开修。

而误判不止落在登录上。支付、权限、数据处理,每一处都可能是原本正常的功能,被顺手改坏。

好在第一步并不难。

先让 AI 只读检查,不许修改代码、配置、依赖和数据。

它必须先告诉你,这一次到底检查了什么。

还要把这次检查对应的代码版本固定下来。

当前是哪一次提交,还有哪些修改没有提交,用了什么扫描工具、什么版本和什么配置,都得写清楚。

否则代码继续改过几轮以后,你连这份结果到底属于哪个版本都说不清。

账号和权限有没有查,用户提交的数据有没有查,密钥和日志有没有查,依赖、第三方服务和公网暴露有没有查。

发现明确证据的,标成已证实。

只有线索、证据还不够的,标成待核实。

已经检查但没有发现问题的,只能写“在当前范围内未发现”。

根本没有检查到的,标成未检查。

不能拿一句“全面扫描完成”,把“当前没发现”“根本没检查”和“已经证明安全”混在一起。

二、把扫描结果变成一份问题账本

检查范围确认以后,再把所有发现写进一份安全审计文档。

每个问题都要有自己的编号。

它出现在哪里,可能影响谁,真被利用以后会发生什么,AI 根据什么认为它有风险,又准备怎么验证,都要写清楚。

已经有保护措施的,也要一并写进去。

这样第二轮复核时,才能判断现有保护到底够不够,而不是重复发现同一个问题。

每一项还要标明当前状态。

刚发现线索时是待核实。

证据能够证明问题成立,改成已证实。

确认是误报或者不适用于当前项目,写清依据以后才能关闭。

开始修复、修复完成和重新验证,也要继续更新状态。

这样你才能看见每个问题到底走到了哪一步,而不是修完以后只剩一句“已处理”。

“已处理”这三个字最省事,也最不说明问题。它是真修好了、还是被 AI 判成误报顺手划掉了,你从这三个字里一点都看不出来。

这份文档里会暴露项目最薄弱的位置,有时还会写到具体的触发方式。

所以它默认是内部文档,不要跟着公开代码一起发出去。

到这里,屏幕上那堆吓人的红色提醒,才开始变成一份能够管理的问题账本。

你可以先把下面这段话交给 AI:

「本轮执行只读安全审计,不修改任何代码、配置、依赖和数据。

先固定基线:项目根目录、当前提交号、未提交改动、技术栈,以及当前生效的需求、架构和安全规则文档。

记录所用扫描工具的名称、版本、配置和执行命令,保证同一版代码可复现同样结果。

审计范围至少覆盖身份与权限、用户输入、敏感数据、密钥与日志、依赖、第三方服务、公网暴露,逐项标明是否已检查。

每条结论按四种状态之一标注:已证实、待核实、当前范围内未发现、未检查。四者含义不同,不得互相替代。

输出一份项目内部的安全审计清单,每项包含编号、风险等级、影响对象、位置、现实后果、判断证据、现有防护、复现方法、验证方法、当前状态。

其中涉及技术判断的结论,各附一句非技术语言的说明。

本轮只交付审计范围、清单和证据,不进入修复。」

三、第二轮不是继续找数量,而是把问题查准

第一轮清单写完,还不能直接动手。

接下来要让 AI 结合当前框架的官方文档、项目里用到的第三方 SDK 文档、项目需求、架构设计和权限规则,把整份清单重新核对一遍。

这里要特别点一句第三方 SDK。

扫描工具认得代码,不认得你装进来的那些别人写好的组件。一条告警到底成不成立,有时候答案根本不在你的代码里,而在那个 SDK 的文档里——它默认开了什么、默认关了什么、哪个版本改过行为。

不翻那份文档,AI 就只能按通用情况猜。

为什么还要再来一次?

因为同一个现象,放在不同的技术框架和业务流程里,结论可能完全不同。

如果 AI 说框架本身已经处理了,不能听完这句话就把问题关掉。

它还得证明:当前使用的框架版本确实提供了这层保护,项目没有把它关掉,这条真实的数据处理过程也确实经过了这层保护。

三项都能拿出证据,才能把它记录成“现有保护已经覆盖”,而不是再写一套重复代码。

告警去重也不能只看文件位置。

同一行代码可能同时存在两种不同的问题,同一个问题也可能经过几条不同的代码路径触发。

让 AI 对照告警使用的规则、用户数据从哪里进入、最后流向哪个危险位置、触发条件和根本原因。

确认这些都指向同一个底层问题,才能合并成一个修复单元。

只看代码表面没有发现,但按照真实业务流程确实能看到别人数据的问题,也不能漏掉。

第二轮真正要做的,是按照证据去重、判断误报、补上业务风险,再重新排顺序。

排序也不能只看工具给出的“高危、中危、低危”。

还要看它有多容易被利用,真出事以后对当前产品的影响有多大。

会影响账号、权限、用户数据、资金或者公网服务的问题,优先处理。

低风险提醒和暂时无法验证的问题继续留在文档里。

不能为了让结果好看,就把还没处理的项目偷偷删掉。

你可以接着对 AI 说:

「结合当前框架官方文档、项目所用第三方 SDK 的官方文档、项目需求、架构设计、数据关系和权限规则,复核这份安全审计清单。

逐条核对告警命中的规则、数据流、触发条件和根本原因。合并修复单元的依据是这些证据指向同一个根本原因,而非位于同一文件。

判定误报或不适用的,写出判定依据。

以“框架已提供防护”为由排除的,需核对框架版本、项目配置和真实数据路径,证明该防护在当前项目中确实生效。

涉及第三方 SDK 的,查对应版本的官方文档,说明该行为属于其默认设置还是本项目配置所致,并给出文档出处。

补充第一轮遗漏的问题,即依赖真实业务流程和权限关系才能发现的那一类。

按可利用性和对当前业务的实际影响重新排序。

本轮只更新审计文档,不修改代码。每一项保留、合并、降级或排除的理由,逐条写明。」

四、真正修复时,一次只处理一个修复单元

清单复核完、处理顺序也确认了,才进入真正的修复。

但这里仍然不能让 AI 一口气全部改完。

动第一项以前,先让 AI 检查 Git 状态。

它要先列出准备提交哪些文件,哪些修改还没有提交,哪些文件没有被 Git 记录。

然后检查暂存内容里有没有存着真实密钥和配置的文件、生产数据、用户信息和不该进入代码仓库的日志。

这些内容没有排干净以前,不准提交。

如果密钥已经写进代码或者提交历史,也不能只把那一行删掉。

先把它记进安全清单,再更换或者作废原来的密钥。

确认提交范围干净以后,才能把当前能够运行的版本保存成一个清楚的检查点,再建立专门处理这轮安全问题的分支。

检查点就是把现在这版代码保存成一个以后能够退回来的节点。

新分支则是单独开一条路处理修改,不和原来的版本混在一起。

接下来一次只处理一个独立的修复单元。

一个修复单元可以对应一条告警,也可以包含几条已经确认来自同一个根本原因的告警。

这样既不会一口气乱改一大片,也不会对同一个问题重复打补丁。

先让 AI 用大白话解释:谁可能利用它,需要满足什么条件,真被利用会造成什么后果。

再让它说明准备改哪些地方,会不会影响现有功能,改完以后怎么证明问题真的关掉了。

到这儿还有两句得追,很多人漏的就是这两句。

第一句:这是不是最好的做法,还有没有别的选择。

AI 给你的方案,通常是它第一个想到的能用的方案。同一个问题往往有好几种改法,有的只动一行配置,有的要改动业务逻辑,代价差得很远。你不问,它不会主动摆出来给你挑。

第二句:这个改动会牵扯到哪些地方,我得重新试一遍哪些功能。

这跟“会不会影响现有功能”不是同一个问题。那一句它可以答“不会”,你就没事可做了。

这一句要的是一张清单:改完以后,你该打开哪几个页面、点哪几个按钮、走哪几条流程。

你不懂代码,看不出改动波及到哪儿。但你能一条条点过去。

这两句问完,你确认方案,它才能动手。

改完也不算完,得拿三样东西出来。

原来那条攻击路径确实被挡住了,扫描工具重跑一遍结论对得上,还有刚才那张复测清单,你自己一条条走完。

三样都有,这一条才算真关掉,写回安全文档,再轮到下一个。

可以这样说:

「本轮只处理安全清单中优先级最高的一个修复单元,其余问题不动。

先说明该单元包含哪些告警,以及触发条件、现实后果和现有防护未能拦截的原因,这部分用非技术语言写。

提交前核对暂存区与提交历史,确认其中不含存放真实密钥和配置的文件、生产数据、用户信息和日志。发现真实密钥时停止提交,报告其出现位置、是否已进入提交历史、需要作废更换哪一个——删除代码中的字符串不足以处理已经泄露的密钥。

给出修复方案:变更文件范围、受影响功能、需要新增或复用的测试、失败时的回滚方式。

同时给出至少两种备选方案,说明各自的代价与风险,以及推荐当前方案的理由。

另外单独输出一份复测清单,写成我可以逐条手动执行的操作步骤,不要只给文件名或函数名。

修改前留下可触发该问题的测试或检查步骤;无法完整复现时,针对这层防护构造一个最小反例。

不改动本单元范围以外的代码,不新增没有真实迁移需求的兼容逻辑。方案经我确认后再实施。

完成后分别提供三项证据:原攻击路径或反例已被拦截、对应扫描结论已符合预期、复测清单全部通过。

将证据写回安全审计清单,然后停下等我确认。」

五、我自己实际是怎么走的

前面四节拆得细,你可能觉得步骤有点多。

我把自己的实际流程说一遍,你就知道它其实只有三轮。

第一轮,只让它扫,扫完写进文档。

这一轮我不看结论,也不让它碰代码。

它只负责把可疑的地方全列出来,一条一条落到那份安全审计文档里。

第二轮,让它把这份文档坐实。

这一轮的关键词是“结合”。

结合当前框架的官方文档,结合项目里用到的那些第三方 SDK 的文档,结合我这个项目自己的架构和权限规则,回头把每一条重新审一遍。

哪条是误报,哪条其实框架早挡住了,哪条得看 SDK 那个版本的默认行为,这一轮才有答案。

而且每一条都要给依据。说误报,得说清凭什么;说框架挡住了,得指出文档哪一句、版本对不对得上。

这一轮做完,那份文档才从“AI 说有这些问题”,变成“已经查过、站得住的问题”。

第三轮,一条条拎出来问。

到这儿才开始谈修,而且一次只谈一条。每一条我固定问四句:

方案是什么。

这是不是最好的方案,还有没有别的选择。

按这个方案改,后果是什么。

会牵扯到哪些环节,我得重新试一遍哪些地方。

四句都问明白,我才说“改吧”。

三轮走下来,最大的变化不是修得多干净,是我全程知道它在干什么。

这三轮里,前两轮一行代码都没动。真正动手是在第三轮,而且是我点头之后。

六、最后

安全扫描扫出很多问题,不代表项目已经没救了。

真正需要警惕的,是你被一长串风险提醒吓住以后,让 AI 立刻全部修掉。

那三轮看起来比“一键修复”慢。

慢的只是前两轮,而前两轮根本没动代码。真正省下来的,是你不用再回头找“到底哪次修改把登录弄坏了”。

安全不是把报告里的红色数字清零。

而是每一个真正存在的问题,都有证据、有方案,也有修复后的验证结果。

如果 AI 给你的安全扫描结果一眼看不懂,就让它从第一项开始用大白话解释,别在没弄清楚以前直接同意修改。

最后我想把这一篇背后那条规矩单独说一遍,因为它不只管安全扫描。

项目出任何问题,都要把“查”和“改”拆成两件事。

查的时候,一行代码都不许动,它只能给你证据;查完拿出方案,你点头,才轮到改;改完还得用同一把尺子,证明问题真的没了、别的地方也没被带坏。

你只要守住一条:没看见证据以前,不说那句“行,你改吧”。

该内容为@openbeetles原创内容,未经授权,禁止转载,违者必究!