https://github.com/langgenius/dify查看设置的apikey

现在我已经掌握了足够的信息,来做一个完整清晰的分析。好的,现在我来给出一个完整的分析。

Dify provider_model_credentials.encrypted_config 解密分析

整体加密架构

Dify 使用 PKCS1_OAEP 加密来保护 API key。每个用户(tenant)都有一个唯一的密钥对,确保 API key 的机密性。

实际上从源码看,Dify 用的是混合加密(RSA + AES),下面是完整的加解密流程图:### 核心源码解读

加密逻辑 (api/libs/rsa.py):

python 复制代码
prefix_hybrid = b"HYBRID:"

def encrypt(text: str, public_key: ...) -> bytes:
    aes_key = get_random_bytes(16)             # 随机生成 AES-128 Key
    cipher_aes = AES.new(aes_key, AES.MODE_EAX)
    ciphertext, tag = cipher_aes.encrypt_and_digest(text.encode())  # AES 加密明文

    cipher_rsa = gmpy2_pkcs10aep_cipher.new(rsa_key)
    enc_aes_key = cipher_rsa.encrypt(aes_key)  # RSA-OAEP 加密 AES Key

    # 拼接成最终密文
    return prefix_hybrid + enc_aes_key + cipher_aes.nonce + tag + ciphertext

所以 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. 从数据库取出密文

sql 复制代码
-- 找到目标记录
SELECT id, tenant_id, model_name, encrypted_config
FROM provider_model_credentials
WHERE provider_name = 'openai';

2. 取出对应租户的 RSA 私钥

私钥存储位置取决于你的文件存储配置(STORAGE_TYPE),路径为 privkeys/{tenant_id}/private.pem:

  • 本地部署:默认在 api/storage/privkeys/{tenant_id}/private.pem
  • S3/OSS 等:在对应的 Bucket 中

3. 用 Python 脚本解密

python 复制代码
from Crypto.PublicKey import RSA
from Crypto.Cipher import AES
import base64

prefix = b"HYBRID:"

def decrypt_api_key(encrypted_hex_or_bytes: bytes, private_key_pem: bytes) -> str:
    # 1. 去掉前缀
    data = encrypted_hex_or_bytes
    if data.startswith(prefix):
        data = data[len(prefix):]

    # 2. 加载私钥
    rsa_key = RSA.import_key(private_key_pem)
    key_size = rsa_key.size_in_bytes()  # 256 bytes for RSA-2048

    # 3. 拆分各部分
    enc_aes_key = data[:key_size]
    nonce       = data[key_size:key_size+16]
    tag         = data[key_size+16:key_size+32]
    ciphertext  = data[key_size+32:]

    # 4. RSA-OAEP 解密 AES Key
    from libs import gmpy2_pkcs10aep_cipher  # Dify 的 OAEP 实现
    cipher_rsa = gmpy2_pkcs10aep_cipher.new(rsa_key)
    aes_key = cipher_rsa.decrypt(enc_aes_key)

    # 5. AES-EAX 解密明文
    cipher_aes = AES.new(aes_key, AES.MODE_EAX, nonce=nonce)
    plaintext = cipher_aes.decrypt_and_verify(ciphertext, tag)
    return plaintext.decode()

# 使用
with open("private.pem", "rb") as f:
    pem = f.read()

# encrypted_config 字段值(bytes)
api_key = decrypt_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 是 RSA+AES 混合加密的密文,解密必须持有对应 tenant_id 的 RSA 私钥文件,这个文件在你的文件存储后端(本地磁盘或对象存储)中,而不在数据库里。

相关推荐
又过二十8 小时前
用 Electron 做的 AI 视频切片工作台:VClip 的技术选型与踩坑实录
ai·electron·aigc·funasr·视频切片
xcLeigh14 小时前
FreeRTOS实战:用STM32+SEGGER打造工业级实时嵌入式系统
人工智能·stm32·单片机·嵌入式硬件·ai
老唐77715 小时前
大模型面试高频题:Transformer、MoE、RLHF、DPO 核心原理拆解
人工智能·深度学习·ai·大模型·transformer·智能体
小七-七牛开发者15 小时前
Agent 支线知识:Personal Agent 如何理解个人意图?
ai·agent·ai智能体·长期记忆·personalagent
数智奔流16 小时前
技术至上的kimi,遇到了全球化难题
ai·ai大模型·kimi
长空任鸟飞_阿康17 小时前
如何设计支持 Skills 的 Agent?一套可扩展的四层架构
python·ai·架构·skills
2601_9620710017 小时前
从OpenRouter到Crazyrouter:Claude Code三处改动
人工智能·ai
cmdch201717 小时前
我的ai之旅——ai短剧绯面:无衣(deepseek+comfy ui)
ai
枝上棉蛮18 小时前
AI生成3D模型工具TOP5:造形家、Meshy、Tripo3D、Luma AI、混元3D怎么选
ai·ai三维建模工具·场地模型·ai生成3d模型·3d资产·建筑模型·游戏角色
Ven%18 小时前
在魔搭 Notebook 容器里跑 Qwen Code:从零配置到省魔粒的完整实践
人工智能·python·ai·ai编程·modelscope