SpringGraphQL反序列化RCE漏洞

admin 2026-09-12 04:41:18 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文分析SpringforGraphQL分页游标反序列化RCE漏洞CVE-2026-59285,影响2.0.0至2.0.4版本,CVSS评分9.8。漏洞源于默认Cursor策略将定位对象序列化为JSON并base64编码,攻击者可通过可控after参数触发Jackson多态反序列化执行代码。建议立即升级至2.0.5,或收紧Jackson多态配置并验证ObjectMapper运行期配置。 综合评分: 88 文章分类: 漏洞分析,WEB安全,安全建设


Spring GraphQL反序列化RCE漏洞

云栖 云栖

云栖码客

2026年8月25日 01:16 安徽

在小说阅读器读本章

去阅读

在公众号小说中沉浸阅读

Spring GraphQL反序列化RCE漏洞

8 月 20 号,Broadcom 一次发了 91 条 Spring 相关安全公告,光数量就够刷屏了。扫一圈标题,大部分是常规修补,但有一条值得你半夜爬起来看:Spring for GraphQL 的分页游标反序列化,编号 CVE-2026-59285。官方定级 HIGH,几家第三方跟踪平台给到的 CVSS 分冲到了 9.8。

先给结论,赶时间的人看到这行就可以去升级了:用 Spring for GraphQL 2.0.0 到 2.0.4 的项目,直接升到 2.0.5,没有中间值。

这个漏洞为什么和别的不一样

Spring for GraphQL 平时不太上安全头条,因为它本身不做数据绑定,真正的坑大多在 GraphQL Java 引擎或者你手写的 resolver 里。这次不一样,问题出在它自己的分页实现上。

GraphQL 生态里做分页,绕不开 Relay 的 Connection 规范。列表字段返回的不再是裸数组,而是一个带 pageInfoedges 的 Connection 对象,每个 edge 上挂一个 cursor 字符串。翻页时客户端把这个 cursor 原样带回,服务端靠它定位到”上次读到哪了”。

问题就出在 cursor 上。它看起来是段乱码字符串,实际上 Spring for GraphQL 的默认策略是:把一个定位用的对象序列化成 JSON,再 base64 编码。反过来解码的时候,同样要拿 Jackson 把这个 JSON 还原成对象。

// 默认 CursorStrategy 干的事,本质是 JSON 对象 <-> base64 字符串
String raw = "{\"position\":42}";
String cursor = Base64.getUrlEncoder()
        .encodeToString(raw.getBytes(StandardCharsets.UTF_8));

如果你的服务端定义了这样的分页字段:

@Controller
public class BookController {

    @SchemaMapping(typeName = "Query", field = "books")
    public Connection<Book> books(@Argument int first, @Argument String after) {
        // 拿到 after 之后,Spring 会把 cursor 解码回定位对象
        return bookService.findPage(first, after);
    }
}

一旦 after 是攻击者可控的(分页参数天然就是),而 Jackson 又开了多态类型解析,攻击者就能在 cursor 里塞进一个 type id,让 Jackson 反序列化时去实例化 classpath 上的某个 gadget 类。gadget 链一旦跑通,就是远程执行代码。

这就是官方给的那四个触发条件:用 Spring for GraphQL、用 Jackson 2.x 做 JSON 反序列化、暴露了分页 Connection 字段、classpath 里碰巧躺着可被利用的 gadget 类。四条同时成立,才算真正暴露。

为什么 Jackson 一掺和就出事

老读者对这套打法应该不陌生。Jackson 的多态反序列化出过一长串 CVE,从 CVE-2020-24616 到今年几起,套路高度一致:攻击者控制类型标识,Jackson 顺着这个标识去加载类、实例化、填充属性。只要 classpath 里能拼出一条从”构造”到”执行”的链子,反序列化就成了任意代码执行。

Spring for GraphQL 这次的问题在于,cursor 这个入口太容易被忽略了。大家习惯性觉得 cursor 是服务端自己生成的、可信的,很少会去校验它的内容。可现实是客户端能把任意字符串塞进 after 参数,解码、反序列化一步不落全走了。

还有一层容易漏的:就算你没手动开 default typing,只要项目里某个地方配置过 Jackson 的多态行为,或者引了会自动开它的依赖,这个开关就是开着的。判断自己有没有踩坑,别只看有没有写 @JsonTypeInfo,得看运行期实际的 ObjectMapper 配置。

现在能做什么

第一件事永远是升级。2.0.5 是 OSS 修复版,2.0.4.1 只对买了商业支持的用户开放。

<dependency>
    <groupId>org.springframework.graphql</groupId>
    <artifactId>spring-graphql</artifactId>
    <version>2.0.5</version>
</dependency>

如果暂时升不了,退而求其次的缓解手段是收紧 Jackson 的多态配置。把 activateDefaultTyping 关掉,或者用一个严格的白名单 PolymorphicTypeValidator,只放行你真正需要的类型,别让默认的宽松策略裸奔。

ObjectMapper mapper = JsonMapper.builder()
        .polymorphicTypeValidator(BasicPolymorphicTypeValidator.builder()
                .allowIfSubType("com.example.model")
                .build())
        .build();

再退一步,至少把 cursor 当成不可信输入看。它本应是 opaque 字符串,客户端不该有理由去解析它,你的服务端也不该对它做任何超出”解码回定位对象”以外的处理。

这条漏洞让我重新审视了一个假设:很多团队默认”服务端发出去的东西一定是干净的”。分页游标、JWT 里的 payload、回调里的签名前字段,全都被当成了可信输入。实际上只要它会绕一圈回到服务端、又经过反序列化,就该按不信任处理。这次是 GraphQL 的 cursor,下次可能就在别的协议里。

升级 2.0.5,顺带把 ObjectMapper 的多态配置过一遍,这两件事今天就能做完。

参考:spring.io/security/cve-2026-59285、Sonatype 对 8 月 20 日 Spring 公告批次的追踪分析。


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:云栖码客 云栖 云栖《Spring GraphQL反序列化RCE漏洞》

    评论:0   参与:  0