【Azure API 管理】APIM 配置Validate-JWT策略,验证RS256非对称(公钥/私钥)加密的Token

本文涉及的产品
密钥管理服务KMS,1000个密钥,100个凭据,1个月
简介: 【Azure API 管理】APIM 配置Validate-JWT策略,验证RS256非对称(公钥/私钥)加密的Token

问题描述

在APIM中配置对传入的Token进行预验证,确保传入后端被保护的API的Authorization信息正确有效,可以使用validate-jwt策略。validate-jwt 策略强制要求从指定 HTTP 标头或指定查询参数提取的 JSON Web 令牌 (JWT) 必须存在且有效。validate-jwt 策略支持 HS256 和 RS256 签名算法。

  • 对于 HS256,必须在策略中以 base64 编码形式提供内联方式的密钥。
  • 对于 RS256,密钥可以通过 Open ID 配置终结点来提供,或者通过提供包含公钥或公钥的模数指数对的已上传证书的 ID 来提供。

在最开始使用HS256签名算法的Token时,在validate-jwt策略中配置 issuer-signing-keys就能成功验证JWT,但是当使用RS256签名算法适合,这样就不行。会抛出 'System.NotSupportedException: IDX10634: Unable to create the SignatureProvider.\nAlgorithm: 'RS256', SecurityKey: 'Microsoft.IdentityModel.Tokens.SymmetricSecurityKey... 错误。

 

HS256配置

<validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="Unvalid authorization" require-expiration-time="true" require-signed-tokens="true">
            <issuer-signing-keys>
                <key>在HS256算法中使用的密钥,进行base64编码后的值</key>
            </issuer-signing-keys>
            <audiences>
                <audience>在生成JWT Token时设置的aud值</audience>
            </audiences>
   </validate-jwt>

RS256配置(附带错误消息)

<validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="Unvalid authorization" require-expiration-time="true" require-signed-tokens="true">
            <issuer-signing-keys>
            <key><RS256 公钥内容通过base64编码后的值></key>
            </issuer-signing-keys>
            <audiences>
                <audience>在生成JWT Token时设置的aud值</audience>
            </audiences>
</validate-jwt>

在进行验证时错误消息(文末附录中包含如何在APIM门户中通过Test功能检测策略的执行结果及错误

validate-jwt (-0.132 ms)
    {
"message": "JWT Validation Failed: IDX10503: Signature validation failed. 
Keys tried: 'Microsoft.IdentityModel.Tokens.SymmetricSecurityKey, KeyId: '', InternalId: 'HuvkEY3HBhujvk2qeDfgPFD2iYc-GYrnlDX6Yd1LsYQ'. ,
 KeyId: \r\n'.\nExceptions caught:\n 'System.NotSupportedException: IDX10634: Unable to create the SignatureProvider.\nAlgorithm: 'RS256',
SecurityKey: 'Microsoft.IdentityModel.Tokens.SymmetricSecurityKey, KeyId: '', 
InternalId: 'HuvkEY3HBhujvk2qeDfgPFD2iYc-GYrnlDX6Yd1LsYQ'.'\n is not supported. 
The list of supported algorithms is available here: https://aka.ms/IdentityModel/supported-algorithms\r\n   
at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateSignatureProvider(SecurityKey key, String algorithm, Boolean willCreateSignatures, Boolean cacheProvider)\r\n   
at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForVerifying(SecurityKey key, String algorithm, Boolean cacheProvider)\r\n   
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(Byte[] encodedBytes, Byte[] signature, SecurityKey key, String algorithm, SecurityToken securityToken, TokenValidationParameters validationParameters)\r\n   
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(String token, 
TokenValidationParameters validationParameters)\r\n'.
\ntoken: '{\"typ\":\"jwt\",\"alg\":\"RS256\"}.{\"aud\":\"xxxxx.azure-api.cn\",\"user_id\":123456,\"username\":\"lutpython\",\"exp\":1631786725}'.."
}

那么, 如何来解决RS256 JWT的验证问题呢?

 

解决方案

正如APIM官网中特别提醒的一句话“对于 RS256,密钥可以通过 Open ID 配置终结点来提供,或者通过提供包含公钥或公钥的模数指数对的已上传证书的 ID 来提供 (英文原文:For RS256 the key may be provided either via an Open ID configuration endpoint, or by providing the ID of an uploaded certificate that contains the public key or modulus-exponent pair of the public key.)” , 所以APIM 中的validate-jwt是不支持使用直接配置公钥(Public Key)。 目前的方案有两种:

1) 使用openid configuration, OpenID Configuration中包含了公钥的内容,是有提供Token的权限服务器管理提供(如 Azure AD中就自动包含OpenID Configuration Endpoint).  注:这部分的详细介绍可以参考官网:https://docs.azure.cn/zh-cn/api-management/api-management-access-restriction-policies#azure-active-directory-token-validation

2) 把有证书机构(CA)颁发的包含公钥(Publick Key)的 .pfx证书上传到APIM中,然后配置 key certificate-id="<上传在APIM证书中的ID值>"  

<validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="Unvalid authorization" require-expiration-time="true" require-signed-tokens="true">
            <issuer-signing-keys>
                <key certificate-id="<上传在APIM证书中的ID值>" />
            </issuer-signing-keys>
            <audiences>
                <audience>在生成JWT Token时设置的aud值</audience>
            </audiences>
        </validate-jwt>

 

方案步骤

可以使用以下的步骤来验证RS256 JWT:

1) 使用 openssl 指令创建 证书 (Local.pfx)

openssl.exe req -x509 -nodes -sha256 -days 3650 -subj "/CN=Local" -newkey rsa:2048 -keyout Local.key -out Local.crt

openssl.exe pkcs12 -export -in Local.crt -inkey Local.key -CSP "Microsoft Enhanced RSA and AES Cryptographic Provider" -out Local.pfx

openssl.exe 下载地址:https://slproweb.com/products/Win32OpenSSL.html, 使用时需要 cd到 openssl.exe所在的bin目录中

 

2)上传 Local.pfx 文件到APIM,并自定义证书ID, 如:apim-rs256-01

 

3)在APIM的策略中(API级,单个操作级别,或者一组API[产品], 或者全部的APIs)。validate-jwt 内容如下:

<policies>
    <inbound>
        <base />
        <validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="401 unauthorized">
            <issuer-signing-keys>
                <key certificate-id="apim-rs256-01" />
            </issuer-signing-keys>
        </validate-jwt>
    </inbound>
    <backend>
        <base />
    </backend>
    <outbound>
        <base />
    </outbound>
    <on-error>
        <base />
    </on-error>
</policies>

4) 使用以下的C#代码生成 Token

using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleAppjwt
{
    class Program
    {
        static void Main(string[] args)
        {            // Token Generation
            var CLIENT_ID = "Local";
            var ISSUER_GUID = "b0123cec-86bb-4eb2-8704-dcf7cb2cc279";
            var filePath = @"C:\Users\xxxx\source\repos\ConsoleAppjwt\ConsoleAppjwt\Cert\Local.pfx";
            var x509Certificate2 = new X509Certificate2(filePath, "123456789");
            var signingCredentials = new X509SigningCredentials(x509Certificate2, SecurityAlgorithms.RsaSha256Signature); //, SecurityAlgorithms.Sha256Digest
            var tokenHandler = new JwtSecurityTokenHandler();
            var originalIssuer = $"{CLIENT_ID}";
            var issuer = originalIssuer;
            DateTime utcNow = DateTime.UtcNow;
            DateTime expired = utcNow + TimeSpan.FromHours(1);
            var claims = new List<Claim> {
         new Claim("aud", "https://login.microsoftonline.com/{YOUR_TENENT_ID}/oauth2/token", ClaimValueTypes.String, issuer, originalIssuer),
         new Claim("exp", "1460534173", ClaimValueTypes.DateTime, issuer, originalIssuer),
         new Claim("jti", $"{ISSUER_GUID}", ClaimValueTypes.String, issuer, originalIssuer),
         new Claim("nbf", "1460533573", ClaimValueTypes.String, issuer, originalIssuer),
         new Claim("sub", $"{CLIENT_ID}", ClaimValueTypes.String, issuer, originalIssuer)
     };
            ClaimsIdentity subject = new ClaimsIdentity(claims: claims);
            var tokenDescriptor = new SecurityTokenDescriptor
            {
                Subject = subject,
                Issuer = issuer,
                Expires = expired,
                SigningCredentials = signingCredentials,
            };
            JwtSecurityToken jwtToken = tokenHandler.CreateToken(tokenDescriptor) as JwtSecurityToken;
            jwtToken.Header.Remove("typ");
            var token = tokenHandler.WriteToken(jwtToken);
            Console.WriteLine(token);
            //Start to Verify Token
            Console.WriteLine("Start to Verify Token");
            ValidationToken(token);
            Console.ReadLine();
        }
        static void ValidationToken(string token)
        {
            try
            {
                JwtSecurityTokenHandler jwtHandler = new JwtSecurityTokenHandler();
                var filePath = @"C:\Users\xxxx\source\repos\ConsoleAppjwt\ConsoleAppjwt\Cert\Local.pfx";
                TokenValidationParameters tvParameter = new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new X509SecurityKey(new X509Certificate2(filePath, "123456789")),
                    ValidateIssuer = false,
                    ValidateAudience = false,
                    // set clockskew to zero so tokens expire exactly at token expiration time (instead of 5 minutes later)
                    ClockSkew = TimeSpan.Zero
                };
                SecurityToken stoken;
                jwtHandler.ValidateToken(token, tvParameter, out stoken);
                Console.WriteLine(stoken);
                Console.WriteLine("Validate Token Success");
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
        }
    }
}

 

5) 调用APIM接口对Authorization验证

当然,也可以直接在调用APIM的客户端中进行验证。

 

附录一:在APIM的接口配置页中,Test页面点击Send按钮,发送API的请求,通过页面中的Trace部分查看每一部分的耗时,处理结果,或错误详情。

 

 

参考资料

验证 JWT:https://docs.azure.cn/zh-cn/api-management/api-management-access-restriction-policies#validate-jwt

How to validate JWT signed with RS256 Algorithm with validate-jwt policy in Azure API management :https://stackoverflow.com/questions/37050233/how-to-validate-jwt-signed-with-rs256-algorithm-with-validate-jwt-policy-in-azur

 

相关文章
|
4天前
|
SQL 安全 算法
网络安全与信息安全的全面解析:应对漏洞、加密技术及提升安全意识的策略
本文深入探讨了网络安全和信息安全的重要性,详细分析了常见的网络安全漏洞以及其利用方式,介绍了当前流行的加密技术及其应用,并强调了培养良好安全意识的必要性。通过综合运用这些策略,可以有效提升个人和企业的网络安全防护水平。
|
17天前
|
存储 中间件 API
ThinkPHP 集成 jwt 技术 token 验证
本文介绍了在ThinkPHP框架中集成JWT技术进行token验证的流程,包括安装JWT扩展、创建Token服务类、编写中间件进行Token校验、配置路由中间件以及测试Token验证的步骤和代码示例。
ThinkPHP 集成 jwt 技术 token 验证
|
6天前
|
SQL 安全 算法
网络安全与信息安全:构建数字世界的防线在数字化浪潮席卷全球的今天,网络安全与信息安全已成为维系社会秩序、保障个人隐私与企业机密的重要基石。本文旨在深入探讨网络安全漏洞的本质、加密技术的前沿进展以及提升安全意识的有效策略,为读者揭示数字时代下信息保护的核心要义。
本文聚焦网络安全与信息安全领域,详细剖析了网络安全漏洞的形成机理、常见类型及其潜在危害,强调了及时检测与修复的重要性。同时,文章系统介绍了对称加密、非对称加密及哈希算法等主流加密技术的原理、应用场景及优缺点,展现了加密技术在保障数据安全中的核心地位。此外,针对社会普遍存在的安全意识薄弱问题,提出了一系列切实可行的提升措施,如定期安全培训、强化密码管理、警惕钓鱼攻击等,旨在引导公众树立全面的网络安全观,共同构筑数字世界的安全防线。
|
20天前
|
JSON 安全 数据安全/隐私保护
从0到1搭建权限管理系统系列三 .net8 JWT创建Token并使用
【9月更文挑战第22天】在.NET 8中,从零开始搭建权限管理系统并使用JWT(JSON Web Tokens)创建Token是关键步骤。JWT是一种开放标准(RFC 7519),用于安全传输信息,由头部、载荷和签名三部分组成。首先需安装`Microsoft.AspNetCore.Authentication.JwtBearer`包,并在`Program.cs`中配置JWT服务。接着,创建一个静态方法`GenerateToken`生成包含用户名和角色的Token。最后,在控制器中使用`[Authorize]`属性验证和解析Token,从而实现身份验证和授权功能。
|
25天前
|
存储 安全 网络安全
网络安全与信息安全:构建安全防线的多维策略在当今数字化时代,网络安全已成为维护个人隐私、企业机密和国家安全的关键要素。本文旨在探讨网络安全漏洞的本质、加密技术的重要性以及提升公众安全意识的必要性,以期为构建更加坚固的网络环境提供参考。
本文聚焦于网络安全领域的核心议题,包括网络安全漏洞的现状与应对、加密技术的发展与应用,以及安全意识的培养与实践。通过分析真实案例,揭示网络安全威胁的多样性与复杂性,强调综合防护策略的重要性。不同于传统摘要,本文将直接深入核心内容,以简洁明了的方式概述各章节要点,旨在迅速吸引读者兴趣,引导其进一步探索全文。
|
14天前
|
算法 安全 网络安全
概念区分:对称加密、非对称加密、公钥、私钥、签名、证书
概念区分:对称加密、非对称加密、公钥、私钥、签名、证书
26 0
|
2月前
|
安全 API 网络安全
【Azure API 管理】APIM不能连接到 App Service (APIM cannot connect to APP service)
【Azure API 管理】APIM不能连接到 App Service (APIM cannot connect to APP service)
|
2月前
|
API
【API Management】使用 APIM Inbound Policy 来修改Content‐Type Header的值
【API Management】使用 APIM Inbound Policy 来修改Content‐Type Header的值
【API Management】使用 APIM Inbound Policy 来修改Content‐Type Header的值
|
2月前
|
安全 网络安全 数据安全/隐私保护
网络安全漏洞与加密技术:保护信息安全的关键策略
【8月更文挑战第31天】在数字化时代,网络安全和信息安全已成为全球关注的焦点。本文将深入探讨网络安全漏洞、加密技术以及提升安全意识的重要性。通过分析常见网络攻击手段,介绍加密技术的原理和应用,并提供实用的安全建议,旨在帮助读者构建更加安全的网络环境。
|
2月前
|
SQL 安全 网络安全
网络安全漏洞与防御策略:从加密技术到安全意识
【8月更文挑战第31天】在数字化时代,网络安全成为维护信息完整性、保密性和可用性的关键。本文将探讨网络安全的薄弱环节,包括常见的网络漏洞、攻击手法,并深入分析加密技术如何作为防御手段保护数据安全。同时,强调培养个人和组织的安全意识对于防范网络威胁的重要性。通过案例分析和代码示例,本文旨在为读者提供实用的网络安全知识,帮助他们构建更安全的网络环境。