AI驱动历史项目安全审查

前言

近期,我们的一个基于 .NET Framework 的老项目被客户的安全扫描器扫出了 SQL 注入。收到报告的那一刻,我的第一反应不是"修",而是 "除了报告里写的这几个点,系统里到底还有多少我们不知道的?"

当然现在的大环境下,基本的安全问题可能利用WAF,EDR等外挂式的防护进行一些阻断,但这本质上都是在系统外面套了一层壳。而壳是可以被绕过的,系统自身的铜头铁骨,才是兜底的防线。

大语言模型发展到今天,已经具备了难以想象的能力。以前我们做安全审查,可以利用一些工具,比如SAST,DAST,甚至是人工审计,但它们都各有各的不足,要么是语义类判断力不从心,要么是需要运行环境,自动化配置操作过复杂,要么就是慢!效率低下。

而今天的大语言模型在安全审查这件事上,有一个传统工具或工作方式不具备的核心能力:它能"读懂"代码的上下文

当你告诉它"这个搜索参数是从 HTTP 请求里取的",它能顺着调用链往上追到 Controller 的 Action 方法,再确认这个 Action 有没有登录态保护。这种 source → sink 的全链追踪,以前只有经验丰富的安全工程师能做到,现在 AI 可以批量、持续、不疲劳地执行。

更重要的是,AI 能带着判断干活

本篇笔者将提供一套完整的、经过多个项目实战验证的 AI 驱动安全审查工作流供大家参考,需要说明的是,这里重要的不是工作流的内容,而是这个工作的切入方式和思考角度。你完全可以根据自己的实际情况,来创建适合自己项目的审查工作流。

好了,本篇正文开始。


前置条件

  • 一个支持长上下文的 AI 编程助手(如 DeepSeek Harness / Hermes / Claude Code 等,本文以 Hermes 为例)
  • 你的项目源码(我这里设置的是 .NET 技术栈,大家根据自身情况配置即可)
  • 项目里有一个文档目录

开始操作

Step 1:投放初始化模板

把下面这份初始化模板复制到你的项目文档目录,命名为 安全漏洞检查方法论-初始化模板.md(见本文附录 A):

"

这份模板约 260 行,包含 8 条核心原则、项目画像模板、SQL 注入双路线扫描表(传统 ADO.NET + ORM)、通用攻击清单、验证判据、文档约定、以及 AI 首次接管的完整执行手册。

Step 2:让 AI 接管

在你的 AI 编程助手里,粘贴这段提示词:

复制代码
请对本项目做一次安全审查。

第一步:读取 {你的文档目录}/安全漏洞检查方法论-初始化模板.md,
执行 §9 首次接管流程------技术栈探测 + 项目画像 + 生成安全基线。

第二步:按基线中的扫描清单开始首轮扫描,产出漏洞台账。

红线:扫描期只读,不改代码;写库测试只用可丢弃数据。

{你的文档目录} 替换成实际路径,比如 Docs/安全审查

执行效果如下图

Step 3:等待 AI 输出

AI 会自动完成以下工作:

  1. 读你的 csproj/sln,判断技术栈
  2. 生成《安全基线.md,包含项目画像、扫描清单、已知线索
  3. 执行首轮扫描,产出漏洞台账(JSON 格式)
  4. 给出修复建议

首次运行大约需要 10-30 分钟(取决于项目大小)。之后你可以用"继续审查"或"推进到下一轮"来驱动多轮审查。本工作流程包含了多轮会话之间的交接文档,详见附录D

"

这里给出我的一个老项目的审查报告


完整工作流详解

工作流全景图

复制代码
┌─────────────────────────────────────────────────────────┐
│                    初始化模板 v0.3                        │
│  (普适方法论,不含任何项目细节)                            │
└─────────────┬───────────────────────────────────────────┘
              │ 投放到项目
              ▼
┌─────────────────────────────────────────────────────────┐
│  AI 探测 → 裁剪 → 回写                                    │
│  读 csproj/sln → 判断 ORM → 裁剪扫描模式 → 生成安全基线     │
└─────────────┬───────────────────────────────────────────┘
              │
              ▼
┌─────────────────────────────────────────────────────────┐
│  多轮审查                                                │
│  轮次 0:初始化                                           │
│  轮次 1:首轮扫描 + 漏洞台账                               │
│  轮次 2:HIGH 级修复                                      │
│  轮次 3:MEDIUM 级修复                                    │
│  轮次 4:专项修复(文件上传/JWT/鉴权...)                    │
│  轮次 5+:验证、回归、收尾                                 │
└─────────────┬───────────────────────────────────────────┘
              │
              ▼
┌─────────────────────────────────────────────────────────┐
│  三层验证                                                │
│  ① 编译验证(dotnet build 零错误)                         │
│  ② SQL 层回归(临时控制台直连数据库)                       │
│  ③ HTTP 层全链路(起站点、登录、发请求、验证响应)            │
└─────────────────────────────────────────────────────────┘

文档体系(四件套)

每轮审查都会产出/更新以下文档:

文档 作用 位置
安全基线 项目画像 + 扫描清单 + 红线 安全审查/安全基线.md
漏洞台账 唯一的状态权威,JSON 格式 安全审查/_review-ledger-{项目名}.md
进度看板 从台账汇总的概览 安全审查/安全审查进度看板.md
CHANGELOG 按时间倒序的变更记录 安全审查/CHANGELOG-安全审查.md
交接文档 跨会话的上下文续接 安全审查/记录/_session-handoff-*.md

关键规则 :台账是明细、看板是概览,看板的计数必须从台账汇总,禁止另写一套。这是我们踩过坑的教训------曾经出现过台账 18 条、看板写 19 条的情况。

漏洞台账格式

每条漏洞用 JSON 记录,结构如下:

复制代码
{
  "id": "VULN-001",
  "pattern_code": "A1_StringInterpolation",
  "sink_file": "xxx.cs",
  "sink_line": 142,
  "source_entry": "xxx(string keyword)",
  "is_controllable": true,
  "risk_level": "HIGH",
  "status": "OPEN",
  "repair_strategy": "Parameterization",
  "note": "keyword 来自 HTTP GET 参数,用户完全可控"
}

状态流转:OPEN → IN_PROGRESS → FIXED → VERIFIED

  • OPEN:发现但未修
  • IN_PROGRESS:已落码 + 编译通过,但未做回归自测
  • FIXED:SQL 层回归自测通过
  • VERIFIED:HTTP 层全链路验证通过
  • REJECTED_UNCONTROLLABLE:确认不可控(如 int 类型约束、死代码无调用方)

"

这里给出一个我这里审查完的目录结构


导入为 AI Skill(推荐)

这个 Skill 的设计哲学是薄壳------它不复制方法论的全文,只做两件事:

  1. 接管引导:告诉 AI "开工前先跑 preflight、先读哪两份文档"
  2. 硬约束:列出该项目会咬人的规矩(如仓库边界、状态语义、证据文件纪律)

方法论的正文始终以项目内的《安全基线.md》和《初始化模板.md》为准,Skill 只做索引。

preflight.py 自动化预检

"

文件 :[preflight.py 通用模板](#preflight.py 通用模板)(见本文附录 C,内容多但不用人看,扔给模型即可)

这个脚本在每轮审查开始和结束时运行,自动检查:

检查项 说明
仓库状态 HEAD 是否与远端一致、有无未提交改动
台账自洽 JSON 可解析、ID 连续、条目数 = 状态计数之和
路径存在性 台账/看板/CHANGELOG 文件是否在预期位置
证据文件 assets 目录是否意外提交了大文件(>1MB)
凭据泄露 是否有密码/密钥/连接串被跟踪
日期自洽 轮次提交日期与交接文档日期是否一致

退出码 0 = 全通过,退出码 1 = 有 FAIL 项,先修再开工。

"

我在早期执行时,出现过 AI 把台账修了但忘记更新看板的情况,甚至出现过上一轮说'修好了'但代码没提交的乌龙。为了解决这类'人工疏忽',才写了 preflight 脚本做机械自查。


适用场景与局限

适合用这套流程的场景

  • .NET 项目(Framework 4.x / Core / .NET 5+),有历史代码需要体检
  • 使用 ADO.NET / EF Core / FreeSql / Dapper 等数据访问方式
  • 希望有结构化的审查记录(不是"扫一遍看报告"就完事)
  • 愿意投入多轮审查,逐步深入

当前局限

  • 主要覆盖 SQL 注入,其他攻击类型(XSS/CSRF/越权)只做了速查清单,未做深度专项
  • 需要人工参与验证:编译和 SQL 层可以自动化,但 HTTP 层全链路测试往往需要登录态、特定业务数据
  • 依赖 AI 的代码理解能力:对于非常复杂的动态 SQL 生成(如运行时拼接 LINQ 表达式树),AI 可能误判
  • 不是渗透测试:这是代码层面的安全审查,不替代专业的渗透测试

总结

这套工作流最大的价值,不是帮你找出几个 SQL 注入,而是把'安全'从一个低频、依赖专家经验的'运动式扫荡',变成了一个高频、可沉淀、越用越聪明的'日常基建'。当 AI 能读懂你的代码上下文,它能替你扛下 80% 的脏活累活,而你只需要做那 20% 的关键决策。在这个时代,善用 AI 去重构工作流,本身就是一种核心竞争力。


附录 A:初始化模板完整内容

"

完整的《安全漏洞检查方法论-初始化模板》约 260 行,包含:

  • §1 核心原则(8 条,来自实战教训)
  • §2 项目画像模板(9 项 [待填] 占位符)
  • §3 检查阶段总览 + 漏洞台账 JSON Schema
  • §4 攻击面清点(taint source 清单)
  • §5 SQL 注入专项(路线 A:传统 ADO.NET 8 种模式 / 路线 B:ORM 6 种模式)+ 修复分层 + 验证判据 + 自测约定
  • §6 其他攻击速查清单(13 类)
  • §7 经验教训库(滚动追加)
  • §8 文档与流程约定
  • §9 首次接管流程 + AI Skill 自导出指南 + 自升级闭环
  • §10 版本演进记录

获取方式 :将本文仓库中的 安全漏洞检查方法论-初始化模板.md 复制到你的项目文档目录即可。 该文件设计为"跨项目稳定"------[普适] 标记的内容不要改,[待填] 由 AI 投放到具体项目后自动填充。

由于模板较长,这里给出你粘贴给 AI 的最简提示词(模板本身由 AI 按 §9 自动执行):

复制代码
读取当前项目的 {docs目录}/安全漏洞检查方法论-初始化模板.md,
执行 §9 首次接管流程:
1. 技术栈探测(读 csproj/sln/packages)
2. 填 §2 项目画像
3. 选路线(A/B/混合)
4. 首轮扫描 + 漏洞台账
5. 过 §6 通用清单
6. 与我确认范围后开始修复

附录 B:SKILL.md 通用模板

下面是 Skill 入口文件的通用模板。你需要根据你的项目定制**§2 项目硬约束**部分。

复制代码
---
name: {项目名}-security-review
description: {项目名} 安全审查的接管入口与机械自查。当用户要继续/推进安全审查、复测已修漏洞、更新台账/看板/交接时使用。
---

# {项目名} 安全审查 · 接管引导

**定位**:这是"防脱节"的薄壳,不是方法论副本。凡本文与项目内《安全基线.md》/母版模板冲突,以项目文档为准。

## 0. 接管第一动作(不可跳过)

运行预检脚本确认状态一致,然后只读两份文档:
1. 最新的交接文档 `_session-handoff-*.md`
2. 漏洞台账 `_review-ledger-*.md`

其余文档按需点读。

## 1. 事实源映射

| 载体 | 路径 | 职责 |
|------|------|------|
| 入口 | `安全审查/安全基线.md` | 项目画像、扫描清单、红线 |
| 明细权威 | `安全审查/_review-ledger-*.md` | 漏洞条目 JSON,状态以此为准 |
| 概览 | `安全审查/安全审查进度看板.md` | 从台账汇总,不得独立计数 |
| 轨迹 | `安全审查/CHANGELOG-安全审查.md` | 倒序,不删原文 |
| 续接 | `安全审查/记录/_session-handoff-*.md` | 每轮一份 |

## 2. 项目硬约束(根据你的项目定制)

- **仓库边界**:只改 `{项目目录}`,勿混编
- **状态语义**:台账只用 OPEN / IN_PROGRESS / FIXED / REJECTED_UNCONTROLLABLE
- **FIXED 标准**:至少需 SQL 层回归自测通过;仅落码+编译记 IN_PROGRESS
- **收尾一致性**:每轮结束须满足「台账条目数 == 状态计数之和 == 看板计数」
- **证据文件**:全表 dump 一律不入版本库
- **熔断**:禁止大面积重构与新功能同轮推进

## 3. 每轮收尾清单

1. 台账更新 → 跑 preflight 确认自洽
2. 看板从台账重汇总
3. CHANGELOG 顶部加本轮条目
4. 新写交接文档(附 git status 实测输出)
5. 分逻辑提交

## 4. 已知不要做

(在此列出你项目中已确认不可控的项、死代码、暂缓项等)

附录 C:preflight.py 通用模板

自动化预检脚本,检查 7 类一致性问题。复制后修改顶部的路径配置即可使用。

复制代码
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
安全审查 · 接管前机械自查(preflight)
用法:python preflight.py            # 只输出结论
      python preflight.py -v         # 附带明细行
退出码:0=全 PASS/WARN,1=有 FAIL
"""
import json, os, re, subprocess, sys

# ===== 根据你的项目修改以下路径 =====
REPO = os.environ.get("SECURITY_REPO", r"G:\your\project\path")
DOCS_SUBDIR = "Docs/安全审查"                    # 相对于 REPO 的文档目录
LEDGER_NAME = "_review-ledger-{项目名}.md"       # 台账文件名
BOARD_NAME = "安全审查进度看板.md"
ASSETS_DIR = "assets"
# ===================================

DOCS = DOCS_SUBDIR
LEDGER = f"{DOCS}/{LEDGER_NAME}"
BOARD = f"{DOCS}/{BOARD_NAME}"
BIG_BLOB_BYTES = 1_000_000
VALID_STATUS = {"OPEN", "IN_PROGRESS", "FIXED", "REJECTED_UNCONTROLLABLE", "REJECTED"}

fails, warns, oks = [], [], []
def ok(m): oks.append(m)
def fail(m): fails.append(m)
def warn(m): warns.append(m)

def git(*args):
    r = subprocess.run(
        ["git", "-C", REPO, "-c", "core.quotepath=false", *args],
        capture_output=True, text=True, encoding="utf-8", errors="replace"
    )
    return (r.stdout or "").strip()

# 1. 仓库状态
head = git("rev-parse", "--short", "HEAD")
remote = git("ls-remote", "--heads", "origin", "refs/heads/main")
remote_sha = remote.split()[0][:7] if remote else ""
if not remote:
    warn("未能读取 origin(离线?)")
elif remote_sha != git("rev-parse", "HEAD")[:7]:
    fail(f"本地 HEAD={head} 与 origin/main={remote_sha} 不一致")
else:
    ok(f"HEAD == origin/main == {head}")

porcelain = git("status", "--porcelain")
if porcelain.strip():
    fail(f"工作区有 {len(porcelain.splitlines())} 项未提交改动")
else:
    ok("工作区干净")

# 2. 台账 JSON 自洽
ledger_path = os.path.join(REPO, LEDGER.replace("/", os.sep))
if not os.path.isfile(ledger_path):
    fail(f"台账不存在:{LEDGER}")
else:
    raw = open(ledger_path, encoding="utf-8").read()
    m = re.search(r"```json\n(.*?)\n```", raw, re.S)
    if not m:
        fail("台账里找不到 JSON 代码块")
    else:
        try:
            entries = json.loads(m.group(1))
            ok(f"台账 JSON 可解析,{len(entries)} 条")
        except Exception as e:
            fail(f"台账 JSON 解析失败:{e}")
            entries = []

        if entries:
            # ID 连续性
            ids = [e.get("id", "") for e in entries]
            want = [f"VULN-{i:03d}" for i in range(1, len(ids) + 1)]
            if ids != want:
                fail(f"台账 ID 不连续:末条 {ids[-1]},期望 {want[-1]}")
            else:
                ok(f"ID 连续 VULN-001~{ids[-1][-3:]}")

            # 状态计数
            tally = {}
            for e in entries:
                st = e.get("status", "?")
                tally[st] = tally.get(st, 0) + 1
                if st not in VALID_STATUS:
                    fail(f"{e.get('id')} 状态非法:{st}")
            if sum(tally.values()) == len(entries):
                ok("状态计数 == 条目数:" + " ".join(f"{k}={v}" for k, v in sorted(tally.items())))
            else:
                fail("状态计数之和 != 条目数")

# 3. 文件存在性
for name, label in [(BOARD, "看板"), (LEDGER, "台账")]:
    if os.path.isfile(os.path.join(REPO, name.replace("/", os.sep))):
        ok(f"{label}存在:{name}")
    else:
        fail(f"{label}不存在:{name}")

# 4. 证据文件(大文件检查)
assets_path = os.path.join(REPO, DOCS.replace("/", os.sep), ASSETS_DIR)
if os.path.isdir(assets_path):
    tracked = git("ls-files", assets_path)
    for f in tracked.splitlines():
        fp = os.path.join(REPO, f)
        if os.path.isfile(fp) and os.path.getsize(fp) > BIG_BLOB_BYTES:
            fail(f"assets 下有大文件被跟踪:{f} ({os.path.getsize(fp)//1024}KB)")

# 5. 凭据泄露(简单关键词扫描)
config_patterns = re.compile(r'(?i)(password|passwd|pwd)\s*[:=]\s*["\'][^"\']{4,}', re.S)
for f in git("ls-files").splitlines():
    if not f.endswith((".cs", ".json", ".xml", ".config", ".yaml", ".yml")):
        continue
    fp = os.path.join(REPO, f)
    if not os.path.isfile(fp):
        continue
    try:
        content = open(fp, encoding="utf-8", errors="ignore").read(50000)
        if config_patterns.search(content):
            warn(f"疑似凭据:{f}")
    except:
        pass

# 输出
print("\n" + "="*60)
print("安全审查 · 预检报告")
print("="*60)
for m in oks:   print(f"  √ {m}")
for m in warns: print(f"  !  {m}")
for m in fails: print(f"  × {m}")
print(f"\n总计:{len(oks)} PASS / {len(warns)} WARN / {len(fails)} FAIL")
if fails:
    print("× 有 FAIL 项,请先处置再开工!")
    sys.exit(1)
else:
    print("√ 全部通过,可以开工。")
    sys.exit(0)

"

使用方法 :复制此文件到你的项目 Skill 目录或项目根目录,修改顶部 4 个路径变量,然后 python preflight.py 即可。


附录 D:多轮审查的提示词模板

继续审查(通用版)

复制代码
继续 {项目名} 安全审查。
先读 {docs}/安全审查/安全基线.md,按 §2 扫描清单与 §4 台账推进。
本轮目标:{具体目标,如"确认 L2 的调用链可控性并给出参数化方案"}。
已确认不可控项:{粘贴上次交接的"勿重复调查清单"}。
红线:只读分析;写库测试只用可丢弃数据;修复前贴 Patch。
相关推荐
2601_954811821 小时前
AI科学实验室MHS标准解读:AI智能体如何统一控制实验室设备接口
人工智能·python
具身AGI1 小时前
第一视角数据从哪来,物理AI 人类学习路线 的入口
人工智能·深度学习·学习
小白羊丨1 小时前
训练中看哪些指标?chosen/rejected 样本质量怎么保证?
人工智能·深度学习·机器学习
CypressTel1 小时前
GPT-6 Astra发布:复杂任务执行能力继续提升——赛柏特AI快讯
人工智能·gpt
ever_up9731 小时前
LangChain基础知识概述1
人工智能·python·langchain
HackTwoHub2 小时前
BurpSuite2026.8专业(稳定版)下载Windows/Linux/Mac支持Java21以上(新增Burp AT智能体)
linux·运维·服务器·安全·macos·网络安全·自动化
豆豆2 小时前
AI 建站实战:AI 生成前端页面如何集成自有 CMS 系统
人工智能·cms·网站搭建·网站管理系统·ai建站·建站工具·中小企业建站
cjy0001112 小时前
2026年9月零基础能听懂国内 FDE 讲师的课吗?
大数据·前端·人工智能·fde
百胜软件@百胜软件2 小时前
百胜软件SenClaw胜券助手正式发布:AI让数据“开口说话”,随时赋能零售运营
大数据·人工智能·零售