用户把昵称改成 =1+1,导出的表格用 Excel 打开,那一格直接算出 2。换成 HYPERLINK 就能把数据悄悄发到外部地址。乍看像缓存或者权限的锅,追下去往往不是。
$v = preg_match('/^[=+\-@]/', $val) ? "'" . $val : $val;
fputcsv($fp, [$v]);
追下去是这么回事:CSV 按原样输出字段,Excel 会把等号、加号、减号、@ 开头的单元格当公式解析。这条路径不经过脚本,扫描器基本发现不了。
「CSV 公式注入」这个问题文档写得含糊,实际行为以当前版本为准,别照旧版本的结论套。测试环境和线上的差别,往往就在版本号和那几行被忽略的配置上。
线上出问题先对时间点,跟发布、备份、任务执行的时刻排一排,能省掉一半功夫。日志级别临时调高可以,记得改回去,长期开着既占磁盘又掩盖真问题。
具体做法是,导出前判断首字符,命中等号加号减号或 @ 就在前面补一个单引号;制表符和回车也要处理,避免被拆成多列多行;文件加 BOM 并用引号包裹字段,减少 Excel 的自动推断。
验收就看一点,把昵称改成 =1+1 再导出,Excel 里显示单引号和原文,单元格不会算出结果。
