Во-первых, этот вопрос был задан и дан ответ здесь , но он был указан c для Ruby / PHP, и хотя я пытался следовать ему и руководству самих Typeform, я не могу реализовать проверку Typeform-Signature в C#.
. Я написал метод расширения для проверки подписи Typeform в отношении полезной нагрузки, отправленной через webhook. Если подпись верна, она возвращает строку (json) полезной нагрузки, но если нет, то возвращает ошибку.
public static class HttpRequestExtensions {
private const string SignatureHeader = "Typeform-Signature";
private static readonly Encoding encoding = new UTF8Encoding ();
public static async Task<Result<string>> ValidateAndRetrievePayload (this HttpRequestMessage request, string key) {
var headerValue = request.GetHeaderValue (SignatureHeader);
if (string.IsNullOrWhiteSpace (headerValue)) return Result.Failure<string> ($"'{SignatureHeader}' Header not found or empty.");
var json = await request.Content.ReadAsStringAsync ();
var payload = encoding.GetBytes (json);
using (var hmac256 = new HMACSHA256 (encoding.GetBytes (key))) {
var hashPayload = hmac256.ComputeHash (payload);
var base64String = Convert.ToBase64String (hashPayload);
var hashResult = $"sha256={base64String}";
if (hashResult.Equals (headerValue)) return Result.Success (json);
return Result.Failure<string> ($"'{SignatureHeader}' does not match. Header: `{headerValue}` | Hash: `{hashResult}`");
}
}
}
На основании других вопросов, найденных в SO, я изменил метод для запуска без кодирования ( см. ниже), но все равно с тем же результатом, хэши не совпадают.
public static class HttpRequestExtensions
{
private const string SignatureHeader = "Typeform-Signature";
public static async Task<Result<string>> ValidateAndRetrievePayload(this HttpRequestMessage request, string key)
{
var headerValue = request.GetHeaderValue(SignatureHeader);
if (string.IsNullOrWhiteSpace(headerValue))
return Result.Failure<string>($"'{SignatureHeader}' Header not found or empty.");
var payload = await request.Content.ReadAsByteArrayAsync();
var byteKey = GetBytes(key);
using (var hmac256 = new HMACSHA256(byteKey))
{
var hashPayload = hmac256.ComputeHash(payload);
var base64String = Convert.ToBase64String(hashPayload);
var hashResult = $"sha256={base64String}";
if (hashResult.Equals(headerValue))
return Result.Success(await request.Content.ReadAsStringAsync());
return Result.Failure<string>(
$"'{SignatureHeader}' does not match. Header: `{headerValue}` | Hash: `{hashResult}`");
}
}
private static byte[] GetBytes(string value)
{
var bytes = new byte[value.Length * sizeof(char)];
Buffer.BlockCopy(value.ToCharArray(), 0, bytes, 0, bytes.Length);
return bytes;
}
private static string GetString(byte[] bytes)
{
var chars = new char[bytes.Length / sizeof(char)];
Buffer.BlockCopy(bytes, 0, chars, 0, bytes.Length);
return new string(chars);
}
}