如何在不获取 CryptographicException 的情况下在 Azure WebJob 上签署 JWT 令牌?
How can I sign a JWT token on an Azure WebJob without getting a CryptographicException?
我有一个 WebJob 需要创建一个 JWT 令牌来与外部服务对话。当我 运行 我的本地计算机上的 WebJob 时,以下代码有效:
public static string SignES256(byte[] p8Certificate, object header, object payload)
{
var headerString = JsonConvert.SerializeObject(header);
var payloadString = JsonConvert.SerializeObject(payload);
CngKey key = CngKey.Import(p8Certificate, CngKeyBlobFormat.Pkcs8PrivateBlob);
using (ECDsaCng dsa = new ECDsaCng(key))
{
dsa.HashAlgorithm = CngAlgorithm.Sha256;
var unsignedJwtData = Base64UrlEncoder.Encode(Encoding.UTF8.GetBytes(headerString)) + "." + Base64UrlEncoder.Encode(Encoding.UTF8.GetBytes(payloadString));
var signature = dsa.SignData(Encoding.UTF8.GetBytes(unsignedJwtData));
return unsignedJwtData + "." + Base64UrlEncoder.Encode(signature);
}
}
但是,当我将 WebJob 部署到 Azure 时,出现以下异常:
Microsoft.Azure.WebJobs.Host.FunctionInvocationException: Exception while executing function: NotificationFunctions.QueueOperation ---> System.Security.Cryptography.CryptographicException: The system cannot find the file specified. at System.Security.Cryptography.NCryptNative.ImportKey(SafeNCryptProviderHandle provider, Byte[] keyBlob, String format) at System.Security.Cryptography.CngKey.Import(Byte[] keyBlob, CngKeyBlobFormat format, CngProvider provider)
它说找不到指定的文件,但我传入的参数不是在寻找文件位置,而是在内存中。从我收集到的信息来看,可能需要启用某种加密设置才能使用 CngKey.Import 方法,但我在 Azure 门户中找不到任何设置来配置与此相关的设置。
我也尝试过使用 JwtSecurityTokenHandler,但它似乎无法处理我需要使用的 ES256 哈希算法(即使它在 JwtAlgorithms class 中被引用为 ECDSA_SHA256)。
如有任何建议,我们将不胜感激!
更新
看来 CngKey.Import 可能实际上是在尝试将证书存储在 Azure 上无法访问的某个位置。我不需要存储它,所以如果有更好的方法来访问内存中的证书或将其转换为更易于使用的不同类型的证书,那将是可行的。
更新 2
此问题可能与 Azure Web Apps IIS 设置不加载用户配置文件有关 。我已通过在 Azure 门户应用程序设置中设置 WEBSITE_LOAD_USER_PROFILE = 1 来启用此功能。 运行通过 Azure 中的 WebJob 和 Web 应用程序连接代码时,我已经尝试过此更新,但我仍然收到相同的错误。
我使用了一个反编译器来深入了解 CngKey.Import 方法实际上在做什么。看起来它试图将我正在使用的证书插入 "Microsoft Software Key Storage Provider"。我实际上并不需要这个,只需要读取证书的值,但看起来不可能。
一旦我意识到证书被插入到机器某处的商店中,我开始考虑如果您的 Azure Web 应用程序 运行 在共享环境,就像它对免费层和共享层所做的那样。果然,我的 VM 在共享层上。将其扩展到基本层解决了这个问题。
我有一个 WebJob 需要创建一个 JWT 令牌来与外部服务对话。当我 运行 我的本地计算机上的 WebJob 时,以下代码有效:
public static string SignES256(byte[] p8Certificate, object header, object payload)
{
var headerString = JsonConvert.SerializeObject(header);
var payloadString = JsonConvert.SerializeObject(payload);
CngKey key = CngKey.Import(p8Certificate, CngKeyBlobFormat.Pkcs8PrivateBlob);
using (ECDsaCng dsa = new ECDsaCng(key))
{
dsa.HashAlgorithm = CngAlgorithm.Sha256;
var unsignedJwtData = Base64UrlEncoder.Encode(Encoding.UTF8.GetBytes(headerString)) + "." + Base64UrlEncoder.Encode(Encoding.UTF8.GetBytes(payloadString));
var signature = dsa.SignData(Encoding.UTF8.GetBytes(unsignedJwtData));
return unsignedJwtData + "." + Base64UrlEncoder.Encode(signature);
}
}
但是,当我将 WebJob 部署到 Azure 时,出现以下异常:
Microsoft.Azure.WebJobs.Host.FunctionInvocationException: Exception while executing function: NotificationFunctions.QueueOperation ---> System.Security.Cryptography.CryptographicException: The system cannot find the file specified. at System.Security.Cryptography.NCryptNative.ImportKey(SafeNCryptProviderHandle provider, Byte[] keyBlob, String format) at System.Security.Cryptography.CngKey.Import(Byte[] keyBlob, CngKeyBlobFormat format, CngProvider provider)
它说找不到指定的文件,但我传入的参数不是在寻找文件位置,而是在内存中。从我收集到的信息来看,可能需要启用某种加密设置才能使用 CngKey.Import 方法,但我在 Azure 门户中找不到任何设置来配置与此相关的设置。
我也尝试过使用 JwtSecurityTokenHandler,但它似乎无法处理我需要使用的 ES256 哈希算法(即使它在 JwtAlgorithms class 中被引用为 ECDSA_SHA256)。
如有任何建议,我们将不胜感激!
更新
看来 CngKey.Import 可能实际上是在尝试将证书存储在 Azure 上无法访问的某个位置。我不需要存储它,所以如果有更好的方法来访问内存中的证书或将其转换为更易于使用的不同类型的证书,那将是可行的。
更新 2
此问题可能与 Azure Web Apps IIS 设置不加载用户配置文件有关
我使用了一个反编译器来深入了解 CngKey.Import 方法实际上在做什么。看起来它试图将我正在使用的证书插入 "Microsoft Software Key Storage Provider"。我实际上并不需要这个,只需要读取证书的值,但看起来不可能。
一旦我意识到证书被插入到机器某处的商店中,我开始考虑如果您的 Azure Web 应用程序 运行 在共享环境,就像它对免费层和共享层所做的那样。果然,我的 VM 在共享层上。将其扩展到基本层解决了这个问题。