2016-08-02 112 views
2

我想了解如何使用.NET Framework驗證JWT令牌的簽名。我正在使用在https://jwt.io/找到的令牌。C#如何驗證JWT令牌上的簽名?

如果我明白這應該如何工作,我可以使用HMACSHA256哈希算法與前兩個令牌和一個祕密值來獲取令牌的最後部分。如果匹配,那麼簽名是有效的。

https://jwt.io/頁顯示計算散列以下述方式的例子:

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

不幸的是在.NET Framework的HMACSHA256對象沒有這樣的方法。您必須傳入一個字節[]或流。也不存在任何祕密。但是,有一個構造函數將字節[]作爲鍵。爲了解決這個問題,我一直在將「secret」這個詞轉換成一個byte []來實例化HMACSHA256對象。

然後,我將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; 
    } 
} 
相關問題