很多审计者卡在”审得出、写不出”:漏洞找到了,报告却写得开发看不懂、老板看不明,最后石沉大海,漏洞原样留着。代码审计的闭环,一半在”找”,一半在”讲”和”修”。这一篇讲怎么把审计成果变成一份真正能推动修复的报告。
本文内容仅用于你对自有或已授权的代码做安全评估后的结果交付。
报告该有哪些部分
一份合格的交付报告,至少包含这几块:
- 概述:审计范围(哪些代码、哪个版本)、方法(白盒/工具辅助)、时间、整体结论。
- 漏洞清单:按严重程度排序的表格,每行含编号、名称、位置(文件:行号)、危害、CVSS 或自定等级。
- 单漏洞详述:每个漏洞给”位置 + 原理 + 复现步骤 + 影响 + 修复建议”。
- 修复总结与优先级:哪些必须马上修、哪些可排期。
- 附录:工具输出、参考 CVE/CWE 编号、复现用的请求/脚本(脱敏)。
记住:开发最关心的是”在哪、怎么改”,老板最关心的是”多严重、要多久”。报告要同时服务这两类读者。
漏洞怎么分级
常用 CVSS 或简化的四级:严重 / 高 / 中 / 低。定级要结合”可利用性 + 影响面”:
- 严重:可远程 RCE、直接获取管理员权限、批量拖库(如命令执行、反序列化 RCE、未授权 admin 接口)。
- 高:普通用户越权操作他人数据、SQL 注入读全库、任意文件上传拿 shell。
- 中:需一定条件(如登录后)的 XSS、信息泄露、SSRF 内网探测。
- 低:明文传输、缺失安全头、日志过于详细等加固项。
定级别只凭”漏洞类型”拍脑袋,要看在这个系统里的实际可达性与危害。同一个 SQL 注入,在内网隔离系统里和公网系统里等级完全不同。
复现步骤要可落地
开发最烦”存在 SQL 注入”这种结论,却没给怎么复现。好的复现描述应是”照着做就能看到”:
- 给出具体请求(URL、参数、payload),或一段最小复现脚本。
- 标出代码位置:
app/Controller/User.php:42的where()拼接。 - 描述预期 vs 实际:预期应报错或拒绝,实际返回了数据库数据。
最好附上截图或响应,让开发不用猜。复现越具体,修复越痛快。
修复建议要”给到位”而非”给方向”
差的修复建议:“建议对输入做过滤。“——等于没说。好的修复建议要具体到代码层面:
- 命令执行:用白名单限定允许的命令/参数,禁止拼接;必须用
exec时对参数escapeshellarg。 - SQL 注入:统一用参数化查询/预处理,禁止字符串拼 SQL;表名/字段名用白名单枚举。
- 越权:在每个按 ID 操作前加归属校验(
AND owner_id = 当前用户);接口层统一鉴权中间件。 - 反序列化:对反序列化类型做白名单;关闭 Fastjson autoType、Jackson 危险多态;升级组件。
- XSS:输出到 HTML 处做上下文转义,用框架自带的模板转义。
给修复建议时,顺手给一小段修正后的示例代码,开发照抄就能用,事半功倍。
和开发协作:把对抗变成共建
审计者最容易犯的错,是把报告当”定罪书”,开发当成”挑刺”。实际上安全是共同目标:
- 先肯定系统做得好的地方,再谈问题,降低防御心理。
- 解释为什么危险,而不只是哪里危险,让开发真正理解根因。
- 对历史包袱重的系统,给出渐进式修复路线:先堵最严重的 RCE/越权,再逐步补输入校验、加统一鉴权。
- 提供复测:开发改完后,你按原复现步骤验证是否真修好,形成闭环。
真正专业的安全工程师,交付的不是一堆漏洞,而是”系统比原来更安全”这个结果。
把审计融入开发流程(安全左移)
一次性的审计治标,长期安全靠流程:
- 安全左移:把代码审计、依赖扫描(Dependency-Check/Snyk)接进 CI,每次提交自动扫,漏洞在合并前就拦下。
- Code Review 加安全视角:团队约定”危险函数、权限判断、外部输入”为重点 review 项。
- 依赖治理:定期更新组件、锁定版本、禁用已知有 CVE 的库。
- 安全编码规范:沉淀团队自己的”危险写法清单”,新代码少踩坑。
审计不是终点,而是让”写安全的代码”成为习惯的起点。
报告写给谁看:三种读者三种写法
同一份审计发现,不同读者关心的重点完全不同。会写报告的人,懂得”一份底稿,三种讲法”:
- 给开发看:他们要的是”在哪、为什么错、怎么改”。所以给具体代码位置、最小复现、可抄的修复示例。少讲危害严重性,多讲技术根因和改法,他们才愿意动。
- 给技术负责人/架构师看:他们关心”整体风险水位、修复成本、排期”。所以给漏洞分级、按优先级排好的修复路线、对系统可用性的影响评估,帮他们做资源决策。
- 给老板/客户看:他们不懂技术细节,只关心”我们有多危险、要花多少钱多少时间、不修会怎样”。所以给一页纸的高层摘要:核心风险、业务影响、合规后果、建议投入,用业务语言而非技术黑话。
实操上,可以准备一份完整技术报告(给开发和负责人),再附一份执行摘要(给老板)。两者数据一致,只是详略和口径不同。这样既能推动开发修,又能让决策层理解投入的价值。
还有一个常犯的错误:把报告写成”漏洞清单流水账”,没有结论和优先级。读者面对几十条漏洞反而不知道先修哪个。好的报告一定给出”先堵哪几个、为什么、大概多久”,把专业判断显性化,这才是审计交付的真正价值。
报告之外:把安全变成习惯
交付报告不是终点,真正的目标是让团队以后少写漏洞。审计者可以在报告之外多做一步:把这次发现的高频问题(比如”按标识操作普遍缺归属校验”)沉淀成团队的安全编码检查项,下次代码评审时重点看;或者给开发做一次短分享,讲清这几个坑为什么会出现。当安全从”事后审计”前移到”事前规范”,你要审的漏洞会越来越少。这比任何一份漂亮的报告中”严重”数量下降,都更值得骄傲。
这一篇你该记住的
- 报告闭环 = 概述 + 漏洞清单 + 单漏洞详述(位置/原理/复现/影响/修复)+ 优先级 + 附录。
- 定级结合可利用性 + 影响面,同类型漏洞在不同系统等级不同。
- 复现要可落地:给具体请求/payload、代码位置(文件:行号)、预期 vs 实际。
- 修复建议要具体到代码,最好附修正示例;命令执行用白名单、SQL 用预处理、越权加归属校验、反序列化用类型白名单。
- 和开发协作把对抗变共建,改完复测形成闭环;长期靠 CI 依赖扫描、安全 Code Review、安全编码规范做”安全左移”。
到这里,六阶段”代码审计(PHP + Java)“十章就讲完了。从审计思路、PHP 基本功、ThinkPHP 与业务实战、PHP 审计工具,到 Java 体系、Spring 审计、反序列化组件漏洞、Java 审计工具,再到报告交付——你已经有了一套从思路、语言、框架、工具到交付的完整白盒审计能力。