【发布时间】:2020-04-16 11:14:37
【问题描述】:
首先,这个问题已经被问到并回答了here,但它是特定于 Ruby/PHP 的,虽然我试图遵循它和 Typeform 本身的指导,但我无法在 C# 中实现 Typeform-Signature Check .
我已经编写了一个扩展方法来验证 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);
}
}
【问题讨论】:
-
嗨,Jason,刚刚发布了一个糟糕的答案,但它的一些代码在我的一个帐户上运行良好......你最终设法解决了这个问题吗?
-
@treendy 谢谢,我明天会试一试,但它看起来非常接近我已经尝试过的,除了你在我使用 UTF8 的地方使用 ASCII。会让你知道的。
-
我终于明白了这一点,但离开了我为之工作的公司,不再能够访问代码。