Как рассчитать ms-подпись для WebHook? - PullRequest
0 голосов
/ 08 октября 2019

Я разрабатываю менеджер Webhooks в C # с помощью Visual Studio с помощью пакета Nu-Get Microsoft CustomWebHooksReceiver.

Затем я проверяю свой менеджер WebHook с помощью программного обеспечения Postman.

При попытке подключиться кмой пользовательский менеджер WebHooks, я получаю сообщение о неверном значении ms-подписи.

Может кто-нибудь объяснить мне, как рассчитать ожидаемое значение параметра ms-signature? Я новичок в webhooks, и я не понимаю, какое значение я должен отправить с запросом Postman, чтобы мой менеджер WebHooks вызывался и был доступен.

Я считаю, что ms-подпись должна включать значение тела JSONзапрос и некоторая секретная информация, но мне нужно четкое описание расчета.

1 Ответ

0 голосов
/ 11 октября 2019

Вот ответ, который я нашел в Интернете. Ms-подпись - это значение, рассчитываемое вызывающей стороной webhooks для секретного значения, заданного получателем и данными JSON запроса. Обратите внимание, что секретный ключ является секретным значением, используемым отправителем и получателем webhook.

   public void CalculateSignature()
    {
        const string secretKey = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; // Secret signature

        byte[] actualHash;
        var secret = Encoding.UTF8.GetBytes(secretKey);
        using (var hasher = new HMACSHA256(secret))
        {
            string data = "INCLUDE HERE JSON VALUE TO SEND";
            byte[] bytes = Encoding.UTF8.GetBytes(data);
            actualHash = hasher.ComputeHash(bytes);
            string hash = Encoding.UTF8.GetString(actualHash);
            var hexString = BitConverter.ToString(actualHash);
            hexString = hexString.Replace("-", "");

        }
    }

Значение в hexString должно быть включено в качестве значения ms-signature в заголовок вашего запроса.

Контроллер webhooks должен реализовать следующие методы для проверки полученной подписи перед обработкой ответа. Если нет, то вы продолжите получать сообщение об ошибке о том, что запрос недействителен из-за значения ms-подписи:

private async Task VerifySignature(HttpRequestMessage request)
    {
        IEnumerable<string> headers;
        const string signatureHeaderName = "ms-signature";
        const string secretKey = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; // Secret signature

        if (request.Headers.TryGetValues(signatureHeaderName, out headers))
        {
            string headerValue = headers.First().Replace("sha256=", "").Trim();
            byte[] expectedHash;
            try
            {
                expectedHash = FromHex(headerValue);
            }
            catch (Exception)
            {
                var invalidEncoding = request.CreateErrorResponse(HttpStatusCode.BadRequest, $"HexValue '{headerValue}' received is not valid. It must be an hex string value.");
                throw new HttpResponseException(invalidEncoding);
            }

            byte[] actualHash;
            var secret = Encoding.UTF8.GetBytes(secretKey);
            using (var hasher = new HMACSHA256(secret))
            {
                var data = await request.Content.ReadAsByteArrayAsync();
                actualHash = hasher.ComputeHash(data);
            }

            if (!SecretEqual(expectedHash, actualHash))
            {
                var message = $"WebHook signature '{signatureHeaderName}' from header is not valid.";
                var badSignature = request.CreateErrorResponse(HttpStatusCode.BadRequest, message);
                throw new HttpResponseException(badSignature);
            }
        }
    }

    private static bool SecretEqual(byte[] inputA, byte[] inputB)
    {
        if (ReferenceEquals(inputA, inputB))
        {
            return true;
        }

        if (inputA == null || inputB == null || inputA.Length != inputB.Length)
        {
            return false;
        }

        var areSame = true;
        for (var i = 0; i < inputA.Length; i++)
        {
            areSame &= inputA[i] == inputB[i];
        }
        return areSame;
    }

    private static byte[] FromHex(string content)
    {
        if (string.IsNullOrEmpty(content))
        {
            return new byte[0];
        }

        byte[] data;
        try
        {
            data = new byte[content.Length / 2];
            var input = 0;
            for (var output = 0; output < data.Length; output++)
            {
                data[output] = Convert.ToByte(new string(new[] { content[input++], content[input++] }), 16);
            }

            if (input != content.Length)
            {
                data = null;
            }
        }
        catch
        {
            data = null;
        }

        if (data == null)
        {
            throw new InvalidOperationException($"Value: '{content}' is not in hex. Please send an hex string.");
        }
        return data;
    }
...