[Bug]: Connector OAuth credentials (access token, refresh token, client secret) are stored in plaintext in the database

该报错描述的是 RAGFlow 数据源连接器完成 OAuth 授权后,access token、refresh token 与 client_secret 被明文写入 MySQL connector.config 字段,属于静态存储缺少加密,而不是授权流程本身失败。优先确认部署版本与 connect

快速结论:该报错描述的是 RAGFlow 数据源连接器完成 OAuth 授权后,access token、refresh token 与 client_secret 被明文写入 MySQL connector.config 字段,属于静态存储缺少加密,而不是授权流程本身失败。优先确认部署版本与 connector 表中 config 的实际内容,并核查数据库与宿主机访问权限。

适用环境:Issue 中确认的环境为 Docker 镜像 infiniflow/ragflow:v0.26.4,使用 Google Drive 等基于 OAuth 的数据源连接器,数据库为 MySQL。

最快修复方案:暂无确认的一步修复方案。Issue 讨论中仅提出了设计层面的修复思路(仅加密 config["credentials"],使用 AES-256-GCM,存储格式为 enc:v1: 前缀加 base64),维护者已表示欢迎提交 PR,但讨论中未体现已合并或已验证的修复。

注意事项:在修复落地前,明文凭据一旦泄露即可直接用于访问第三方账号,绕过 RAGFlow 自身的访问控制。讨论中提出的设计明确不含两项内容:GET 接口仍会把解密后的凭据返回浏览器;REST API 连接器的 config.headers 仍可存放游离于 credentials 之外的令牌。因此即使该设计被实现,也不能视为完整的凭据防护。

问题场景

在 RAGFlow 中通过 OAuth 授权 Google Drive(或其他基于 OAuth 的)数据源连接器后,完整的 OAuth 凭据被以明文持久化到 MySQL connector 表的 config 列(longtext 类型,写入前后均未加密)。复现步骤为:部署 RAGFlow、添加 Google Drive 数据源并完成授权流程,然后直接查询 SELECT config FROM connector WHERE source='google_drive';,即可看到 access token、refresh token、client_id 与 client_secret 可读。报告者确认当前 main 分支的 api/apps/restful_apis/connector_api.py 中 create_connector() 也将请求中的 config 原样写入 Connector 模型。

报错原文

[Bug]: Connector OAuth credentials (access token, refresh token, client secret) are stored in plaintext in the database

The full OAuth credential payload is persisted in plaintext in the `connector.config` column
(a `longtext` MySQL field with no encryption applied before or after write).

原因分析

最可能的原因:连接器创建与更新路径(如 create_connector())直接将请求中的 config 写入数据库,缺少应用层对 credentials 的加密步骤。报告者检索 api/ 与 common/ 后未发现用于此类机密的静态加密工具,因此判断这是功能缺口,而不是已有工具未接入。讨论中进一步指出了现有 common/crypto_utils.py 中 CBC helper 的局限:CBC 无法检测密钥错误,且没有 Go 语言移植版本,所以未被纳入拟议方案。

环境排查

  • 确认 RAGFlow 镜像版本(Issue 中为 infiniflow/ragflow:v0.26.4),并对照当前 main 的 connector_api.py 是否仍在原样写入 config。
  • 确认 MySQL 中 connector 表是否存在 config 明文凭据,重点检查 source 为 google_drive 等 OAuth 类型的记录。
  • 检查数据库账号权限、备份文件与宿主机管理工具的访问范围,评估凭据可能暴露的途径。
  • 若考虑采用讨论中的修复方向,需确认部署方式为 Go 服务、Python 服务还是混合模式,并确认是否已配置 server-side key;该设计在未设置密钥时仍按明文存储。

解决步骤

  1. 确认问题存在:按复现步骤查询 connector 表,检查 config 中 credentials 是否可读为明文 JSON。
  2. 收紧暴露面:限制数据库只读账号与备份流程的访问权限,避免非同源人员或工具读取 config 列。
  3. 评估凭据轮换:在第三方提供方侧撤销并重新签发相关凭据,以降低已泄露 refresh token、client_secret 的可用性;Issue 与讨论中未给出具体轮换步骤,需按提供方文档操作。
  4. 关注修复进展:讨论中提出的设计为仅加密 config["credentials"],AES-256-GCM,存储前缀 enc:v1:,密钥为 32 随机字节的 base64,并提供 ragflow_server --migrate 迁移步骤对存量行加密;该方案尚未确认合入,可优先关注后续 PR。
  5. 修复落地后验证兼容性:存量明文 credentials 应可继续读取;无密钥、密钥错误或认证标签校验失败时应报错,而不是把密文交给连接器。

验证方法

当前版本可通过直接查询数据库确认 config 中凭据是否仍为明文;若后续修复落地,则应验证新写入记录的 credentials 以 enc:v1: 开头、无法直接读出令牌,同时存量连接器仍能正常同步,迁移命令重复执行不产生额外改动。

参考来源

infiniflow/ragflow #17265

GamsGo AI

AI 工具推荐

想把多个 AI 模型放在一个入口?

GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。

了解 GamsGo AI

推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 33675

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注