2016-08-02 8 views
2

Я пытаюсь понять, как проверить подписи токенов JWT с использованием .NET Framework. Я использую токен, найденный по адресу https://jwt.io/.C# Как проверить подпись на токене JWT?

Если я понимаю, как это должно работать, я могу использовать алгоритм хэширования HMACSHA256 с первыми двумя токенами и секретное значение, чтобы получить последнюю часть токена. Если это соответствует, то подпись действительна.

В примере на странице показывает https://jwt.io/ вычисления хэш следующим образом:

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

К сожалению, объект HMACSHA256 в .NET Framework не имеет такого метода. Вы должны пройти в байт [] или поток. Также нет аргументов в пользу тайны. Существует, однако, конструктор, который берет байт [] в качестве ключа. Чтобы обойти, я преобразовал слово «secret» в байт [], создавая объект HMACSHA256 с этим.

Затем я конвертирую base64 закодированную строку header.payload в байт [] и передаю это методу ComputeHash объекта HMACSHA256.

Здесь я столкнулся с проблемами. Выход из 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 Encoded Enched. Вам нужно будет закодировать вычисленное значение хэша, чтобы проверить равенство.

Просмотрите следующий модульный тест, чтобы узнать, где вы поступили не так с вашей проверкой.

[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; 
    } 
}