2016-08-02 13 views
2

.NET Frameworkを使用してJWTトークンの署名を検証する方法を理解しようとしています。私はhttps://jwt.io/にあるトークンを使用しています。C#JWTトークンの署名を確認する方法は?

これがどのように動作するのか分かっていれば、最初の2つのトークンと秘密の値を持つHMACSHA256ハッシュアルゴリズムを使用して、トークンの最後の部分を取得できます。一致した場合、署名は有効です。

https://jwt.io/ページの例は、以下のようにハッシュを計算示す:

HMACSHA256(
     base64UrlEncode(header) + "." + 
     base64UrlEncode(payload), secret 
) 

残念ながら、.NET FrameworkのHMACSHA256オブジェクトはそのような方法を持っていません。バイト[]またはストリームを渡す必要があります。秘密の議論もありません。しかし、byte []をキーとして取り込むコンストラクタがあります。これを回避するために、私は「秘密」という単語を、それを使ってHMACSHA256オブジェクトをインスタンス化するbyte []に​​変換しています。

次に、base64でエンコードされたheader.payload文字列をbyte []に​​変換し、HMACSHA256オブジェクトのComputeHashメソッドに渡します。

ここで私は問題に遭遇します。 ComputeHashの出力はバイト配列です。このバイト[]を文字列に変換しようとしても、それは決して署名と一致しません。私はどこが間違っているのか分かりません。トークンの署名部分はハッシュ値かbase64でエンコードされたハッシュ値ですか?ここで

は私のコードです:

string jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ"; 
string[] parts = jwt.Split(".".ToCharArray()); 
string headerDotPayload = string.Format("{0}.{1}", parts[0], parts[1]); 

string signature = parts[2]; 
byte[] secret = System.Text.UTF8Encoding.UTF8.GetBytes("secret"); 
byte[] input = System.Text.UTF8Encoding.UTF8.GetBytes(headerDotPayload); 

var alg = new HMACSHA256(secret); 
byte[] hash = alg.ComputeHash(input); 

//Attempting to verify 
StringBuilder result = new StringBuilder(); 

for (int i = 0; i < hash.Length; i++) 
{ 
    result.Append(hash[i].ToString("x2")); 
} 

string verify1 = result.ToString(); //Does not match signature 

string verify2 = System.Text.UTF8Encoding.UTF8.GetString(hash); //Does not match signature 

byte[] verify3 = System.Text.UTF8Encoding.UTF8.GetBytes(signature); //Does not match value in the hash byte[] 

答えて

0

は、トークンの署名部分ハッシュ値またはbase64では ハッシュ値を符号化されていますか?

これは、Base64 Urlでエンコードされたハッシュ値です。等価性を検証するために、計算されたハッシュ値をエンコードする必要があります。

次の単体テストを確認して、どこが間違っているか確認してください。

[TestClass] 
public class JwtUnitTest { 
    [TestMethod] 
    public void VerifySignature() { 

     string jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ"; 
     string[] parts = jwt.Split(".".ToCharArray()); 
     var header = parts[0]; 
     var payload = parts[1]; 
     var signature = parts[2];//Base64UrlEncoded signature from the token 

     byte[] bytesToSign = getBytes(string.Join(".", header, payload)); 

     byte[] secret = getBytes("secret"); 

     var alg = new HMACSHA256(secret); 
     var hash = alg.ComputeHash(bytesToSign); 

     var computedSignature = Base64UrlEncode(hash); 

     Assert.AreEqual(signature, computedSignature); 
    } 

    private static byte[] getBytes(string value) { 
     return Encoding.UTF8.GetBytes(value); 
    } 

    // from JWT spec 
    private static string Base64UrlEncode(byte[] input) { 
     var output = Convert.ToBase64String(input); 
     output = output.Split('=')[0]; // Remove any trailing '='s 
     output = output.Replace('+', '-'); // 62nd char of encoding 
     output = output.Replace('/', '_'); // 63rd char of encoding 
     return output; 
    } 
} 
関連する問題