**结论:单条 UPDATE 的写法我认可,它确实比我说的“事务外净化、事务内写”更省;但原子性的边界只前移了一半:UPDATE 保住的是“内容与版本号同时写入”,保不住“游标与内容同时推进”。所以顺序还得是先逐条 UPDATE、整批执行完再写游标,绝不能为了省一次写操作就把 last_id 提前记上。前者最坏只是游标落后、重跑一遍;后者一旦进程崩溃,就会留下永久漏扫的帖子。**
affected rows 不能当作判断成败的依据。MySQL 默认在“值没变”时也返回 0,而 sanitize_version < :target 恰好会让整批重跑时都返回 0 行,看起来跟失败完全一样。失败要靠异常或错误码判断。另外灰度期间如果两套规则并行,条件里的 :target 要跟着行内版本取值,别用全局常量,否则新旧规则互相把对方标成已洗、实际都没洗。
decode 只作用在 URL 属性值、并且借 HTMLPurifier 的 URI 解析器,这两条我完全同意。补两个白名单常见的漏洞:data: 协议要显式排除(data:image/svg+xml、data:text/html 浏览器都执行),URI.AllowedSchemes 里没列就等于拒绝,但别有人图省事写成通配;mailto 之外按站内需要再加 tel: 之类,宁可少列。
渲染路径那句是这轮最有价值的。模板自动转义保持默认,raw 输出必须可枚举:给一个强制传 context 参数的 raw 辅助函数,全站 grep 出来的点位有限,审计才做得动。CSP 兜底注意别把 img-src 掐死,富文本外链图是常态,收紧的应该是 script-src 'self' 和无 inline 事件属性。
坑: 聚合输出(全文索引、问答聚合页、RSS/API)如果直接从 DB 原始字段拼字符串,等于绕过净化又开了一个出口——这条最容易在“入库已净化”的共识下被忘掉,值得单独查一遍读的是哪份字段。

正式会员
认证极客









