• Identity Server4 基础应用(四)Hybrid Flow与PKCE


    前言

    前文介绍了Authorization Code flow的基本内容,可以看出其拥有不错的安全机制。但是仍然存在局限,如果客户端是运行在服务器上的Web应用程序(这类客户端称为机密客户端)当然是个不错授权模式,因为很多涉及安全隐患的步骤(如AccessToken)都是通过后端通道由web服务器和授权服务器直接通信的,而不需要经过用户的浏览器或者其他的地方。虽然如此,但是Authorization Code仍然是通过前端通道传递的,如果code被泄露,就仍然存在安全隐患,典型的有Cut and pasted code attack,就是一种盗用code的攻击来获取用户的权限。因此,官方更加建议使用“Hybrid Flow”或“PKCE”从而增加安全性,但是官方更加推荐使用PKCE。

    Hybrid Flow

    先介绍一下ID_Token具体是什么,ID_Token就像我们的身份证或者户口本,客户端程序可以通过ID_Token获取用户的ClaimsID_Token由三个部分(头Header,体Body和签名Signature)组成并且是通过JWT形式呈现。ID_Token中包含的主要内容有issIssuing authority)、subA unique identifier for the end-user issued by the issuer)、audexpiatauth_time等。

    Hybrid Flow在流程上大致是和Authorization Code flow一样的,唯一的区别是在完成用户的身份认证之后,通过authorization endpoint返回的数据不同。而这一步返回的数据是根据我们发送请求时的response_type参数决定的,这使得流程更加灵活。

    Hybrid Flow根据response_type的不同,authorization endpoint返回可以分为三种情况。

    1. response_type = code + id_token ,即包含Authorization Codeidentity Code
    2. response_type = code + token ,即包含Authorization CodeAccess Code
    3. response_type = code + id_token + token,即包含Authorization Codeidentity CodeAccess Token

    可以看到,code都是一定会返回的。如果ID_Tokenauthorization endpointtoken endpoint都被返回了,那么

    • iss和sub的值必须是相同的
    • 所有关于身份认证的Claims在两者中应该都包含
    • 但是authorization endpoint返回的Claim数量应该会少一点,这也是出于对隐私的考虑

    如果Access Tokenauthorization endpointtoken endpoint都被返回了,那么

    • 那么两次值可能相同也可能不同
    • 这都是取决于这两个终结点的安全特性

    那么到底为什么要使用hybrid flow呢?让我们的应用程序在前端通道和后端通道都可以接收到分开的token接下来进行一些简单的实践,有了前面AuthorizationCode模式代码的经验,编写Hybrid Flow也是很简单的。

    授权服务器上新增HybridClient

    在之前代码的基础上,新增一个授权方式是Hybridclient,这样就ok了。

    创建一个Hybrid流程的MVC客户端

    创建一个新的ASP.NET Core MVC程序,取名为“MVC_Hybrid”,使用Nuget添加IdentityModelOpenIdConnect的引用。

    Startup.cs中进行配置,代码和Authorization Code Flow的基本一致,只是我们在配置ResponseType时需要使用Hybrid定义的三种情况之一,具体代码如下。

    随后在Controller中,和前面介绍Authorization Code时一样,我们通过扩展方法在授权过程中获取的几个token,并显示到界面上

     1 public async Task<IActionResult> Index()
     2         {
     3             //我们利用拓展方法获取存下来的Access Token
     4             var accessToken = await HttpContext.GetTokenAsync(OpenIdConnectParameterNames.AccessToken);
     5             ViewBag.idToken = await HttpContext.GetTokenAsync(OpenIdConnectParameterNames.IdToken);
     6             var client = new HttpClient();
     7             //携带上AccessToken
     8             client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
     9             //去请求受保护的api1上的资源
    10             var response = await client.GetAsync("http://localhost:5001/identity");
    11             if (!response.IsSuccessStatusCode)
    12             {
    13                 ViewBag.Json = response.ReasonPhrase;
    14             }
    15             var content = await response.Content.ReadAsStringAsync();
    16             ViewBag.Json = JArray.Parse(content).ToString();
    17             return View();
    18         }
    Controller中Index
    1 @{
    2     ViewBag.Title = "Json";
    3     Layout = "_Layout";
    4 }
    5 <p>@ViewBag.idToken</p>
    6 <pre>@ViewBag.Json</pre>

    以上,准备工作就已经完成了。接下来运行授权服务器和mvc客户端,运行成功后使用内置的用户登录,完成授权后进入获取到数据。

    在整个过程中,我们使用Fiddler抓取请求,可以看到在Authorization Endpoint同时返回了codeid_token

    使用https://jwt.io/解析Authorization EndPoint返回的Id_TokenToken EndPoint返回的id_Token,可以看到其中包含的用户信息都是一样的。

    关于Hybrid Flow的其他两种模式也类似,我们只需要在客户端的修改请求时的ResponseType即可,就不再赘述了。

    在使用Hybrid时我们看到授权终结点返回的Id Token中包含at_hashAccess Token的哈希值)和c_hashCode的哈希值),规范中定义了以下的一些检验规则。

    1. 两个id_token中的 iss 和 sub 必须相同。
    2. 如果任何一个 id token 中包含关于终端用户的声明,两个令牌中提供的值必须相同。
    3. 关于验证事件的声明必须都提供。
    4. at_hash 和 c_hash 声明可能会从 token 端点返回的令牌中忽略,即使从 authorize 端点返回的令牌中已经声明。

    Proof Key for Code Exchange

    在授权过程中,Authorization Code通过前端通道传递有被泄露的风险,在Hybrid FlowId_Token也在前端通道传递的同时也将用户数据暴露了出来。因此这里介绍的Proof Key for Code Exchange(PKCE) 就是用来降低威胁的一种方法。概括下PKCE参与在授权验证中的主要流程。

    1. 客户端在请求code前随机生成一段字符串,称为code_verifier
    2. code_verifier通过加密算法生成加密后的字符串,称为code_challenge
    3. 当客户端在向授权服务器的授权终结点请求code的同时发送code_challenge给授权服务器,同时为了告诉服务器我使用的是什么加密算法,将算法标识放在
    4. code_challenge_method中;
    5. 当客户端使用codeToken终结点请求AccessToken的同时会发送code_verifier
    6. 授权服务器使用相同的加密算法将code_verifier变换后与之前收到的code_challenge比对,比对成功才会发放Access Token

    再画一个简图直观的看一下上面的流程。

     其实在第二篇文章中其实我们已经看到了这个方法的影子,在Fiddler查看授权请求时我们看到了code_challengcode_challenge_methodcode_verifier,这是因为我们在配置OpenIdConnect时对PKCE的支持是默认开启的,只不过当时我们没有在授权服务器端打开验证。

    那么在授权服务器端我们如何开启使用PKCE验证呢,也很简单,在对client进行配置时,只需添加一句配置。

    1 AllowedGrantTypes = GrantTypes.Code,
    2 RequirePkce = true,  //开启PCKE

    根据官方的说法,还是更加推荐使用PKCE。因为涉及到的加密过程都需要在客户端中实现,相比Hybrid模式实现PKCE的客户端就十分简洁,并且也在前端通道中增加其他的响应元素,最主要的还是因为在实现起来,PKCE更加简单,在ASP.NET Core3开始后已经增加了对PKCE的默认支持,只需简单的一句设置(RequirePkce = true)就能搞定了。

    参考资料:

    https://identityserver4.readthedocs.io/en/latest/topics/grant_types.html 

    https://medium.com/identity-beyond-borders/openid-connect-hybrid-flow-1123bc9461fe 

    https://tools.ietf.org/html/rfc7636 

    https://tonyxu.io/zh/posts/2018/oauth2-pkce-flow/ 

  • 相关阅读:
    layui日历控件设置选择日期不能超过当前日期
    layui表格工具条,如何动态控制按钮的展示?
    celery定时任务
    redis的安装(windows+linux)
    redis常用操作
    mac通过virtualbox安装win10
    制作U盘启动盘
    k8s报错: * spec.template.spec.volumes[0].name: Invalid value: "nfs_pvc001": must match the regex [a-z0-9]([-a-z0-9]*[a-z0-9])? (e.g. 'my-name' or '123-abc')
    k8s的容器的端口暴露
    k8s中pod文件的定义格式
  • 原文地址:https://www.cnblogs.com/xhy0826/p/12530951.html
Copyright © 2020-2023  润新知