System.IdentityModel.Tokens.Jwtを使用したJWTトークンのデコードと検証


101

私はJWTライブラリを使用してJson Webトークンをデコードしており、Microsoftの公式JWT実装であるSystem.IdentityModel.Tokens.Jwtに切り替えたいと考えています。

ドキュメントは非常にまばらなので、私がJWTライブラリーで行っていることを達成する方法を理解するのに苦労しています。JWTライブラリには、base64でエンコードされたJWTをJSONに変換してから逆シリアル化できるDecodeメソッドがあります。System.IdentityModel.Tokens.Jwtを使用して同様のことをしたいのですが、かなり掘り下げた後、その方法を理解できません。

価値があるのは、GoogleのIDフレームワークで使用するために、CookieからJWTトークンを読み取ることです。

任意の助けいただければ幸いです。



-ここでは、証明書をGoogleやトークンを検証するためにフェッチする方法についての実践的な答えだstackoverflow.com/questions/29757140/...
rothschild86を

回答:


147

パッケージ内には、JwtSecurityTokenHandlerから派生するというクラスがありますSystem.IdentityModel.Tokens.SecurityTokenHandler。WIFでは、これはセキュリティトークンを逆シリアル化およびシリアル化するためのコアクラスです。

このクラスには、ReadToken(String)base64でエンコードされたJWT文字列を受け取りSecurityToken、JWTを表すを返すメソッドがあります。

SecurityTokenHandlerは、ValidateToken(SecurityToken)を取得してSecurityTokenを作成するメソッドもありますReadOnlyCollection<ClaimsIdentity>。通常、JWTの場合、これにはClaimsIdentity、元のJWTのプロパティを表す一連のクレームを持つ単一のオブジェクトが含まれます。

JwtSecurityTokenHandlerには追加のオーバーロードがいくつか定義されValidateTokenていClaimsPrincipal ValidateToken(JwtSecurityToken, TokenValidationParameters)ます。特に、オーバーロードがあります。TokenValidationParameters引数には、(のリストとしてトークン署名証明書を指定することができますX509SecurityTokens)。また、JWTをとしてではstringなくオーバーロードしますSecurityToken

これを行うコードはかなり複雑ですが、次の場所にあるTokenValidationHandler「ADAL-Native App to REST service-Authentication with ACS via Browser Dialog」と呼ばれる開発者サンプルのGlobal.asax.cxコード(クラス)にあります。

http://code.msdn.microsoft.com/AAL-Native-App-to-REST-de57f2cc

または、JwtSecurityTokenクラスには、ベースSecurityTokenクラスにない追加のメソッドがあります。たとえばClaimsClaimsIdentityコレクションを経由せずに含まれるクレームを取得するプロパティなどです。また、トークンの未加工のJSONを取得できるオブジェクトPayloadを返すプロパティもありJwtPayloadます。最も適切なアプローチは、シナリオによって異なります。

SecurityTokenHandlerクラスの一般的な(つまり、JWT固有ではない)ドキュメントは、

http://msdn.microsoft.com/en-us/library/system.identitymodel.tokens.securitytokenhandler.aspx

アプリケーションによっては、他のハンドラーとまったく同じように、JWTハンドラーをWIFパイプラインに構成できます。

さまざまなタイプのアプリケーションで使用されている3つのサンプルがあります。

http://code.msdn.microsoft.com/site/search?f%5B0%5D.Type=SearchText&f%5B0%5D.Value=aal&f%5B1%5D.Type=User&f%5B1%5D.Value=Azure% 20AD%20Developer%20Experience%20Team&f%5B1%5D.Text = Azure%20AD%20Developer%20Experience%20Team

おそらく、あなたのニーズに合うか、少なくともそれらに適応できるでしょう。


3
本当にありがとうございます。では、ClaimsIdentityを取得したら、それを公開キーと照合するにはどうすればよいですか?具体的には、公開鍵(gstatic.com/authtoolkit/cert/gitkit_cert.pem)に対してGoogle IDツールキットJWTを検証しようとしています
w.brian

4
私の答えを更新しました-これの完全なソースを収めることはできませんでしたが、適切な開発者サンプルの方向を示しました。それが役に立てば幸い。
マイクグッドウィン

4
@ w.brian-私も同じことをしようとしています。私はデコードできるトークンと検証したい公開鍵を持っていますが、これらのサンプルを見ても、どうやってこれを行うのかを理解するのに苦労しています。実際にあなたを助けたコードへのポインタはありますか?ありがとう。
Barguast

25

JWTトークンのデコードと検証にいくつかのライブラリを使用する理由を単に考えているだけです。

エンコードされたJWTトークンは、次の疑似コードを使用して作成できます

var headers = base64URLencode(myHeaders);
var claims = base64URLencode(myClaims);
var payload = header + "." + claims;

var signature = base64URLencode(HMACSHA256(payload, secret));

var encodedJWT = payload + "." + signature;

特定のライブラリがなくても非常に簡単です。次のコードを使用:

using System;
using System.Text;
using System.Security.Cryptography;

public class Program
{   
    // More info: https://stormpath.com/blog/jwt-the-right-way/
    public static void Main()
    {           
        var header = "{\"typ\":\"JWT\",\"alg\":\"HS256\"}";
        var claims = "{\"sub\":\"1047986\",\"email\":\"jon.doe@eexample.com\",\"given_name\":\"John\",\"family_name\":\"Doe\",\"primarysid\":\"b521a2af99bfdc65e04010ac1d046ff5\",\"iss\":\"http://example.com\",\"aud\":\"myapp\",\"exp\":1460555281,\"nbf\":1457963281}";

        var b64header = Convert.ToBase64String(Encoding.UTF8.GetBytes(header))
            .Replace('+', '-')
            .Replace('/', '_')
            .Replace("=", "");
        var b64claims = Convert.ToBase64String(Encoding.UTF8.GetBytes(claims))
            .Replace('+', '-')
            .Replace('/', '_')
            .Replace("=", "");

        var payload = b64header + "." + b64claims;
        Console.WriteLine("JWT without sig:    " + payload);

        byte[] key = Convert.FromBase64String("mPorwQB8kMDNQeeYO35KOrMMFn6rFVmbIohBphJPnp4=");
        byte[] message = Encoding.UTF8.GetBytes(payload);

        string sig = Convert.ToBase64String(HashHMAC(key, message))
            .Replace('+', '-')
            .Replace('/', '_')
            .Replace("=", "");

        Console.WriteLine("JWT with signature: " + payload + "." + sig);        
    }

    private static byte[] HashHMAC(byte[] key, byte[] message)
    {
        var hash = new HMACSHA256(key);
        return hash.ComputeHash(message);
    }
}

トークンのデコードは、上記のコードの逆バージョンです。署名を確認するには、署名部分と計算された署名を比較する必要があります。

更新:base64 url​​safeエンコード/デコードを実行する方法にどのように苦労しているのかについては、別のSO質問、およびwikiとRFC を参照してください


2
素敵な答え。:あなたがここにHMACベースの署名を示しているので、それはHMACの検証を実装したライブラリでは、いくつかの重大な脆弱性を認識することが意味をなすかもしれないが、ここでAuth0サイト上で説明するようauth0.com/blog/2015/03/31/...
Sudhanshuミシュラ

2
これが最良の答えだと思います。OPは...明確な例とされ、この記事のアドレス、具体的JWTの情報を要求
webworm

13
この答えは説明し、どのように証明する エン質問はについて非常に明確であるコードJWT コーディング。これはいい答えかもしれませんが、まったく別の質問に対する答えです。
Deltics 2017年

2
@Delticsトークンをデコードするためにエンコードアルゴリズムを書き換えるのにコンピュータサイエンスの学位も必要ではないと思います。あなたはどのようにエンコードを理解していれば-あなたはどのようにデコードするために理解
Regfor

31
「答え」のアイデアは、質問に対処することであり、誰かが何らかの逆意のパズルを解くことを期待してパズルを提起することではありません。ベッドサイドでは、暗号化の方法を知っていても、必ずしも復号化の方法を知っているとは限りません。これは、単に自分の鍵を使用して署名するのではなく、サードパーティのトークンを処理し、署名を検証するために鍵を取得する必要があるためです。いずれにせよ、ない答えではない、実際に定義して答えるがありませんより良いものに比較したときに」答えない私が応答した先の観察です。
Deltics 2017年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.