现在我已经掌握了足够的信息来做一个完整清晰的分析。好的现在我来给出一个完整的分析。Difyprovider_model_credentials.encrypted_config解密分析整体加密架构Dify 使用 PKCS1_OAEP 加密来保护 API key。每个用户tenant都有一个唯一的密钥对确保 API key 的机密性。实际上从源码看Dify 用的是混合加密RSA AES下面是完整的加解密流程图### 核心源码解读加密逻辑api/libs/rsa.pyprefix_hybridbHYBRID:defencrypt(text:str,public_key:...)-bytes:aes_keyget_random_bytes(16)# 随机生成 AES-128 Keycipher_aesAES.new(aes_key,AES.MODE_EAX)ciphertext,tagcipher_aes.encrypt_and_digest(text.encode())# AES 加密明文cipher_rsagmpy2_pkcs10aep_cipher.new(rsa_key)enc_aes_keycipher_rsa.encrypt(aes_key)# RSA-OAEP 加密 AES Key# 拼接成最终密文returnprefix_hybridenc_aes_keycipher_aes.noncetagciphertext所以encrypted_config字段的字节结构为HYBRID: | enc_aes_key(256B) | nonce(16B) | tag(16B) | ciphertext(变长)解密逻辑api/core/provider_manager.py解密时系统通过encrypter.get_decrypt_decoding(tenant_id)获取租户的 RSA 私钥再调用encrypter.decrypt_token_with_decoding对provider_model_credentials中各字段的加密值进行解密。如何手动查看 API Key你需要同时具备两个东西1. 从数据库取出密文-- 找到目标记录SELECTid,tenant_id,model_name,encrypted_configFROMprovider_model_credentialsWHEREprovider_nameopenai;2. 取出对应租户的 RSA 私钥私钥存储位置取决于你的文件存储配置STORAGE_TYPE路径为privkeys/{tenant_id}/private.pem本地部署默认在api/storage/privkeys/{tenant_id}/private.pemS3/OSS 等在对应的 Bucket 中3. 用 Python 脚本解密fromCrypto.PublicKeyimportRSAfromCrypto.CipherimportAESimportbase64 prefixbHYBRID:defdecrypt_api_key(encrypted_hex_or_bytes:bytes,private_key_pem:bytes)-str:# 1. 去掉前缀dataencrypted_hex_or_bytesifdata.startswith(prefix):datadata[len(prefix):]# 2. 加载私钥rsa_keyRSA.import_key(private_key_pem)key_sizersa_key.size_in_bytes()# 256 bytes for RSA-2048# 3. 拆分各部分enc_aes_keydata[:key_size]noncedata[key_size:key_size16]tagdata[key_size16:key_size32]ciphertextdata[key_size32:]# 4. RSA-OAEP 解密 AES Keyfromlibsimportgmpy2_pkcs10aep_cipher# Dify 的 OAEP 实现cipher_rsagmpy2_pkcs10aep_cipher.new(rsa_key)aes_keycipher_rsa.decrypt(enc_aes_key)# 5. AES-EAX 解密明文cipher_aesAES.new(aes_key,AES.MODE_EAX,noncenonce)plaintextcipher_aes.decrypt_and_verify(ciphertext,tag)returnplaintext.decode()# 使用withopen(private.pem,rb)asf:pemf.read()# encrypted_config 字段值bytesapi_keydecrypt_api_key(encrypted_config_bytes,pem)print(api_key)注意事项关键点说明每个 tenant 独立密钥私钥按tenant_id分目录存放不同租户不能互解encrypted_config的格式provider_model_credentials表里存的是 JSON 序列化后的字段级加密每个敏感字段单独加密不是整条记录加密SECRET_KEY环境变量用于 AES-256 加密第三方 OAuth 凭证与 model credentials 是不同的加密路径不要直接改密钥替换 RSA 私钥后已存储的所有encrypted_config都将无法解密简单来说encrypted_config是 RSAAES 混合加密的密文解密必须持有对应tenant_id的 RSA 私钥文件这个文件在你的文件存储后端本地磁盘或对象存储中而不在数据库里。
https://github.com/langgenius/dify查看设置的apikey
发布时间:2026/5/15 19:33:41
现在我已经掌握了足够的信息来做一个完整清晰的分析。好的现在我来给出一个完整的分析。Difyprovider_model_credentials.encrypted_config解密分析整体加密架构Dify 使用 PKCS1_OAEP 加密来保护 API key。每个用户tenant都有一个唯一的密钥对确保 API key 的机密性。实际上从源码看Dify 用的是混合加密RSA AES下面是完整的加解密流程图### 核心源码解读加密逻辑api/libs/rsa.pyprefix_hybridbHYBRID:defencrypt(text:str,public_key:...)-bytes:aes_keyget_random_bytes(16)# 随机生成 AES-128 Keycipher_aesAES.new(aes_key,AES.MODE_EAX)ciphertext,tagcipher_aes.encrypt_and_digest(text.encode())# AES 加密明文cipher_rsagmpy2_pkcs10aep_cipher.new(rsa_key)enc_aes_keycipher_rsa.encrypt(aes_key)# RSA-OAEP 加密 AES Key# 拼接成最终密文returnprefix_hybridenc_aes_keycipher_aes.noncetagciphertext所以encrypted_config字段的字节结构为HYBRID: | enc_aes_key(256B) | nonce(16B) | tag(16B) | ciphertext(变长)解密逻辑api/core/provider_manager.py解密时系统通过encrypter.get_decrypt_decoding(tenant_id)获取租户的 RSA 私钥再调用encrypter.decrypt_token_with_decoding对provider_model_credentials中各字段的加密值进行解密。如何手动查看 API Key你需要同时具备两个东西1. 从数据库取出密文-- 找到目标记录SELECTid,tenant_id,model_name,encrypted_configFROMprovider_model_credentialsWHEREprovider_nameopenai;2. 取出对应租户的 RSA 私钥私钥存储位置取决于你的文件存储配置STORAGE_TYPE路径为privkeys/{tenant_id}/private.pem本地部署默认在api/storage/privkeys/{tenant_id}/private.pemS3/OSS 等在对应的 Bucket 中3. 用 Python 脚本解密fromCrypto.PublicKeyimportRSAfromCrypto.CipherimportAESimportbase64 prefixbHYBRID:defdecrypt_api_key(encrypted_hex_or_bytes:bytes,private_key_pem:bytes)-str:# 1. 去掉前缀dataencrypted_hex_or_bytesifdata.startswith(prefix):datadata[len(prefix):]# 2. 加载私钥rsa_keyRSA.import_key(private_key_pem)key_sizersa_key.size_in_bytes()# 256 bytes for RSA-2048# 3. 拆分各部分enc_aes_keydata[:key_size]noncedata[key_size:key_size16]tagdata[key_size16:key_size32]ciphertextdata[key_size32:]# 4. RSA-OAEP 解密 AES Keyfromlibsimportgmpy2_pkcs10aep_cipher# Dify 的 OAEP 实现cipher_rsagmpy2_pkcs10aep_cipher.new(rsa_key)aes_keycipher_rsa.decrypt(enc_aes_key)# 5. AES-EAX 解密明文cipher_aesAES.new(aes_key,AES.MODE_EAX,noncenonce)plaintextcipher_aes.decrypt_and_verify(ciphertext,tag)returnplaintext.decode()# 使用withopen(private.pem,rb)asf:pemf.read()# encrypted_config 字段值bytesapi_keydecrypt_api_key(encrypted_config_bytes,pem)print(api_key)注意事项关键点说明每个 tenant 独立密钥私钥按tenant_id分目录存放不同租户不能互解encrypted_config的格式provider_model_credentials表里存的是 JSON 序列化后的字段级加密每个敏感字段单独加密不是整条记录加密SECRET_KEY环境变量用于 AES-256 加密第三方 OAuth 凭证与 model credentials 是不同的加密路径不要直接改密钥替换 RSA 私钥后已存储的所有encrypted_config都将无法解密简单来说encrypted_config是 RSAAES 混合加密的密文解密必须持有对应tenant_id的 RSA 私钥文件这个文件在你的文件存储后端本地磁盘或对象存储中而不在数据库里。