ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

安全基线做进开发模板:AI编程时代的安全左移实践

安全基线做进开发模板:AI编程时代的安全左移实践

1. 当代码风格统一了,安全基线为什么还散落在每个人的电脑里

团队里做代码规范这件事,这几年已经卷得很成熟了。ESLint、Prettier、EditorConfig、Husky 加 lint-staged,一套组合拳下来,缩进、引号、分号、命名风格基本能做到全组一致。CI 上再挂一道检查,谁提交的代码格式不对直接打回。这套东西跑通之后,代码看起来确实整齐了,review 的时候也少了很多“你这个空格多了”这种低价值争论。

但有个问题一直没解决:代码风格统一了,安全基线却还留在每个人的个人电脑上。

我见过太多团队是这样的——组里有个安全意识比较强的同学,他在自己的编辑器里配了一堆检查规则,本地跑得好好的。换个人、换台机器,同样的仓库拉下来,那些检查规则一个都不生效。更麻烦的是,现在 AI 编程工具普及之后,很多人直接让 AI 生成代码,AI 生成出来的东西风格上可能没问题,但安全上完全是另一回事。SQL 拼接、硬编码密钥、不安全的反序列化、命令注入,这些坑 AI 一样会踩,而且踩得理直气壮。

这个项目的核心思路,就是把安全基线从“个人电脑上的配置”变成“开发模板里的默认项”。换句话说,不再依赖某个人记得去装什么插件、配什么规则,而是让仓库本身、让开发模板本身,天然就带着这套基线。新人 clone 下来,打开就能用;AI 工具读到的上下文里,也天然包含这些约束。

关键词里提到的AGENTS.md、开发模板、Claude Code、AI编程工具、安全基线,其实指向的是同一件事:在 AI 参与编码的时代,规范和安全不能靠人自觉,得靠模板和上下文文件来承载。这篇就围绕这个思路,把“基线做进开发模板”这件事拆开讲清楚,包括为什么这么做、模板里到底放什么、AI 工具怎么接进来、以及我在实操中踩过的那些坑。

适合谁看?如果你是团队里负责工程规范、DevOps、或者安全左移落地的人,这篇会对你有直接帮助。如果你只是个人开发者,想让自己用 AI 写代码时少埋雷,同样能抄走一套可用的模板结构。

2. 安全基线为什么天然容易“掉队”

2.1 代码规范有天然的执行载体,安全基线没有

代码规范之所以能统一,是因为它有一个非常明确的执行载体:代码本身。缩进、引号、换行这些是代码的物理形态,工具可以直接解析、直接改写、直接在提交时拦截。ESLint 能自动 fix,Prettier 能一键格式化,这些东西的反馈是即时的、确定的。

安全基线不一样。安全问题的形态太分散了:有的是代码写法问题(比如字符串拼接 SQL),有的是配置问题(比如把 debug 打开、把密钥写进配置文件),有的是依赖问题(引了个有漏洞的包),有的是流程问题(比如没做输入校验)。它没有一个统一的“物理形态”,所以也就没有一个天然的执行载体。

结果就是,安全基线往往以“文档”“checklist”“培训”的形式存在。文档没人看,checklist 靠自觉,培训听完就忘。这不是态度问题,是机制问题——没有载体,就没有执行。

2.2 个人电脑上的配置,本质上是不可复现的

我见过不少团队的安全检查是这么做的:某个同学在自己机器上装了某个扫描插件,或者写了个本地脚本,跑一跑,发现问题就口头提醒一下。这套东西的问题在于:

  • 不可复现:换台机器就没了,新人进来根本不知道有这回事。
  • 不可审计:跑了没有、跑了什么、结果如何,没有任何记录。
  • 不可强制:全靠个人自觉,没有卡点。
  • 不可传承:这个人离职了,这套东西就消失了。

这四点里,最致命的是“不可传承”。代码规范因为有.eslintrc、.prettierrc这些文件存在仓库里,所以它是团队资产。而个人电脑上的安全配置,是个人资产,人走茶凉。

2.3 AI 编程工具把这个问题放大了

以前写代码是人手写,人至少还有个“我这么写安不安全”的模糊意识。现在用 AI 编程工具,比如 Claude Code 这类,你给个需求,它直接给你生成一大段代码。生成速度极快,但安全判断这件事,AI 并不会天然帮你兜底。

我实测过很多次,让 AI 生成一个“读取用户输入并查询数据库”的功能,它十有八九会给你一个字符串拼接的 SQL,而不是参数化查询。你让它生成一个配置文件读取逻辑,它可能会把默认值写成硬编码的密钥。这不是 AI 不行,而是AI 的默认行为是“让代码跑起来”,而不是“让代码安全地跑起来”。

所以在这个背景下,安全基线如果还停留在个人电脑上,那基本等于没有。因为代码的生产速度已经远远超过了人工审查的速度,你不可能靠人肉去 review AI 生成的每一行。

2.4 把基线做进模板,本质是换一个执行载体

既然安全基线缺的是“载体”,那解法就很清楚了:给它找一个和代码规范一样的载体。这个载体就是开发模板。

开发模板是什么?可以理解成一套“项目脚手架 + 约定文件 + 工具配置”的组合。新人要开新项目,不从零开始,而是从这个模板 clone。模板里已经预置好了目录结构、基础配置、以及——安全基线相关的规则和上下文文件。

这样一来,安全基线就从“个人电脑上的配置”变成了“仓库里的文件”。它可复现、可审计、可强制、可传承。而且因为它在仓库里,AI 编程工具读上下文的时候,天然就能读到这些约束。

3. 开发模板里到底该放什么:一份可落地的清单

3.1 模板的骨架:目录结构和约定文件

先说模板的整体结构。我的做法是,模板仓库本身就是一个可运行的最小项目,包含以下层次:

project-template/ ├── AGENTS.md # AI 工具上下文与约束 ├── CONTRIBUTING.md # 人看的贡献规范 ├── .editorconfig # 编辑器基础约定 ├── .eslintrc / .prettierrc # 代码风格 ├── security/ │ ├── baseline.md # 安全基线说明 │ ├── rules/ # 自定义检查规则 │ └── secrets-scan.yaml # 密钥扫描配置 ├── .github/ │ └── workflows/ │ └── security.yml # CI 安全卡点 ├── src/ └── tests/

这个结构里,AGENTS.md和security/目录是核心。前者是给 AI 工具看的,后者是给人看的、也是给 CI 用的。

3.2 AGENTS.md:让 AI 工具天然带着安全约束

AGENTS.md这个文件,是这两年随着 AI 编程工具普及才出现的约定。它的作用是:当 AI 工具在这个仓库里工作时,优先读取这个文件,把它当作行为准则。

你可以把它理解成“给 AI 看的 CONTRIBUTING.md”。人看 CONTRIBUTING,AI 看 AGENTS。内容上,它应该包含:

  • 项目的基本技术栈和结构说明
  • 代码风格约定(和 ESLint 保持一致)
  • 安全约束:哪些写法是禁止的,哪些是必须的
  • 常用命令和测试方式

安全约束这部分,是我们要重点塞进去的。比如:

## 安全约束(必须遵守) - 所有数据库查询必须使用参数化查询,禁止字符串拼接 SQL。 - 禁止在代码中硬编码任何密钥、token、密码。统一从环境变量读取。 - 所有外部输入必须做校验和转义,禁止直接拼接进命令、SQL、HTML。 - 反序列化操作必须限定类型,禁止对不可信数据做无类型反序列化。 - 文件路径拼接必须做规范化校验,防止路径穿越。 - 新增依赖前必须检查其许可证和已知漏洞。

这些约束写进AGENTS.md之后,AI 工具在生成代码时会把它当作上下文的一部分。我实测下来,有这份文件和没有这份文件,AI 生成代码的安全质量差别非常明显。没有的时候,它默认给你拼接 SQL;有的时候,它会主动用参数化查询,甚至会在注释里提醒你“这里需要做输入校验”。

3.3 security/baseline.md:人机共读的基线说明

AGENTS.md是给 AI 的,但团队里的人也需要一份更详细的说明。security/baseline.md就是这个角色。它比AGENTS.md更详细,包含:

  • 每条安全规则的原因(为什么禁止拼接 SQL)
  • 正例和反例代码
  • 违反后的处理流程
  • 例外情况的申请方式

为什么要写原因和正反例?因为安全规则如果只写“禁止 X”,人是记不住的,AI 也容易误判。写清楚“为什么”和“长什么样”,执行起来才准确。

3.4 密钥扫描配置:把最容易漏的一环卡住

硬编码密钥是最高频、也最容易通过模板卡住的问题。模板里应该预置密钥扫描配置,比如用 gitleaks 或类似工具,配置好扫描规则和忽略规则。

# secrets-scan.yaml 示例 rules: - id: generic-api-key description: 检测疑似 API Key regex: '(?i)(api[_-]?key|apikey)\s*[:=]\s*["'']?[a-z0-9]{16,}' - id: private-key description: 检测私钥文件内容 regex: '-----BEGIN (RSA|EC|OPENSSH) PRIVATE KEY-----'

这份配置放在模板里,CI 上直接调用。新人 clone 下来,提交前本地也能跑,提交后 CI 再兜一道。

3.5 CI 卡点:让基线从“建议”变成“强制”

模板里预置的 CI 工作流,是让安全基线真正生效的关键。没有 CI 卡点,模板里的规则就只是“建议”;有了 CI 卡点,它才是“强制”。

# .github/workflows/security.yml 示例 name: security-baseline on: [push, pull_request] jobs: scan: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: 密钥扫描 run: gitleaks detect --config security/secrets-scan.yaml - name: 依赖漏洞扫描 run: npm audit --audit-level=high - name: 自定义规则检查 run: ./security/rules/run-checks.sh

这套东西跑起来之后,任何违反基线的提交都过不了。而且因为配置在仓库里,所有人都能看到规则是什么、为什么被拦。

4. 把 AI 编程工具接进这套模板的正确姿势

4.1 为什么 AI 工具需要“上下文文件”而不是“提示词”

很多人用 AI 编程工具的习惯是,每次对话都手动敲一遍要求:“请用参数化查询”“请不要硬编码密钥”。这么做的问题是:

  • 重复劳动:每次都要说,累。
  • 容易遗漏:说漏一条就埋一个雷。
  • 不可传承:你的提示词只在你脑子里,别人用不了。

而AGENTS.md这类上下文文件,本质上是把“提示词”固化成了“仓库资产”。AI 工具每次在这个仓库里工作,都会自动读取它。你不需要每次重复,规则天然生效。

这就是为什么关键词里AGENTS.md和开发模板会绑在一起——模板提供载体,AGENTS.md 提供 AI 能读懂的约束。

4.2 Claude Code 这类工具怎么读取模板约束

以 Claude Code 为例,它在一个项目里工作时,会读取项目根目录的约定文件。你把安全约束写进AGENTS.md,它在生成代码、修改代码、执行命令时,就会把这些约束纳入考虑。

我实测的一个具体场景:让它在模板项目里生成一个用户登录接口。没有AGENTS.md的时候,它生成的代码里密码比对是明文比较,SQL 是拼接的。有了AGENTS.md之后,它会用参数化查询,并且会在密码处理上提示“建议使用 bcrypt 等慢哈希”。

这个差别不是玄学,就是上下文的作用。AI 的行为高度依赖它看到的上下文,你给它什么约束,它就往什么方向走。

4.3 模板 + AI 工具的组合,实际工作流长什么样

把整套东西串起来,实际工作流是这样的:

  1. 新人要开新项目,从模板仓库 clone。
  2. 打开项目,AI 工具自动读取AGENTS.md,加载安全约束。
  3. 用 AI 生成代码,生成结果天然符合基线。
  4. 本地提交前,pre-commit hook 跑密钥扫描和基础检查。
  5. 推到远端,CI 跑完整的安全检查。
  6. 任何一步不通过,都打回修改。

这套流程里,人不需要记住所有规则,因为规则在模板里、在上下文里、在 CI 里。人只需要在例外情况下做判断。

4.4 一个容易忽略的点:模板本身也要版本管理

模板不是写完就完了。安全基线会变,新的漏洞类型会出现,AI 工具的行为也会变。所以模板本身要当成一个产品来维护:

  • 模板有版本号,项目可以锁定版本。
  • 基线更新时,模板发新版本,项目按需升级。
  • 升级过程要有 changelog,说明改了什么、为什么改。

我见过一些团队,模板建好之后就没人管了,半年后里面的依赖全是老版本,规则也过时了。这就又回到了“不可传承”的老问题。模板要活,得有人维护,得有版本。

5. 实操中踩过的坑和对应的解法

5.1 坑一:AGENTS.md 写太啰嗦,AI 反而不遵守

我一开始写AGENTS.md的时候,恨不得把所有安全知识都塞进去,写了三千多字。结果发现 AI 反而不太遵守,因为它抓不住重点。

后来我改成:只写最关键的、可执行的约束,每条不超过两行,用列表呈现。详细的解释放到security/baseline.md里,人去看。AI 只需要知道“禁止什么、必须什么”。

这个经验很反直觉——给 AI 的上下文不是越多越好,而是越精准越好。约束要短、要硬、要可判定。

5.2 坑二:规则太严,把正常开发卡死了

安全基线如果定得太严,比如“禁止一切字符串拼接”,那连正常的日志拼接都会被拦。结果就是大家开始想办法绕过,基线形同虚设。

我的解法是:区分“硬规则”和“软规则”。硬规则是绝对不能碰的(比如硬编码密钥、拼接 SQL),软规则是建议性的(比如日志拼接建议用模板字符串)。硬规则进 CI 卡点,软规则进 lint 警告。

# 规则分级示例 hard_rules: - no-hardcoded-secrets - no-sql-concatenation soft_rules: - prefer-template-literals - prefer-const

这样既守住了底线,又不至于让开发寸步难行。

5.3 坑三:AI 生成的代码“看起来对”,但绕过了基线

有一次我让 AI 生成一个文件上传功能,它生成的代码里,文件路径拼接用的是path.join,看起来没问题。但仔细一看,它没有对文件名做规范化校验,存在路径穿越风险。

这说明一个问题:AI 会遵守你明确写出来的规则,但不会自动补全你没写的规则。所以AGENTS.md里的约束要尽量覆盖高频风险场景,尤其是那些“看起来没问题但实际有坑”的地方。

我的做法是,每次发现 AI 绕过基线,就把这个场景补进AGENTS.md。模板是迭代出来的,不是一次写好的。

5.4 坑四:模板更新了,老项目不跟进

模板发新版本之后,老项目往往不会主动升级。时间一长,新老项目的基线就不一致了。

解法有两个:一是把模板做成依赖,项目通过包管理器引用模板里的规则包,升级就是改个版本号;二是定期做基线巡检,用脚本扫描所有项目,看哪些项目的基线版本落后了,推动升级。

前者更彻底,但改造成本高;后者更轻,适合存量项目多的团队。我一般建议新项目用前者,老项目用后者过渡。

5.5 坑五:把安全基线做成了“安全团队的事”

最后一个坑,也是最根本的坑:如果安全基线只是安全团队在推,开发团队被动接受,那它一定落不了地。

正确的做法是,把基线做进开发模板,让开发团队在开新项目时天然就用上。安全团队的角色是定义基线、维护模板、提供支持,而不是逐个项目去检查。这样基线才不是“外挂”,而是“内置”。

6. 从模板到习惯:让基线真正长在流程里

6.1 模板只是起点,习惯才是终点

把基线做进模板,解决的是“有没有”的问题。但模板再好,如果团队不按模板来,还是白搭。所以下一步是让“从模板开始”变成默认动作。

具体做法:新项目立项时,第一件事就是从模板 clone,而不是从零建。这个动作要写进团队的开发流程文档里,要有明确的入口。我见过做得好的团队,他们的项目创建是有一个内部平台的,点一下就从模板生成,根本不给“从零开始”的机会。

6.2 用数据反馈基线的有效性

基线做进去之后,怎么知道它有没有用?我的做法是看几个指标:

指标含义期望趋势
密钥扫描拦截次数有多少次硬编码密钥被拦下初期上升,后期下降
CI 安全卡点失败率有多少提交因安全规则失败逐步下降
基线例外申请数有多少次申请绕过基线保持低位
新项目模板使用率多少新项目从模板创建接近 100%

初期拦截次数上升是正常的,因为以前没卡,现在卡了,问题暴露出来了。后期下降,说明大家习惯了,问题在源头就避免了。

6.3 让 AI 工具成为基线的“执行者”而不是“破坏者”

AI 编程工具本身是中性的。它既可以帮你快速生成不安全的代码,也可以在基线的约束下帮你生成安全的代码。关键在于你有没有给它约束。

把AGENTS.md和模板结合起来,AI 工具就从“潜在的风险源”变成了“基线的执行者”。它每次生成代码,都在帮你落实基线。这是我觉得这套方案最有价值的地方——它把安全从“事后检查”变成了“事中生成”。

6.4 一个具体的落地节奏建议

如果你现在想在自己团队推这套东西,我建议的节奏是:

  1. 第一周:建模板仓库,把AGENTS.md、security/baseline.md、密钥扫描配置先放进去。
  2. 第二周:接 CI,把硬规则卡点跑起来,先只卡最关键的几条。
  3. 第三周:找一两个新项目试点,从模板创建,收集反馈。
  4. 第四周:根据反馈调整规则,补充AGENTS.md,然后推广到所有新项目。
  5. 之后:每月 review 一次基线,每季度更新一次模板版本。

这个节奏不激进,但能保证每一步都落地。最怕的是一上来就定几十条规则,结果开发怨声载道,最后不了了之。

6.5 最后分享几个我在实操中总结的小技巧

第一个技巧:AGENTS.md里的规则,尽量用“禁止/必须”这种硬词,少用“建议/尽量”。AI 对硬词的响应更明确,软词容易被忽略。

第二个技巧:每次 AI 生成的代码出了问题,别只改代码,要把这个场景补进模板。模板是活的,问题是最好的养料。

第三个技巧:密钥扫描的忽略规则要谨慎。我见过有人为了图省事,把整个测试目录都加进忽略列表,结果测试代码里的密钥就漏出去了。忽略规则要精确到文件,不要精确到目录。

第四个技巧:模板里的示例代码,本身就是最好的文档。与其写一堆规则说明,不如在模板里放几个正例文件,AI 和人一看就懂。

这套东西我推了大概半年,最大的感受是:安全基线这件事,靠人自觉是永远做不好的,靠机制才能做好。而模板,就是那个最自然的机制载体。它不增加额外负担,因为它本来就该存在;它又能把基线固化下来,因为它跟着代码走。把基线做进开发模板,本质上就是让安全从“个人电脑上的配置”变成“团队资产”,从“事后检查”变成“事中生成”。这件事值得每个还在靠人肉 review 的团队认真做一遍。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进