一、事件背景
近期在测试 OA 创建流程接口(/api/workflow/paService/doCreateRequest)时,遇到一个比较隐蔽的问题:业务侧传入的附件内容采用 base64 方式提交,接口返回 PARAM_ERROR,错误信息指向“生成附件失败”。
表面上看,这类问题通常会先怀疑以下几种方向:
- 图片文件本身损坏
base64转换过程出错- 请求体过长导致截断
- OA 附件服务解析失败
但这次问题的特殊之处在于:
- 同一张图片在本地可以正常解码
base64长度、补位、MD5 都正常- 错误并不是稳定出现在所有图片上,而是只出现在部分附件内容上
这意味着问题不太像“通用性格式错误”,更像“特定内容触发了某种中间处理逻辑”。
二、问题现象
业务调用 OA 创建流程接口时,附件字段通过 base64: 前缀方式上传,接口返回类似错误:
{
"code": "PARAM_ERROR",
"errMsg": {
"field_xxx": "生成附件失败,参数为:fieldid:xxxx,annexId:-3,fileValue:[...]"
}
}从附件服务语义上看,annexId:-3 的含义基本可以理解为:附件内容在进入保存逻辑后,Base64 解码失败。
但关键问题是,业务侧原始 base64 在本地验证完全正常。
三、第一次排查:先排除“文件坏了”
第一步做的是最基础的校验:
- 提取原始请求中的
base64 - 校验长度是否为 4 的倍数
- 检查是否只包含合法 Base64 字符
- 本地执行解码
- 对解码后的文件做 MD5 校验
结果很明确:
- 原始
base64串合法 - 本地可以成功解码
- 解码后的图片与原始附件 MD5 一致
也就是说,问题不在业务系统生成附件这一步。
四、第二次排查:不是所有 Base64 都失败
为了避免被“单个样本”误导,我们做了几组对照实验。
1. 安全样例
传一个很短、内容简单的 base64,结果成功。
2. 含特定片段的样例
构造一些很短但包含特定文本片段的 base64,例如:
4or+4and+4union+4select+
结果发现,这类请求会稳定失败。
更关键的是,OA 返回报文中回显出来的附件内容,已经不是原始值,而是被改写成了全角字符,例如:
4or+变成4or+4and+变成4and+
一旦 base64 内部出现全角字符,后续解码必然失败。
这一步已经把问题从“附件坏了”收缩到“请求进入 OA 后被改写了”。
五、第三次排查:到底是什么条件会触发改写
如果只是“出现 or 就失败”,那很多正常图片都应该大量失败,但事实并不是这样。
于是我们继续做边界实验,只改变命中关键词左右两边的字符。
实验样例如下:
- 会失败:
4or+ - 会成功:
Aor+ - 会成功:
4orA - 会成功:
AorA
同样地:
- 会失败:
4and+ - 会成功:
AandA
这说明触发条件不是“只要包含 or / and 就拦截”,而是更接近:
当某些敏感关键词左右两边都不是字母时,会被安全规则命中。
这类模式与常见 SQL 注入拦截规则高度一致。
六、第四次排查:回到真实失败图片做验证
为了避免“小样本实验不代表真实图片”的质疑,我们又对真实失败图片做了反向验证。
结论如下:
- 原始图片 Base64 上传失败
- 回显内容中,只有其中一处
or被改写为or - 这处命中的上下文正好是
4or+
然后我们只做一个极小改动,不改整张图片,只改这一处附近的边界字符:
- 原始:
4or+-> 请求失败 - 改成:
Aor+-> 请求成功 - 改成:
4orA-> 请求成功
这一步的意义非常大,因为它证明:
- 不是图片太大导致失败
- 不是图片整体内容有问题
- 不是 Base64 长度问题
- 不是附件服务偶发异常
而是图片 Base64 中某个刚好命中安全规则的片段,触发了请求内容改写。
七、最终结论
这次事件的根因可以明确归纳为:
OA 在接收application/x-www-form-urlencoded请求参数时,安全过滤链会对命中的敏感关键词进行全角替换;当附件base64恰好包含类似or、and、union、select等关键词,并且其左右边界满足规则时,原始base64会被污染,最终导致附件解码失败。
换句话说:
- 业务系统生成的附件 Base64 没问题
- 图片本身没问题
- 问题发生在 OA 接收请求后的安全处理阶段
这是一个典型的“安全规则误杀二进制文本内容”问题。
八、为什么这个问题隐蔽
这个问题很难第一时间定位,原因有三个:
1. 现象看起来像附件服务失败
接口只返回“生成附件失败”,很容易让人先怀疑附件服务或图片本身。
2. 不是所有附件都失败
只有当 Base64 内部恰好出现特定关键词组合时才触发,因此问题呈现出明显的“偶发性”。
3. 原始请求侧看不到污染
业务侧生成的 Base64 完全正常,真正的问题发生在请求进入 OA 后的处理中间层。
九、排查经验总结
这次事件里,最有效的不是一开始盯着大日志翻,而是做了几轮最小化实验:
- 先验证原始 Base64 是否真的合法
- 再用短样本确认问题是否与特定内容有关
- 再通过边界变体判断触发规则
- 最后回到真实图片做反向验证
这套方法的价值在于:
- 能快速排除“文件坏了”这类低价值方向
- 能把问题从“偶发失败”收敛成“稳定可复现”
- 能把结论从“怀疑安全拦截”推进到“确认是关键词边界命中”
十、后续建议
如果后续要彻底解决,建议从以下几个方向评估:
1. 调整 OA 对附件类字段的安全过滤策略
对于明确承载 base64 附件内容的字段,应考虑:
- 增加字段级白名单
- 增加接口级豁免
- 在安全过滤前识别并跳过合法 Base64 内容
2. 优化附件上传方式
如果接口支持,优先考虑:
- 先上传附件,再传附件 ID
- 使用
multipart/form-data - 避免把大段二进制文本直接放进普通表单字段
3. 建立关键故障样本库
像这次命中的 4or+、4and+ 这种片段,建议沉淀成回归样本,避免后续升级或策略调整时再次踩坑。
十一、结语
这次故障表面上是“附件 Base64 失败”,本质上却是“安全规则误杀了 Base64 文本内容”。
它提醒我们一件事:
当接口处理的不是普通业务文本,而是承载二进制内容的编码字符串时,安全策略如果仍按普通文本规则处理,就很容易把合法数据当成攻击特征误拦。
很多“看起来像解析失败”的问题,最后都不是解析器本身有问题,而是数据在到达解析器之前,已经被别的环节悄悄改写了。
[泛微 EC9] OA 附件 Base64 误杀事件排查复盘 by https://oneszhang.com/archives/198.html