使用带有 DataProtection API 的 IdentityServer4 进行令牌签名

Using IdentityServer4 with DataProtection API for token signing

我有一个基于 IS4 + Net Core 3.1 的 authentication/authorization 服务器。 由于此身份服务与一些新的以及一些非常旧的应用程序交互,它还会创建 2 个不同的身份验证 cookie 和令牌。 我们目前正在使用 DPAPI 来签署 cookie 和我们需要的其他一些敏感信息。

到目前为止,我们一直在使用证书作为 IS4 中的 SigningCredential,但现在我希望能够使用 DPAPI 以便自动管理密钥轮换,或者至少,我们可以在一个一个地方。

基于IS4 docs我只需要实现ISigningCredentialStoreIValidationKeysStore,但是我不太熟悉这是如何管理的。 我有这样的近似值(我知道,此时它几乎毫无价值):

private class CustomSigningCredentialStore : ISigningCredentialStore
{
    private readonly IKeyManager _keyManager;

    public CustomSigningCredentialStore(IKeyManager keyManager) =>
        _keyManager = keyManager;

    public Task<SigningCredentials> GetSigningCredentialsAsync()
    {
        // For the sake of simplicity, lets assume
        // that this is the correct one
        var currentKey = _keyManager.GetAllKeys().ElementAt(0);

        // Complete

        return new SigningCredentials(...);
    }
}

private class CustomValidationKeysStore : IValidationKeysStore
{
    private readonly IKeyManager _keyManager;

    public CustomValidationKeysStore(IKeyManager keyManager) =>
        _keyManager = keyManager;

    public Task<IEnumerable<SecurityKeyInfo>> GetValidationKeysAsync()
    {
        var keys = _keyManager.GetAllKeys();

        // Complete

        return keys.Select(key => new SecurityKeyInfo(...));
    }
}

老实说,我被这个问题困住了,我不知道如何映射由 DPAPI 生成的当前密钥,它看起来像这样:

<?xml version="1.0" encoding="utf-8"?>
<key id="32f6d43e-97a9-4c4b-b108-e11f65e05cc4" version="1">
  <creationDate>2020-07-31T00:00:00.0886417Z</creationDate>
  <activationDate>2020-07-31T00:00:00.086065Z</activationDate>
  <expirationDate>2020-08-30T00:00:00.086065Z</expirationDate>
  <descriptor deserializerType="Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=3.1.8.0, Culture=neutral, PublicKeyToken=adb9793829ddae60">
    <descriptor>
      <encryption algorithm="AES_256_CBC" />
      <validation algorithm="HMACSHA256" />
      <masterKey p4:requiresEncryption="true" xmlns:p4="http://schemas.asp.net/2015/03/dataProtection">
        <value>h1/a9G8i78kpnHBTEsisA5rk5ppm8vzByquAT2CO1OFnYHCX/eT/yfcFM/JigYkSDj+dupBz9ZZ7/XFMu/uWxg==</value>
      </masterKey>
    </descriptor>
  </descriptor>
</key>

任何见解将不胜感激。

我最近实现了自己的 key-ring 存储,将密钥存储在 Azure Key Vault 中,我在此处发布了相关博客:

Storing the ASP.NET Core Data Protection Key Ring in Azure Key Vault

对于您询问的令牌登录,我首先从 Azure Key Vault 加载它们,然后将其手动添加到 IdentitySever,就像这样(使用一些自定义扩展方法):

// First we load the certificates (that contains the private keys) from Azure Key Vault
var rsaCert = KeyVaultExtensions.LoadCertificate(config, "rsa");
       
//Add RS256 (RSASSA-PKCS1-v1_5 using SHA-256)
builder.AddSigningCredential(rsaCert, "RS256");

此外,我不会尝试使用来自 DPAPI 的密钥作为签名密钥,因为这些密钥不适合用于签名令牌。对于令牌签名,您需要 RSA 或 ECDSA 密钥,最简单的方法是将它们存储在 Azure Key Vault 中。您应该在应用程序外部配置和存储 DPAPI,但这仅用于保护会话 cookie。不签署令牌。

我非常怀疑您能否使用数据保护来为您管理和轮换签名密钥。 DPAPI 颁发并存储在密钥环中的密钥是对称的,而用于密钥签名的密钥需要是非对称的(public/private RSA/ECDSA 密钥)。基本上不兼容。