资讯详情

Dify模型供应商API Key解密全攻略:从PostgreSQL还原明文密钥

📅 2026/10/16 4:45:22 | 华诺云谱 👁 阅读
Dify模型供应商API Key解密全攻略:从PostgreSQL还原明文密钥
先别急着翻配置文档我直接说结论如果你用的是Docker Compose部署的Dify模型供应商的API Key虽然不会明文存在数据库里但只要你的SECRET_KEY还在就有办法把密文解出来。这篇东西就是干这个用的——我会从Dify到底怎么存Key讲起再带你一步步连进PostgreSQL把加密配置捞出来最后用一段Python脚本配合SECRET_KEY还原出明文API Key。整个过程适用于查账、迁移、对接其他系统时需要重新拿到Key明文的人也包括那些刚接手别人部署的Dify、前任没留下任何交接记录的倒霉蛋。先说清楚这不是教你去破解什么而是拿回属于你自己的系统配置。Dify后台的模型供应商页面只会显示一串掩码比如sk-****abcd点编辑也不会给你看完整明文。你真正能做的就两条路要么在后台重新填一个新Key要么从数据库里把加密的配置解密出来。前者适合Key还能正常用、你只是想换个新的场景后者适合你确实需要旧Key的明文比如要迁移到另一套系统、要做费用审计、或者供应商那边需要你提供Key来核对用量。我下面讲的就是第二条路。1. 先搞清楚API Key在Dify里到底存成了什么样1.1 不是忘了是Dify根本没打算让你再看到明文很多第一次操作的人会陷入一个思维误区以为登录Dify后台、找到模型供应商页面就能像看密码一样“显示”出完整的API Key。实际上Dify的产品设计里API Key一旦保存就不会再以明文形式回显给你。这跟你在各种网站后台看到的“密码不可见”是一个道理属于安全设计不是产品缺陷。所以“找回API Key”这句话严格意义上分两种情况。一种是找回“能继续用的凭据”那最简单的办法就是重置一个新Key填进去另一种是找回“当初那串明文”那就得走解密这条路。从我的实际经验看大部分人以为自己需要的是前者但真到操作的时候往往是后者——因为他们在模型供应商那边申请了好几个Key分不清Dify里用的是哪一个或者财务要核对账单必须知道Dify上绑定的是哪把Key。还有一个高频场景是接手别人的系统。某公司请外包团队搭了一套Dify交接文档里只写了“模型供应商已配置完成”API Key散落在某个同事的聊天记录里等那人离职就彻底失联了。这时候你能依靠的除了重新申请新Key就只剩下数据库里那串密文。1.2 存储机制数据表里的密文和SECRET_KEYDify的模型供应商配置不是直接明文写在某个配置文件里的。你填好Key点保存之后它会经过一层Fernet对称加密然后以密文形式存进PostgreSQL数据库的providers表字段名叫encrypted_config。这里要划一个重点它是“加密存储”不是“哈希存储”。哈希是不可逆的你永远没法从哈希值反推原文但加密是可逆的只要你手里有密钥就能解回来。Dify用来加密的密钥就是部署时配置的环境变量SECRET_KEY。这串东西在Docker Compose部署方式下写在docker-compose.yml或者.env文件里在源码部署方式下写在.env文件里。所以整条链路非常清晰数据库providers表里存的是密文SECRET_KEY是解开密文的钥匙。只要这两个东西你都能拿到还原明文API Key就是一次标准解密操作。反过来如果你连SECRET_KEY也一起丢了那基本等于把钥匙锁进了保险柜解密这条路就彻底断了。1.3 找回之前必须先确认的三件事在动手之前先把下面三件事确认清楚否则折腾半天很可能白忙。第一部署方式。不同部署方式决定了数据库在哪、SECRET_KEY在哪。Docker Compose部署是最常见的数据库跑在docker-db-1容器里SECRET_KEY在环境变量里如果你是源码部署那PostgreSQL可能是独立装的SECRET_KEY在项目根目录的.env里如果你用的是Kubernetes那SECRET_KEY存在K8s的Secret对象里还得先找到对应的Secret名。第二数据库访问权限。这一步需要用psql连进PostgreSQL所以你得知道数据库的用户名、密码和库名。Docker Compose部署时这些信息一般也在.env或docker-compose.yml里比如POSTGRES_USER、POSTGRES_PASSWORD、POSTGRES_DB。第三SECRET_KEY是否还在。这个最关键。你可以去docker-compose.yml或者.env里搜一下SECRET_KEY看到形如SECRET_KEYyour-random-string的配置就是它。需要提醒一句有些部署者图省事会把SECRET_KEY写成默认值或者留空这让解密无从谈起——没有正确的密钥密文就是一堆无法还原的乱码。这三件事都确认无误后才能进入下一步的实操。缺少任何一项都建议直接跳到第5章走重置方案。2. 找Key前置准备确认部署形态与关键凭证2.1 三种部署方式下的环境变量定位我遇到的Dify部署绝大多数逃不出下面三种形态。每种形态下你找东西的位置完全不同列个表方便对照。部署方式PostgreSQL在哪SECRET_KEY在哪需要准备的工具Docker Compose名为 docker-db-1 的容器内docker-compose.yml 的 environment或同目录 .envdocker 命令、psql源码运行独立安装的 PostgreSQL 服务项目根目录的 .env 文件psql 客户端Kubernetes集群内的 PostgreSQL Pod 或外部实例名为 dify-secret 之类的 Secret 对象kubectl、psql这里要特别说明一下Docker Compose部署。绝大多数个人开发者和中小团队都用这种方式因为官方文档一句话“docker compose up -d”就能跑起来。在这种模式下docker-compose.yml里通常会有这样的片段environment: SECRET_KEY: your-secret-key-value POSTGRES_USER: postgres POSTGRES_PASSWORD: difyai123456 POSTGRES_DB: dify注意SECRET_KEY的值有可能是直接写进docker-compose.yml的也有可能是通过${SECRET_KEY}从.env文件引用的。如果你只看到引用变量记得去同目录下的.env里找真值。2.2 实际操作先用docker命令确认容器状态不太确定自己部署方式的情况下先敲一条命令看看正在跑的容器docker ps --format table {{.Names}}\t{{.Image}}\t{{.Ports}}正常情况下你会看到docker-nginx-1、docker-api-1、docker-worker-1、docker-db-1、docker-redis-1这些容器。其中docker-db-1就是PostgreSQL所在的容器而docker-api-1里跑的Dify API服务才是真正执行加密解密的代码。顺手把docker-db-1的端口映射看一眼——很多配置会把5432映射到宿主机方便本地管理例如0.0.0.0:5432-5432/tcp。如果你看到这个映射后面直接用宿主机的5432端口连接就行没映射也没关系在容器内直接执行psql也一样。2.3 动手前的安全备份对数据库做任何查询之前先备份。备份不是多余动作而是防止你在操作过程中出现手误——比如有人习惯性地敲了UPDATE而不是SELECT一条语句下去密文就被改坏了。Dify的日志里每天都有大量AI应用调用一旦providers表数据损坏模型供应商配置就得全部重新填。备份命令很简单进容器执行docker exec docker-db-1 pg_dump -U postgres -d dify -t providers providers_backup.sql这条命令只备份providers表因为解密只需要这张表的数据。如果你担心其他配置表也被影响到可以不指定-t参数直接把整个库导出。备份文件生成后放在当前目录后续操作即便出了问题也能随时恢复。3. 实战从数据库里把加密配置捞出来3.1 进入PostgreSQL容器并连接数据库前置工作做完开始进数据库。先用docker exec进入docker-db-1容器然后用psql连接docker exec -it docker-db-1 psql -U postgres -d dify这里-U和-d的值要跟你在docker-compose.yml或.env里看到的POSTGRES_USER、POSTGRES_DB保持一致。如果你发现默认用户名不是postgres换成实际的就行。连进去之后命令提示符会变成dify#说明你已经进了Dify的数据库。如果提示密码错误检查一下POSTGRES_PASSWORD。顺便说一个经验Dify官方提供的docker-compose.yml模板里默认密码是difyai123456如果你没改过用这个就能登进去。当然这只是默认值生产环境务必改掉。3.2 定位tenant、provider、token记录进入数据库之后第一件事是看看有哪些表\dt你会在输出里看到一堆表其中跟模型供应商配置有关的主要是这几张tenants租户表Dify里每个工作区对应一个租户providers模型供应商配置表核心目标provider_models模型与供应商的绑定关系表先看租户确认你要找的工作区对应哪个租户IDSELECT id, name FROM tenants;输出大概长这样id | name ------------------------------------------------- xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx | 默认工作区记下你所在的租户ID接着查这个租户下配置了哪些自定义模型供应商SELECT tenant_id, provider_name, provider_type, encrypted_config FROM providers WHERE tenant_id 你的租户ID AND provider_type custom AND encrypted_config IS NOT NULL;这一步你会看到encrypted_config字段里是一长串以gAAAAAB开头的密文。看到这个前缀基本可以确认数据是Fernet加密的。如果你只想快速确认系统里有哪些供应商不看密文也可以只查前几个字段。3.3 为什么不能直接在数据库改明文查到密文之后有的读者可能会想“我直接把encrypted_config改成明文JSONDify不就能读到了”千万别这么干。Dify读取供应商配置时会先调用解密函数把encrypted_config解开再解析成JSON对象。如果你把密文替换成明文解密函数会直接抛异常轻则这个模型供应商在后台显示配置错误重则API服务启动失败。所以正确的流程是密文只用来解密查看永远不要在数据库里直接改动它。你要是真想修改配置正路是去Dify后台的模型供应商页面操作让Dify自己加密写入。4. 解密用SECRET_KEY还原明文API Key4.1 Fernet加密的原理用一句话说清Fernet是对称加密方案加密和解密用同一把钥匙。打个比方你把备用钥匙藏在保险柜里这本身是安全的但前提是你必须记得保险柜密码。Dify做的事是拿SECRET_KEY做SHA-256运算把结果做URL-safe的Base64编码再当作Fernet密钥去加密你的API Key配置。整个加密过程发生在你每次点击“保存”按钮的时候而解密过程则发生在Dify每次发起模型调用之前。你不需要理解Fernet的底层分组密码细节只要知道一件事SECRET_KEY 密文 → 明文。缺了SECRET_KEY密文就跟天书一样。4.2 解密脚本实战回到你的宿主机新建一个Python脚本比如叫decrypt_dify_key.py把以下内容贴进去import json import hashlib import base64 from cryptography.fernet import Fernet # 替换成你的SECRET_KEY secret_key your-secret-key-value # 替换成从数据库查到的encrypted_config字段值 encrypted_config gAAAAABxxxxxx... # 第一步计算SECRET_KEY的SHA-256摘要 digest hashlib.sha256(secret_key.encode()).digest() # 第二步做URL-safe的Base64编码得到Fernet密钥 fernet_key base64.urlsafe_b64encode(digest) # 第三步创建Fernet解密器 fernet Fernet(fernet_key) # 第四步解密并解析JSON try: decrypted_bytes fernet.decrypt(encrypted_config.encode()) config json.loads(decrypted_bytes.decode()) print(json.dumps(config, indent2, ensure_asciiFalse)) except Exception as e: print(解密失败:, e)逐行解释一下。第一步的SHA-256是为了把任意长度的SECRET_KEY统一成固定长度的字节。第二步转成URL-safe Base64是因为Fernet要求密钥必须是32字节的URL-safe Base64字符串。第三步创建解密器第四步尝试解密并打印。这里有个细节不要直接把encrypted_config当作普通字符串打印因为不同模型供应商的密文长度差异很大打印出来也不利于你找到API Key字段。运行脚本之前先装依赖pip install cryptography然后执行python decrypt_dify_key.py解密成功的话你会看到类似这样的输出{ api_key: sk-xxxxxxxxxxxxxxxxxxxxxxxx, api_base: https://api.example.com/v1, model: gpt-4o }不同模型供应商的字段名会略有差异常见的有api_key、api_base、api_type等。你重点关注api_key字段那个值就是Dify里正在使用的真实API Key。4.3 解密常见报错与处理解密过程中你大概率会遇到几个报错我把最常见的列一下。报错InvalidToken意思是Fernet解密时发现密文不合法。这通常有三种原因SECRET_KEY填错了、密文复制的时候被截断、或者数据库里存的根本不是你想要的这条记录。处理办法是先检查SECRET_KEY有没有少字符再去数据库用length(encrypted_config)确认密文长度是否完整。报错UnicodeDecodeError说明解密出来了字节串但转成字符串失败。这种情况多半是因为你拿到的encrypted_config不是完整的JSON密文而是某个嵌套字段。回去看看是不是查错了字段确认你是从providers表的encrypted_config字段取的而不是provider_models表里的某列。还有一种情况是脚本直接报ModuleNotFoundError那就是cryptography库没装好重新执行pip install cryptography即可。4.4 拿到明文后先做两件事明文API Key到手别急着关终端。先做两件事能省掉你后续很多麻烦。第一立刻去模型供应商的控制台核对一下这把Key的状态。看看它是不是还处于有效状态、额度还剩多少、最近有没有调用记录。这一步能确认你解出来的是不是当前正在使用的那把Key避免出现“解出了Key但根本没用过”的情况。第二把Key存进密码管理器。我见过太多人花了半小时解密然后把明文复制到聊天窗口里发给同事转头就忘了。正确做法是用本地的密码管理器保存或者至少写进一个加密的归档文件。如果你现在手里没有密码管理器先用chmod 600限制权限的文本文件存着后面再补归档。5. 如果解密这条路走不通怎么办5.1 重置流在Dify后台重新配置模型供应商如果SECRET_KEY丢了、数据库连不上、或者解密脚本反复报错最务实的方案是重置。流程非常简单登录Dify后台找到模型供应商页面点已配置的供应商条目选择编辑或重新填入新Key然后测试连接。整个过程两分钟代价只是旧Key作废、需要确保新Key还有对应额度。这也符合安全常识不确定Key是否泄露的时候轮换是优先选择。类比一下家门钥匙丢了比起研究怎么用铁丝开锁不如直接把锁芯换掉成本更低安全性反而更高。模型供应商的API Key同理重新生成一把新的旧的直接作废你也不需要再纠结旧Key去哪了。5.2 去模型供应商侧找回原始Key所有主流模型供应商的控制台里API Key管理页面都会展示Key列表。你可以看到每把Key的创建时间、最后使用时间、额度消耗情况。教材级的操作是用这些元数据去对照Dify里模型的调用时间找到那把“看起来正在被Dify使用的Key”然后在供应商侧重新生成一把同权限的新Key。不过有一点必须提醒绝大多数模型供应商在创建Key时只显示一次明文页面刷新后就再也看不到完整Key了。所以“找回原始Key”在供应商侧通常不是字面意义的找回而是“识别出旧Key并创建新Key”。你需要做的就是把新Key填进Dify替换掉旧的。5.3 一些不太推荐的偏门思路聊几个你在网上可能会看到的野路子我直接帮你把坑填了。网络抓包不推荐。Dify和模型供应商之间的请求是HTTPS加密的除非你在API容器里额外装了代理并且拥有解密SSL的能力否则抓到的全是密文。更麻烦的是为了抓一次Key去改Dify的网络链路完全是给自己找事。日志排查基本没戏。Dify的运行日志不会记录完整的API Key倒是可能在异常栈里带出配置片段。概率低到可以忽略不值得专门去翻。翻聊天记录和邮件这个反而值得试试。很多人当时配置Key时会把Key发在团队聊天工具里或者写在采购邮件里。我帮人处理过一个案例最后是在公司内部的采购申请单附件里找到的Key明文跟解密结果完全一致。所以先在自己人的通信记录里搜一遍成本最低。5.4 方案对比帮你快速做决定方案可行度风险适用场景数据库解密高低但依赖SECRET_KEY需要旧Key明文、审计、迁移后台重置新Key极高极低旧Key作废只是想继续使用Dify不关心旧Key供应商侧找回/重建高低需要登录供应商控制台需要确认Key归属、账务核对抓包/日志极低高操作复杂且大概率无效基本不推荐从我的经验来说除非明确需要旧Key的明文否则无条件推荐重置方案。解密适合一次性审计或迁移场景日常运维不应该依赖它。6. 安全收尾与日常防护建议6.1 拿到Key后立刻要做的4件事第一把Key存进密码管理器设置好归属标签例如“Dify生产环境-模型供应商A”。第二如果怀疑Key可能已经泄露——包括但不限于曾发到过聊天工具、存在过公共代码仓库、被截图传播过——立刻去供应商控制台吊销并重建一把。第三清空当前终端的历史记录history -c只在当前会话有效更保险的是直接关掉终端窗口。第四把解密得到的完整配置包括api_base等字段拍照或存档方便后续与供应商对账。这里专门提一下剪贴板的问题。解密脚本运行后明文Key会留在系统剪贴板里。如果你接下来在浏览器里粘贴其他内容有概率被某些应用读取剪贴板。建议复制Key之后随手复制一段无关文本覆盖剪贴板内容。6.2 团队协作时的密钥交接清单如果你是团队里负责Dify运维的人把下面这份清单当成交接文档的标准模板。明确记录部署方式Docker Compose/源码/K8s和部署目录位置。记录SECRET_KEY的存放位置并提醒自己人这串值丢了等于数据加密的钥匙丢了。模型供应商的全部API Key统一归档在团队密码管理器里不依赖任何个人聊天记录。记录每个Key对应的Dify环境生产/测试、权限范围、额度上限。设定季度审计提醒每季度检查一次各Key是否还在使用、额度是否异常。我踩过的坑是有次团队交接前任把SECRET_KEY写在docker-compose.yml里但这份文件在服务器上被改过.env里的值跟实际不一致导致解密时拿到了错误的密钥。所以交接文档不仅要写“在哪”还要写“哪个是当前生效的”。6.3 日常防忘的3个习惯习惯一创建新API Key的当天就完成归档不要等“有空再记”。人脑的记忆不可靠而API Key是纯随机字符串根本没法靠记忆。习惯二Dify的SECRET_KEY单独备份到一个离线介质。我见过有人把它存在服务器上的.env里后来整个磁盘坏掉连备份一起没了。把SECRET_KEY写进一个加密压缩包放到本地U盘或者密码管理器里多一份保险。习惯三定期轮换。API Key不是设置完就能永久用的供应商那边随时可能因为安全策略调整而强制轮换。提前养成轮换习惯比急着在故障发生时临时换Key要从容得多。实际上我处理过的最顺利的一次找回前后不到十分钟查数据库、拿SECRET_KEY、跑脚本、拿到Key一气呵成。但那次的前提是SECRET_KEY被规规矩矩地存在密码管理器里数据库密码也有文档记录。所以你看解密本身不难难的是平时有没有把该记的东西记好。这篇文章教你的不只是解密技巧更是提醒你API Key的明文、SECRET_KEY的值、部署配置的存放位置这些都是运维资产的组成部分该归档归档该备份备份。真到需要“找回”的那一刻你才有路可走。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑