You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将Windows VM中DPAPI加密的Data Protection密钥迁移至Azure Key Vault

迁移ASP.NET Data Protection密钥至Azure Key Vault并避免用户登出

一、解密DPAPI加密的Data Protection密钥

你尝试直接用ProtectedData.Unprotect失败,核心原因是loadUserProfile=false时,应用池身份使用的是机器级DPAPI加密,而非当前用户级。调整以下步骤即可解密:

正确解密方式

  1. 确保运行解密代码的进程与应用池使用相同身份(比如应用池用LocalSystem,就以本地系统账户运行解密程序)
  2. 使用DataProtectionScope.LocalMachine替换CurrentUser,示例代码:
using System.Security.Cryptography;

// 替换为你从注册表获取的加密密钥Base64值
var encryptedBase64 = "AQAAANCMnd8BFdERjHoAwE/....I19Nf2RdYA==";
var encryptedBytes = Convert.FromBase64String(encryptedBase64);
// 机器级DPAPI解密,匹配loadUserProfile=false的场景
var decryptedBytes = ProtectedData.Unprotect(encryptedBytes, null, DataProtectionScope.LocalMachine);

更可靠的API解密方式

直接利用ASP.NET DataProtection原生API加载并解密密钥,避免手动处理序列化:

using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.DataProtection.XmlEncryption;
using System.Xml.Linq;

// 加载从注册表导出的完整密钥XML
var keyXml = XElement.Parse(@"你的密钥XML内容");

// 创建支持DPAPI解密的DataProtectionProvider
var provider = DataProtectionProvider.Create(new DirectoryInfo(@"C:\temp"), config =>
{
    config.ProtectKeysWithDpapi(); // 默认使用机器级加密范围
});

// 解密XML中的加密密钥
var encryptedSecretElement = keyXml.Descendants(XName.Get("encryptedSecret", "http://schemas.asp.net/2015/03/dataProtection")).Single();
var decryptor = new DpapiXmlDecryptor();
var decryptedSecret = decryptor.Decrypt(encryptedSecretElement);

二、导出密钥为Azure Key Vault支持的PEM格式

Azure Key Vault支持导入对称密钥,需将解密后的明文密钥转换为PEM格式:

using System.Text;
using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel;

// 反序列化解密后的密钥为AuthenticatedEncryptorDescriptor
var serializer = new AuthenticatedEncryptorDescriptorDeserializer();
var descriptor = serializer.Deserialize(decryptedSecret);

// 提取AES加密密钥材料
var aesKey = descriptor.EncryptorKey.GetKeyMaterial();

// 生成PEM格式文件
var pemContent = $"-----BEGIN SYMMETRIC KEY-----\n{Convert.ToBase64String(aesKey, Base64FormattingOptions.InsertLineBreaks)}\n-----END SYMMETRIC KEY-----";
File.WriteAllText(@"C:\temp\data-protection-key.pem", pemContent);

导入到Azure Key Vault

  1. 登录Azure门户,进入目标Key Vault
  2. 进入「密钥」菜单,点击「生成/导入」
  3. 选择「导入」,上传生成的PEM文件,密钥类型选「对称」,有效期可与原密钥的expirationDate保持一致

三、配置站点兼容新旧密钥(避免用户登出)

要确保切换过程中用户不会被迫登出,需让站点同时支持旧的注册表密钥和新的Key Vault密钥,直到旧密钥过期。

步骤1:安装依赖包

Install-Package Microsoft.AspNetCore.DataProtection.AzureKeyVault

步骤2:修改应用配置(Program.cs/Startup.cs)

using Microsoft.AspNetCore.DataProtection;
using Azure.Identity;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddDataProtection()
    // 保留旧的注册表密钥,兼容现有用户票据
    .PersistKeysToRegistry(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ASP.NET\DataProtection\Keys")
    // 添加Azure Key Vault作为新密钥存储
    .PersistKeysToAzureKeyVault(
        new Uri("https://你的密钥库名称.vault.azure.net/keys/data-protection-key"),
        new DefaultAzureCredential()
    )
    // 必须与原站点的ApplicationName完全一致
    .SetApplicationName("你的应用名称");

var app = builder.Build();

// 其他中间件配置...

app.Run();

部署后,站点会:

  • 使用旧注册表密钥解密现有用户的认证票据
  • 将新生成的密钥存储到Azure Key Vault

四、完全切换到Azure Key Vault

等旧密钥的expirationDate到期后(比如示例中的2024-10-22),移除PersistKeysToRegistry配置即可:

builder.Services.AddDataProtection()
    .PersistKeysToAzureKeyVault(
        new Uri("https://你的密钥库名称.vault.azure.net/keys/data-protection-key"),
        new DefaultAzureCredential()
    )
    .SetApplicationName("你的应用名称");

常见问题排查

  • 解密失败:确认运行解密代码的身份与应用池身份完全一致,可用psexec工具以服务账户身份运行程序
  • Key Vault权限不足:确保应用的托管身份/服务主体拥有Key Vault的「Key Manage」「Key Get」「Key List」权限

内容的提问来源于stack exchange,提问作者user27019586

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 20:13:08