CSV 导出前先做公式注入审计:一个零依赖 Python 检查器
CSV 看似只是纯文本,但用户把它拖进 Excel、WPS 或其他电子表格后,以 =、+、-、@ 开头的单元格可能被当作公式解释。用户提交的昵称、备注、地址或外部导入数据一旦带有这些前缀,就可能形成公式注入风险。
本文验证一个只读检查器:它不修改原 CSV,只定位可疑单元格,输出行号、列号、前缀类别和内容预览,让数据导出流程能够在发布文件前做一次显式审核。
边界与原则
这个工具负责“发现”,不负责自动清洗。原因是 -12.5、+100 这类内容也可能有真实业务含义,直接改写会改变数据。工具将它们标记为 formula_prefix_numeric,由数据所有者决定加单引号、转成数值列,还是在导出格式层做安全编码。
检查范围:
=、+、-、@开头的内容;- 忽略前导空白后命中的内容;
- 制表符、回车等不可见前缀;
- 保留原始行号、列号和短预览。
为什么不能只检查第一个字节
电子表格可能忽略前导空格。因此仅判断 value[0] 会漏掉 " @SUM(A1:A2)"。实现先执行 lstrip(),再判断首个有效字符;同时把原始预览保留下来,便于定位真实字段。
def classify_cell(value):
stripped = value.lstrip()
if not stripped:
return None
if stripped[0] in ("=", "+", "-", "@", "\t", "\r"):
if stripped[0] in "+-" and _looks_numeric(stripped):
return "formula_prefix_numeric"
return "formula_prefix"
return None
_looks_numeric 使用 float() 尝试解析。它不是为了判断“安全”,而是为了区分“像数字的正负号”和明显的公式前缀,帮助处理人员做更精准的决策。
使用标准库读取 CSV
csv.reader 会处理引号、逗号和跨行字段,避免用字符串 split(',') 时常见的错列问题。文件使用 utf-8-sig 打开,可以同时兼容带 BOM 和不带 BOM 的输入。
with path.open("r", encoding="utf-8-sig", newline="") as handle:
rows = list(csv.reader(handle))
检查器只读输入文件,报告写到 -o 指定路径;有问题时进程退出码为 1,可以接在 CI 或导出脚本后面阻止有风险的文件继续流转。
实际验证
项目包含 4 项标准库 unittest 测试:
=、@和带制表符的公式前缀;-12.5、+100的数值型正负号分类;- 普通文本、空白和空单元格;
- 多行多列定位结果。
测试结果:
Ran 4 tests in 0.000s
OK
对三行合成 CSV 运行后,报告识别到 3 个问题:
{
"rows": 4,
"finding_count": 3,
"safe": false
}
命中位置分别为第 3 行第 2 列、第 3 行第 3 列和第 4 行第 2 列,退出码为 1。
使用方式
python3 csv_formula_audit.py input.csv -o report.json
python3 -m unittest discover -s tests -v
生产落地建议
将检查器放在“生成 CSV”和“发布下载链接”之间,并把报告、输入文件哈希和构建编号一起归档。真正修复时可选择:
- 对用户可见文本做平台约定范围内的前缀转义;
- 对纯数值字段使用数值类型并在导出时格式化;
- 在打开电子表格前增加数据来源提示和人工复核。
不要把“把内容用双引号包起来”当成安全修复:CSV 引号解决的是字段边界,不等于阻止电子表格解释单元格公式。
小结
公式注入检查不应该偷偷修改数据,而应先把风险变成可定位、可解释、可审计的记录。零依赖的 csv.reader 加上明确的前缀分类,已经足以让导出流程在交付前多一道可靠检查。
- 点赞
- 收藏
- 关注作者
评论(0)