/// <summary>
        /// Verifies that the signature header matches that of the actual body.
        /// </summary>
        protected virtual async Task <bool> VerifySignature(string id, HttpRequestMessage request)
        {
            string secretKey = await GetReceiverConfig(request, Name, id, SecretMinLength, SecretMaxLength);

            // Get the expected hash from the signature header
            string signatureHeaderValue = GetRequestHeader(request, SignatureHeaderName);

            byte[] expectedHash;
            try
            {
                expectedHash = EncodingUtilities.FromHex(signatureHeaderValue);
            }
            catch (Exception ex)
            {
                string msg = string.Format(CultureInfo.CurrentCulture, InstagramReceiverResources.Receiver_BadHeaderEncoding, SignatureHeaderName);
                request.GetConfiguration().DependencyResolver.GetLogger().Error(msg, ex);
                HttpResponseMessage invalidEncoding = request.CreateErrorResponse(HttpStatusCode.BadRequest, msg);
                throw new HttpResponseException(invalidEncoding);
            }

            // Get the actual hash of the request body concatenated with the request URI
            byte[] actualHash;
            byte[] secret = Encoding.UTF8.GetBytes(secretKey);
            using (var hasher = new HMACSHA1(secret))
            {
                byte[] data = await request.Content.ReadAsByteArrayAsync();

                actualHash = hasher.ComputeHash(data);
            }

            // Now verify that the provided hash matches the expected hash.
            return(WebHookReceiver.SecretEqual(expectedHash, actualHash));
        }
        /// <summary>
        /// Verifies that the signature header matches that of the actual body.
        /// </summary>
        protected virtual async Task VerifySignature(string id, HttpRequestMessage request)
        {
            var secretKey = await GetReceiverConfig(request, Name, id, SecretMinLength, SecretMaxLength);

            // Get the expected hash from the signature header
            var header = GetRequestHeader(request, SignatureHeaderName);
            var values = header.SplitAndTrim('=');

            if (values.Length != 2 || !string.Equals(values[0], SignatureHeaderKey, StringComparison.OrdinalIgnoreCase))
            {
                var message = string.Format(CultureInfo.CurrentCulture, GitHubReceiverResources.Receiver_BadHeaderValue, SignatureHeaderName, SignatureHeaderKey, "<value>");
                request.GetConfiguration().DependencyResolver.GetLogger().Error(message);
                var invalidHeader = request.CreateErrorResponse(HttpStatusCode.BadRequest, message);
                throw new HttpResponseException(invalidHeader);
            }

            byte[] expectedHash;
            try
            {
                expectedHash = EncodingUtilities.FromHex(values[1]);
            }
            catch (Exception ex)
            {
                var message = string.Format(CultureInfo.CurrentCulture, GitHubReceiverResources.Receiver_BadHeaderEncoding, SignatureHeaderName);
                request.GetConfiguration().DependencyResolver.GetLogger().Error(message, ex);
                var invalidEncoding = request.CreateErrorResponse(HttpStatusCode.BadRequest, message);
                throw new HttpResponseException(invalidEncoding);
            }

            // Get the actual hash of the request body
            byte[] actualHash;
            var    secret = Encoding.UTF8.GetBytes(secretKey);

            using (var hasher = new HMACSHA1(secret))
            {
                var data = await request.Content.ReadAsByteArrayAsync();

                actualHash = hasher.ComputeHash(data);
            }

            // Now verify that the provided hash matches the expected hash.
            if (!WebHookReceiver.SecretEqual(expectedHash, actualHash))
            {
                var badSignature = CreateBadSignatureResponse(request, SignatureHeaderName);
                throw new HttpResponseException(badSignature);
            }
        }
Beispiel #3
0
        /// <summary>
        /// Verifies that the signature header matches that of the actual body.
        /// </summary>
        protected virtual async Task <bool> VerifySignature(string id, HttpRequestMessage request)
        {
            // Get the expected hash from the signature and app key headers
            string signatureHeaderValue = GetRequestHeader(request, SignatureHeaderName);
            string keyHeaderValue       = GetRequestHeader(request, KeyHeaderName);

            // Lookup which secret to use based on key header value
            IDictionary <string, string> lookupTable = await GetSecretLookupTable(id, request);

            string secretKey;

            if (!lookupTable.TryGetValue(keyHeaderValue, out secretKey))
            {
                string msg = string.Format(CultureInfo.CurrentCulture, PusherReceiverResources.Receiver_SecretNotFound, KeyHeaderName, keyHeaderValue);
                request.GetConfiguration().DependencyResolver.GetLogger().Error(msg);
                HttpResponseMessage invalidEncoding = request.CreateErrorResponse(HttpStatusCode.BadRequest, msg);
                throw new HttpResponseException(invalidEncoding);
            }

            byte[] expectedHash;
            try
            {
                expectedHash = EncodingUtilities.FromHex(signatureHeaderValue);
            }
            catch (Exception ex)
            {
                string msg = string.Format(CultureInfo.CurrentCulture, PusherReceiverResources.Receiver_BadHeaderEncoding, SignatureHeaderName);
                request.GetConfiguration().DependencyResolver.GetLogger().Error(msg, ex);
                HttpResponseMessage invalidEncoding = request.CreateErrorResponse(HttpStatusCode.BadRequest, msg);
                throw new HttpResponseException(invalidEncoding);
            }

            // Get the actual hash of the request body
            byte[] actualHash;
            byte[] secret = Encoding.UTF8.GetBytes(secretKey);
            using (var hasher = new HMACSHA256(secret))
            {
                byte[] data = await request.Content.ReadAsByteArrayAsync();

                actualHash = hasher.ComputeHash(data);
            }

            // Now verify that the provided hash matches the expected hash.
            return(WebHookReceiver.SecretEqual(expectedHash, actualHash));
        }
Beispiel #4
0
        /// <summary>
        /// Verifies that the signature header matches that of the actual body.
        /// </summary>
        protected virtual async Task <bool> VerifySignature(HttpRequestMessage request, string id)
        {
            // 1. Ensure configuration for this receiver and id exists.
            var secretKey = await GetReceiverConfig(request, Name, id, SecretMinLength, SecretMaxLength);

            // 2. Get the timestamp and expected signatures from the signature header. Header is a comma-separated set
            // of key=value pairs.
            var    signatureHeaderValue = GetRequestHeader(request, SignatureHeaderName);
            var    pairs              = signatureHeaderValue.SplitAndTrim(',');
            string timestamp          = null;
            var    expectedSignatures = new List <string>();

            foreach (var pair in pairs)
            {
                var keyValuePair = pair.SplitAndTrim('=');
                if (keyValuePair.Length != 2)
                {
                    var message = string.Format(
                        CultureInfo.CurrentCulture,
                        StripeReceiverResources.Receiver_InvalidHeaderFormat,
                        SignatureHeaderName);
                    request.GetConfiguration().DependencyResolver.GetLogger().Error(message);

                    var invalidHeader = request.CreateErrorResponse(HttpStatusCode.BadRequest, message);
                    throw new HttpResponseException(invalidHeader);
                }

                if (string.Equals(keyValuePair[0], SignatureKey, StringComparison.OrdinalIgnoreCase))
                {
                    expectedSignatures.Add(keyValuePair[1]);
                }
                else if (string.IsNullOrEmpty(timestamp) &&
                         string.Equals(keyValuePair[0], TimestampKey, StringComparison.OrdinalIgnoreCase))
                {
                    timestamp = keyValuePair[1];
                }
            }

            if (string.IsNullOrEmpty(timestamp) || expectedSignatures.Count == 0)
            {
                var message = string.Format(
                    CultureInfo.CurrentCulture,
                    StripeReceiverResources.Receiver_HeaderMissingValue,
                    SignatureHeaderName,
                    TimestampKey,
                    SignatureKey);
                request.GetConfiguration().DependencyResolver.GetLogger().Error(message);

                var invalidHeader = request.CreateErrorResponse(HttpStatusCode.BadRequest, message);
                throw new HttpResponseException(invalidHeader);
            }

            // 3. Get the actual hash of the timestamp and request body.
            var secret = Encoding.UTF8.GetBytes(secretKey);
            var prefix = Encoding.UTF8.GetBytes(timestamp + ".");

            byte[] actualHash;
            using (var hasher = new HMACSHA256(secret))
            {
                hasher.TransformBlock(
                    inputBuffer: prefix,
                    inputOffset: 0,
                    inputCount: prefix.Length,
                    outputBuffer: null,
                    outputOffset: 0);

                var data = await request.Content.ReadAsByteArrayAsync();

                actualHash = hasher.ComputeHash(data);
            }

            // 4. Verify that the actual hash matches one of the expected hashes.
            foreach (var expectedSignature in expectedSignatures)
            {
                // While this looks repetitious compared to hex-encoding actualHash (once), a single v1 entry in the
                // header is the normal case. Expect multiple signatures only when rolling secret keys.
                byte[] expectedHash;
                try
                {
                    expectedHash = EncodingUtilities.FromHex(expectedSignature);
                }
                catch (Exception ex)
                {
                    var message = string.Format(
                        CultureInfo.CurrentCulture,
                        StripeReceiverResources.Receiver_BadSignatureEncoding,
                        SignatureHeaderName,
                        SignatureKey);
                    request.GetConfiguration().DependencyResolver.GetLogger().Error(message, ex);

                    var invalidEncoding = request.CreateErrorResponse(HttpStatusCode.BadRequest, message);
                    throw new HttpResponseException(invalidEncoding);
                }

                if (SecretEqual(expectedHash, actualHash))
                {
                    return(true);
                }
            }

            return(false);
        }