Я пытаюсь проверить свой секретный ключ приложения-функции, который передается из Github Webhook, используя .NET CORE 3.1.
В моем веб-перехватчике Github я вставил ключ по умолчанию из функции Azure в поле «Секрет». Теперь я пытаюсь проверить это в своем коде. По какой-то причине мой зашифрованный секретный ключ отличается от того, что есть в вебхуке.
ПРИМЕЧАНИЕ. Секрет от Github Webhook зашифрован алгоритмом SHA1.
Код:
public static async Task<IActionResult> Run(HttpRequest req, ILogger log)
{
var secretKey = "my_key";
StringValues outHeader;
if (req.Headers.TryGetValue("x-hub-signature", out outHeader))
{
log.LogWarning("========= = ");
log.LogWarning(outHeader);
log.LogWarning(GetHash(secretKey));
log.LogWarning("========= = ");
}
string responseMessage = "Everything went well!";
return new OkObjectResult(responseMessage);
}
public static string GetHash(string input)
{
return "sha1 = " + string.Join("",
(new SHA1Managed()
.ComputeHash(Encoding.UTF8.GetBytes(input)))
.Select(x => x.ToString("x2"))
.ToArray());
}
Выход:
2020-12-13T16:46:47.592 [Warning] ==========
2020-12-13T16:46:47.592 [Warning] sha1=f859bebbf5ec452a7ecd42efc69e0d86a4f25b16
2020-12-13T16:46:47.593 [Warning] sha1=fa1167715f137edff21d55d00adf63afb318b2a6
2020-12-13T16:46:47.593 [Warning] ==========
Официальная документация относится только к решению Node.js.
Как правильно проверить секрет Github Webhook Secret в .NET CORE 3.1? Спасибо за любую помощь.
Здесь вы не передаете полезную нагрузку своему методу GetHash, а метод GetHash не принимает секрет. Это моя реализация:
using Azure.Identity;
using Azure.Security.KeyVault.Secrets;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives;
using System;
using System.IO;
using System.Net;
using System.Net.Mail;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace GitHubWebhooks
{
public static class Security
{
private const string ShaPrefix = "sha256 = ";
private const string keyVaultUrl = "<keyvault URL or replace with some other security>";
private const string gitHubWebhookSecretSecretName = "GitHubWebHookSecret";
private static KeyVaultSecret gitHubWebhookSecret;
private static async Task FetchSecrets(CancellationToken cancellationToken)
{
var client = new SecretClient(new Uri(keyVaultUrl), new DefaultAzureCredential());
var gitHubWebHookSecretSecretResponse = await client.GetSecretAsync(gitHubWebhookSecretSecretName, cancellationToken: cancellationToken);
gitHubWebhookSecret = gitHubWebHookSecretSecretResponse.Value;
}
// https://davidpine.net/blog/github-profanity-filter/
// https://docs.github.com/en/developers/webhooks-and-events/securing-your-webhooks
public static async Task<bool> IsGithubPushAllowedAsync(HttpRequest request, CancellationToken cancellationToken)
{
if (gitHubWebhookSecret == null)
{
await FetchSecrets(cancellationToken);
}
request.Headers.TryGetValue("X-GitHub-Event", out StringValues eventName);
request.Headers.TryGetValue("X-Hub-Signature-256", out StringValues signatureWithPrefix);
request.Headers.TryGetValue("X-GitHub-Delivery", out StringValues delivery);
if (string.IsNullOrWhiteSpace(eventName))
{
return false;
}
if (string.IsNullOrWhiteSpace(signatureWithPrefix))
{
return false;
}
if (string.IsNullOrWhiteSpace(delivery))
{
return false;
}
string payload;
// https://justsimplycode.com/2020/08/02/reading-httpcontext-request-body-content-returning-empty-after-upgrading-to-net-core-3-from-2-0/
// Request buffering needs to be enabled in app startup configuration.
// The snippet is:
// app.Use((context, next) =>
// {
// context.Request.EnableBuffering();
// return next();
// });
request.Body.Position = 0;
// We don't close the stream as we're not the one who's opened it.
using (var reader = new StreamReader(request.Body, leaveOpen: true))
{
payload = await reader.ReadToEndAsync();
}
if (string.IsNullOrWhiteSpace(payload))
{
return false;
}
string signatureWithPrefixString = signatureWithPrefix;
if (signatureWithPrefixString.StartsWith(ShaPrefix, StringComparison.OrdinalIgnoreCase))
{
var signature = signatureWithPrefixString.Substring(ShaPrefix.Length);
var secret = Encoding.ASCII.GetBytes(gitHubWebhookSecret.Value);
var payloadBytes = Encoding.UTF8.GetBytes(payload);
using (var sha = new HMACSHA256(secret))
{
var hash = sha.ComputeHash(payloadBytes);
var hashString = ToHexString(hash);
if (hashString.Equals(signature))
{
return true;
}
}
}
return false;
}
public static string ToHexString(byte[] bytes)
{
var builder = new StringBuilder(bytes.Length * 2);
foreach (byte b in bytes)
{
builder.AppendFormat("{0:x2}", b);
}
return builder.ToString();
}
}
}