安全编码规范把前六幕的防御要点落成开发手边的检查项(参数化查询、输出编码、归属校验、不硬编码密钥……),提交前对照自查;代码审计则以人工判断补自动扫描的盲区,在评审中对新代码逐项核查高危点,并回头看历史遗留。两者一起让“写错安全代码”的概率在源头下降。
第七幕的第二个站点讲“落地动作”。规范和审计是一体两面:规范告诉你怎么写才对,审计保证你确实这么写了。它们都依赖对前六幕每个漏洞“该守哪一层”的准确判断,正好考验你前面学得结不结实。
与其让每个开发自己悟,不如把防御要点固化成一份可执行清单。典型条目:
规范的价值在于“照着核对”,也让新人上手有明确指引。最好再配正反代码样例,说明什么写法要禁止、正确写法长什么样。
# 规范示例: 一律用参数化, 绝不因缺省拼字符串 def get_user(conn, uid): cur = conn.cursor() cur.execute("SELECT * FROM users WHERE id = ?", (uid,)) return cur.fetchone()
CVE 扫描、SAST(下节讲)能替人照很多,但静态分析漏掉的问题(跨模块的归属校验缺失、逻辑漏洞、信任边界的隐式假设)往往要靠人来判断。代码审计要盯的典型点:
一个高频经验:新增代码审查反而好做(你本来就熟悉它),价值大的是“账本式审计”盯住老代码与边界——那里常是上线很久没被正视的洼地。
⚠️ 常见坑:把代码审计做成“过场打卡”。没有清单、没有结论归属的审计等于没审——审计的价值不在“看过代码”,而在“产出了可追踪、能回流的结论”。
背景:团队给一个订单接口上线前做审计,新代码里发现一处“以请求 ID 查订单但未做归属”与一处“日志里打了完整手机号”。操作:按信任边界 + 归属提权 + 明文密钥三块走查,定位两处问题。结果:越权风险 + 敏感信息落日志被记录并开具修复单。解读:人工审计抓到了自动扫描难以判定的归属缺失问题。变式:把两条规范(归属必校验、敏感字段日志脱敏)写入编码清单与模板示例,后续新接口提交前自动自查,验证“审计回流到规范防止再生”。
审计资源有限,别把同样多的时间花在低危复制粘贴与高风险登录上。给一个优先级排序:第一优先是“不信任输入进入信任区”的那几处(外面的参数有没有经过校验/编码/授权再影响后续),因为它是注入与越权最容易的挂点;第二优先是“涉及支付、身份、密钥、批量写库”的路径,出事最重;第三优先才是普通业务与无关紧要的重构。审计报告也应按此分级,高危必改带责任人与时限,低危记录归堆后续统一清。这样才能把“审代码”从平均分摊变成真正打在刀刃上的投入。
单次审计解决单次问题,价值有限;让审计发现回流成系统能力,才算闭环。做法有三:一,把高频高危发现写成新的规范条目与正反代码样例,让后人不再犯同类;二,能机械判断的(未脱敏落日志、字符串拼 SQL)固化成自动检查或模板限制,减少人工重复;三,把审计发现的历史模式沉淀成 checklist,下次同类型接口凭一份清单就快速过掉。审计的价值因此不只在你读过的那些代码,而在于它不断把“踩过的坑”转化为团队的默认防护——这才是“写错安全代码的概率在源头下降”的真正机制。
代码审计的人力有限,若每次只“看心情”抽查几段,高危点也可能恰好没被抽到。给一个更稳的覆盖思路:按变更面分配审计注意力——改动到登录鉴权、支付、对外接口、批量写库、文件与上传处理这几类时,一律强制走审计;只动文案、展示、配置或纯重构的,走轻量自检即可。把“改动类型 → 是否强制审计”写成一张映射表,挂在合并流程前,就能保证风险和审查投入成正比,而不是靠运气。同时把审计结论里未闭环的高危项推给对应 owner 并设时限复查,防止“审了但没改、改没改没人管”。这样审计就从随缘抽查,变成一条和每次提交绑定、覆盖该覆盖之处的固定工序,也让“安全编码”有了可量化的落实抓手。
写了规范不等于用得上,团队最容易卡在“记得有规范,临写时忘了怎么套”。把它落进随手可得的样板最有效:给登录、文件上传、支付、对外接口这类高频场景各配一段“安全写法示例”,注释里标清每一步为什么这么写;把参数化查询、输出编码、归属校验这些动作做成公共函数或中间件,让正确写法成为默认路径。这样新人在写第一个接口时,跟着样板走就不会踩坑,而不是靠背一页容易过时的规范。规范的价值因此从“贴在墙上的字”变成“落在代码里的默认”,审计时也省力——多数接口已经按样板写对了,只要盯住少数绕过样板的“特殊化”实现。