MENU

[泛微 EC9] OA 附件 Base64 误杀事件排查复盘

• 2026 年 06 月 09 日 • 阅读: 5 • 躺过的坑,OA

一、事件背景

近期在测试 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 注入拦截规则高度一致。


六、第四次排查:回到真实失败图片做验证

为了避免“小样本实验不代表真实图片”的质疑,我们又对真实失败图片做了反向验证。

结论如下:

  1. 原始图片 Base64 上传失败
  2. 回显内容中,只有其中一处 or 被改写为 or
  3. 这处命中的上下文正好是 4or+

然后我们只做一个极小改动,不改整张图片,只改这一处附近的边界字符:

  • 原始:4or+ -> 请求失败
  • 改成:Aor+ -> 请求成功
  • 改成:4orA -> 请求成功

这一步的意义非常大,因为它证明:

  • 不是图片太大导致失败
  • 不是图片整体内容有问题
  • 不是 Base64 长度问题
  • 不是附件服务偶发异常

而是图片 Base64 中某个刚好命中安全规则的片段,触发了请求内容改写


七、最终结论

这次事件的根因可以明确归纳为:

OA 在接收 application/x-www-form-urlencoded 请求参数时,安全过滤链会对命中的敏感关键词进行全角替换;当附件 base64 恰好包含类似 orandunionselect 等关键词,并且其左右边界满足规则时,原始 base64 会被污染,最终导致附件解码失败。

换句话说:

  • 业务系统生成的附件 Base64 没问题
  • 图片本身没问题
  • 问题发生在 OA 接收请求后的安全处理阶段

这是一个典型的“安全规则误杀二进制文本内容”问题。


八、为什么这个问题隐蔽

这个问题很难第一时间定位,原因有三个:

1. 现象看起来像附件服务失败

接口只返回“生成附件失败”,很容易让人先怀疑附件服务或图片本身。

2. 不是所有附件都失败

只有当 Base64 内部恰好出现特定关键词组合时才触发,因此问题呈现出明显的“偶发性”。

3. 原始请求侧看不到污染

业务侧生成的 Base64 完全正常,真正的问题发生在请求进入 OA 后的处理中间层。


九、排查经验总结

这次事件里,最有效的不是一开始盯着大日志翻,而是做了几轮最小化实验:

  • 先验证原始 Base64 是否真的合法
  • 再用短样本确认问题是否与特定内容有关
  • 再通过边界变体判断触发规则
  • 最后回到真实图片做反向验证

这套方法的价值在于:

  • 能快速排除“文件坏了”这类低价值方向
  • 能把问题从“偶发失败”收敛成“稳定可复现”
  • 能把结论从“怀疑安全拦截”推进到“确认是关键词边界命中”

十、后续建议

如果后续要彻底解决,建议从以下几个方向评估:

1. 调整 OA 对附件类字段的安全过滤策略

对于明确承载 base64 附件内容的字段,应考虑:

  • 增加字段级白名单
  • 增加接口级豁免
  • 在安全过滤前识别并跳过合法 Base64 内容

2. 优化附件上传方式

如果接口支持,优先考虑:

  • 先上传附件,再传附件 ID
  • 使用 multipart/form-data
  • 避免把大段二进制文本直接放进普通表单字段

3. 建立关键故障样本库

像这次命中的 4or+4and+ 这种片段,建议沉淀成回归样本,避免后续升级或策略调整时再次踩坑。


十一、结语

这次故障表面上是“附件 Base64 失败”,本质上却是“安全规则误杀了 Base64 文本内容”。

它提醒我们一件事:

当接口处理的不是普通业务文本,而是承载二进制内容的编码字符串时,安全策略如果仍按普通文本规则处理,就很容易把合法数据当成攻击特征误拦。

很多“看起来像解析失败”的问题,最后都不是解析器本身有问题,而是数据在到达解析器之前,已经被别的环节悄悄改写了。