rsa - 使用 at_hash 验证访问 token

标签 rsa identityserver3 oauth-2.0

我正在尝试根据 at_hash 验证访问 token 。 token 头是这样的

{ “类型”:“智威汤逊”, “alg”:“RS256”, "x5t": "MclQ7Vmu-1e5_rvdSfBShLe82eY", “ child ”:“MclQ7Vmu-1e5_rvdSfBShLe82eY” }

如何从我的访问 token 获取 id token 中 Base64 编码的 at_hash 声明值?有没有在线工具可以帮助我解决这个问题? SHA256 哈希计算器不是一个正确的工具吗?

谢谢

最佳答案

Is SHA256 hash calculator not a correct tool for this?

它不起作用,因为您需要在其中一个步骤中使用二进制数据,并且几乎所有网络工具都期望某种文本作为输入并生成文本作为输出。在线工具不适合于此。我将编写一个工具,以便您可以了解它是如何完成的。

How do I get from my access token to the Base64 encoded at_hash claim value that is in the id token?

这是我第一次 C# 程序迭代 2 :) 所以如果它很丑,那是因为我以前从未使用过它。此后的解释将解释如何计算 at_hash token ,包括为什么我们需要 decode_base64

using System;
using System.Security.Cryptography;

using System.Collections.Generic;
using System.Text;
namespace AtHash
{
    class AtHash
    {
        private const String access_token = "ya29.eQGmYe6H3fP_d65AY0pOMCFikA0f4hzVZGmTPPyv7k_l6HzlEIpFXnXGZjcMhkyyuqSMtN_RTGJ-xg";
        private const String id1 = "eyJhbGciOiJSUzI1NiIsImtpZCI6ImUxMWQ1N2QxZmY0ODA0YjMxYzA1MWI3MWY2ZDVlNWExZmQyOTdjZjgifQ";
        private const String id2 = "eyJpc3MiOiJhY2NvdW50cy5nb29nbGUuY29tIiwic3ViIjoiMTEwMTY5NDg0NDc0Mzg2Mjc2MzM0IiwiYXpwIjoiNDA3NDA4NzE4MTkyLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwiZW1haWwiOiJiaWxsZDE2MDBAZ21haWwuY29tIiwiYXRfaGFzaCI6ImxPdEkwQlJvdTBaNExQdFF1RThjQ3ciLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiYXVkIjoiNDA3NDA4NzE4MTkyLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwiaWF0IjoxNDMyMTQyMjIyLCJleHAiOjE0MzIxNDU4MjJ9";

        private byte[] decode_base64(String str) {
            List<byte> l = new List<Byte>(Encoding.Default.GetBytes(str));
            while (l.Count % 4 != 0 ){
                l.Add(Convert.ToByte('='));
            }
            return Convert.FromBase64String(Encoding.Default.GetString(l.ToArray()));
        }

        public String sha256_at_hash(String access_token) {
            SHA256Managed hashstring = new SHA256Managed();
            byte[] bytes         = Encoding.Default.GetBytes(access_token);
            byte[] hash = hashstring.ComputeHash(bytes);
            Byte[] sixteen_bytes = new Byte[16];
            Array.Copy(hash, sixteen_bytes, 16);
            return Convert.ToBase64String(sixteen_bytes).Trim('=');
        }

        public static void Main (string[] args) {
            AtHash ah = new AtHash();
            byte[] id1_str = ah.decode_base64 (id1);
            byte[] id2_str = ah.decode_base64 (id2);

            Console.WriteLine(Encoding.Default.GetString(id1_str));
            Console.WriteLine(Encoding.Default.GetString(id2_str));

            Console.WriteLine ("\n\tat_hash value == " + ah.sha256_at_hash(access_token));
        }
    }
}

该程序的输出(格式化我的)

{ 
  "alg":"RS256",
  "kid":"e11d57d1ff4804b31c051b71f6d5e5a1fd297cf8"
}
{
   "exp" : 1432145822,
   "iat" : 1432142222,
   "azp" : "407408718192.apps.googleusercontent.com",
   "aud" : "407408718192.apps.googleusercontent.com",
   "email_verified" : true,
   "iss" : "accounts.google.com",
   "at_hash" : "lOtI0BRou0Z4LPtQuE8cCw",
   "sub" : "110169484474386276334",
   "email" : "billd1600@gmail.com"
}

at_hash value == lOtI0BRou0Z4LPtQuE8cCw

这是验证 at_hash 值的方法。如果您想使用我用过的数据,您可以跳过 google 部分,但如果您想在新数据上测试它,您可以在 Google 上获取它...

从 Google O2Auth Playground 获取访问 token

去这里

 https://developers.google.com/oauthplayground/

不要选择任何内容,页面底部附近有一个输入框。输入openid并点击Authorize APIs,单击您要使用的ID并选择allow。选择用授权代码交换 token 。如果成功,您将得到类似于以下内容的内容。

{ 
 "access_token": "ya29.eQGmYe6H3fP_d65AY0pOMCFikA0f4hzVZGmTPPyv7k_l6HzlEIpFXnXGZjcMhkyyuqSMtN_RTGJ-xg", 
 "token_type": "Bearer", "expires_in": 3600, 
 "refresh_token": "1/r5RRN6oRChjLtY5Y_T3lrqOy7n7QZJDQUVm8ZI1xGdoMEudVrK5jSpoR30zcRFq6", 
 "id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImUxMWQ1N2QxZmY0ODA0YjMxYzA1MWI3MWY2ZDVlNWExZmQyOTdjZjgifQ.eyJpc3MiOiJhY2NvdW50cy5nb29nbGUuY29tIiwic3ViIjoiMTEwMTY5NDg0NDc0Mzg2Mjc2MzM0IiwiYXpwIjoiNDA3NDA4NzE4MTkyLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwiZW1haWwiOiJiaWxsZDE2MDBAZ21haWwuY29tIiwiYXRfaGFzaCI6ImxPdEkwQlJvdTBaNExQdFF1RThjQ3ciLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiYXVkIjoiNDA3NDA4NzE4MTkyLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwiaWF0IjoxNDMyMTQyMjIyLCJleHAiOjE0MzIxNDU4MjJ9.jtnP4Ffw2bPjfxRAEvHI8j88YBI4OJrw2BU7AQUCP2AUOKRC5pxwVn3vRomGTKiuMbnHqMyMiVSQZWTjAgjQrmaANxTEA68UMKh3dtu63hh4LHkGJly2hFcIKwbHxMWPDRO9nv8LxAUeCF5ccMgFNXhu-i-CeVtrMOsjCq6j5Qc"
}

id_token 分为三个部分,使用句点 . 分隔。前两部分是 base64 编码的。我忽略了 id_token 的第三部分。我们需要对两者进行 Base64 解码。注意,我使用 Perl 来避免填充 Base64 字符串,即 Perl 为我们处理它。

您已经知道的第一部分为我们提供了需要使用的算法。

perl -MMIME::Base64 -e 'print decode_base64("eyJhbGciOiJSUzI1NiIsImtpZCI6ImUxMWQ1N2QxZmY0ODA0YjMxYzA1MWI3MWY2ZDVlNWExZmQyOTdjZjgifQ")'
{
 "alg":"RS256",
 "kid":"e11d57d1ff4804b31c051b71f6d5e5a1fd297cf8"
}

第二部分给出的是at_hash值。

perl -MMIME::Base64 -e 'print decode_base64("eyJpc3MiOiJhY2NvdW50cy5nb29nbGUuY29tIiwic3ViIjoiMTEwMTY5NDg0NDc0Mzg2Mjc2MzM0IiwiYXpwIjoiNDA3NDA4NzE4MTkyLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwiZW1haWwiOiJiaWxsZDE2MDBAZ21haWwuY29tIiwiYXRfaGFzaCI6ImxPdEkwQlJvdTBaNExQdFF1RThjQ3ciLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiYXVkIjoiNDA3NDA4NzE4MTkyLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwiaWF0IjoxNDMyMTQyMjIyLCJleHAiOjE0MzIxNDU4MjJ9")'

{
"iss":"accounts.google.com",
........
"at_hash":"lOtI0BRou0Z4LPtQuE8cCw",
........
"exp":1432145822
}

现在我们知道了 at_hash 值是什么,我们可以使用 access_token 验证它们是否相同...以下 Perl 程序执行此操作。

#!/usr/bin/env perl
use strict;
use warnings;
use MIME::Base64;
use Digest::SHA qw(sha256);
my $data = "ya29.eQGmYe6H3fP_d65AY0pOMCFikA0f4hzVZGmTPPyv7k_l6HzlEIpFXnXGZjcMhkyyuqSMtN_RTGJ-xg"; 
my $digest = sha256($data);
my $first_16_bytes = substr($digest,0,16);
print encode_base64($first_16_bytes);

该程序可以按如下方式运行

perl sha256.pl 
lOtI0BRou0Z4LPtQuE8cCw==   

请注意,我们得到了 at_hash 但为什么它们不一样......,它们实际上是相同的,只是其中一个缺少填充。添加 = 符号,直到满足以下条件为止。

(strlen($base64_string) % 4 == 0)

就我们而言

strlen("lOtI0BRou0Z4LPtQuE8cCw") == 22 

所以我们在结果中添加了两个 == :)。它们不在 token 中的原因是,编写规范的人不认为如果可以将它们添加到另一端,则通过网络传递不必要的字节不是一个好主意。

关于rsa - 使用 at_hash 验证访问 token ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36152633/

相关文章:

java - RSA 解密 - BadPaddingException : Data must start with zero

c# - 如何在thinktecture IdentityServer中禁用自动登录

python - 身份验证后无法访问共享邮箱 - 用户已通过身份验证但未连接

python - M2Crypto,立即加密和签名?

java - 如何从 RSA 1024 位加密中获得较短的输出(密文)结果?

Python:load_pem_private_key 无法识别生产中的我的私钥

spring - 需要进行身份验证才能获取访问 token - 使用 'password' grant 和 Spring 的 ResourceOwnerPasswordResourceDetails 时

asp.net-mvc-4 - IdentityServer3 与 ServiceStack 和 MVC 客户端

asp.net - Asp Core 2.0 和 Identity Server v3,受众验证失败

python - 如何从备用源创建 Google API OAuth Credentials 对象