private static async Task <X509Certificate2> GetCertificate(Uri signatureCertChainUrl) { if (signatureCertChainUrl == null) { return(null); } if (certificateCache.Key == null || certificateCache.Key.ToString().ToLowerInvariant() != signatureCertChainUrl.ToString().ToLowerInvariant()) { try { X509Certificate2 certificate = await RequestVerification.GetCertificate(signatureCertChainUrl); if (certificate != null) { certificateCache = new KeyValuePair <Uri, X509Certificate2>(signatureCertChainUrl, certificate); } return(certificate); } catch { return(null); } } else { return(certificateCache.Value); } }
private async Task <bool> ValidateRequest(HttpRequest request, SkillRequest skillRequest) { try { request.Headers.TryGetValue("SignatureCertChainUrl", out var signatureChainUrl); if (string.IsNullOrWhiteSpace(signatureChainUrl)) { return(false); } Uri certUrl; try { certUrl = new Uri(signatureChainUrl); } catch { return(false); } request.Headers.TryGetValue("Signature", out var signature); if (string.IsNullOrWhiteSpace(signature)) { return(false); } var body = ""; request.EnableRewind(); using (var stream = new StreamReader(request.Body)) { stream.BaseStream.Position = 0; body = stream.ReadToEnd(); stream.BaseStream.Position = 0; } if (string.IsNullOrWhiteSpace(body)) { return(false); } bool isTimestampValid = RequestVerification.RequestTimestampWithinTolerance(skillRequest); bool valid = await RequestVerification.Verify(signature, certUrl, body); if (!valid || !isTimestampValid) { return(false); } else { return(true); } } catch { return(false); } }
public void Replay_Attack_Timestamp_Invalidated_By_RequestVerification() { var request = new SkillRequest { Request = new LaunchRequest { Timestamp = DateTime.Now.AddMinutes(3) } }; Assert.False(RequestVerification.RequestTimestampWithinTolerance(request)); }
private static async Task <bool> ValidateRequest(HttpRequest request, ILogger log, SkillRequest skillRequest) { request.Headers.TryGetValue("SignatureCertChainUrl", out var signatureChainUrl); if (string.IsNullOrWhiteSpace(signatureChainUrl)) { log.LogError("Validation failed. Empty SignatureCertChainUrl header"); return(false); } Uri certUrl; try { certUrl = new Uri(signatureChainUrl); } catch { log.LogError($"Validation failed. SignatureChainUrl not valid: {signatureChainUrl}"); return(false); } request.Headers.TryGetValue("Signature", out var signature); if (string.IsNullOrWhiteSpace(signature)) { log.LogError("Validation failed - Empty Signature header"); return(false); } request.Body.Position = 0; var body = await request.ReadAsStringAsync(); request.Body.Position = 0; if (string.IsNullOrWhiteSpace(body)) { log.LogError("Validation failed - the JSON is empty"); return(false); } bool isTimestampValid = RequestVerification.RequestTimestampWithinTolerance(skillRequest); bool valid = await RequestVerification.Verify(signature, certUrl, body, GetCertificate); // bool valid = await RequestVerification.Verify(signature, certUrl, body); if (!valid || !isTimestampValid) { log.LogError("Validation failed - RequestVerification failed"); return(false); } else { return(true); } }
public void New_Request_Timestamp_validated_By_RequestVerification() { var request = new SkillRequest { Request = new LaunchRequest { Timestamp = DateTime.Now.AddMinutes(1) } }; Assert.True(RequestVerification.RequestTimestampWithinTolerance(request)); }
/// <summary> /// Validate if all necessary parts for a valid request are available /// and pass them to the RequestsVerification tool /// </summary> /// <param name="context"></param> /// <returns></returns> public async Task Invoke(HttpContext context) { // EnableBuffering so the body can be read without causing issues to the request pipeline context.Request.EnableBuffering(); // Verify SignatureCertChainUrl is present context.Request.Headers.TryGetValue("SignatureCertChainUrl", out var signatureChainUrl); if (string.IsNullOrWhiteSpace(signatureChainUrl)) { context.Response.StatusCode = StatusCodes.Status400BadRequest; return; } Uri certUrl; try { certUrl = new Uri(signatureChainUrl); } catch { context.Response.StatusCode = StatusCodes.Status400BadRequest; return; } // Verify SignatureCertChainUrl is Signature context.Request.Headers.TryGetValue("Signature", out var signature); if (string.IsNullOrWhiteSpace(signature)) { context.Response.StatusCode = StatusCodes.Status400BadRequest; return; } var body = await new StreamReader(context.Request.Body).ReadToEndAsync(); context.Request.Body.Position = 0; if (string.IsNullOrWhiteSpace(body)) { context.Response.StatusCode = StatusCodes.Status400BadRequest; return; } var valid = await RequestVerification.Verify(signature, certUrl, body); if (!valid) { context.Response.StatusCode = StatusCodes.Status400BadRequest; return; } await _next(context); }
public static async Task <bool> ValidateRequestAsync(this SkillRequest skillRequest, HttpRequest request, ILogger log) { // Verifies that the request is indeed coming from Alexa. request.Headers.TryGetValue("SignatureCertChainUrl", out var signatureChainUrl); if (string.IsNullOrWhiteSpace(signatureChainUrl)) { log.LogError("Validation failed. Empty SignatureCertChainUrl header"); return(false); } Uri certUrl; try { certUrl = new Uri(signatureChainUrl); } catch { log.LogError($"Validation failed. SignatureChainUrl not valid: {signatureChainUrl}"); return(false); } request.Headers.TryGetValue("Signature", out var signature); if (string.IsNullOrWhiteSpace(signature)) { log.LogError("Validation failed - Empty Signature header"); return(false); } request.Body.Position = 0; var body = request.Body.ToString(); request.Body.Position = 0; if (string.IsNullOrWhiteSpace(body)) { log.LogError("Validation failed - the JSON is empty"); return(false); } var isTimestampValid = RequestVerification.RequestTimestampWithinTolerance(skillRequest); var isValid = await RequestVerification.Verify(signature, certUrl, body); if (!isValid || !isTimestampValid) { log.LogError("Validation failed - RequestVerification failed"); return(false); } return(true); }
private async Task <bool> ValidateRequest(HttpRequest request, SkillRequest skillRequest) { try { var header = request.Headers; var signature = header["Signature"]; var certUrl = new Uri(header["SignatureCertChainUrl"]); var body = await request.ReadAsStringAsync(); return (RequestVerification.RequestTimestampWithinTolerance(skillRequest) && await RequestVerification.Verify(signature, certUrl, body)); } catch { m_logger.LogError("Validation exception"); return(false); } }
public static async Task EnsureValidAlexaSignatureAsync(this HttpRequest request) { request.EnableRewind(); // Verify SignatureCertChainUrl is present request.Headers.TryGetValue("SignatureCertChainUrl", out var signatureChainUrl); if (string.IsNullOrWhiteSpace(signatureChainUrl)) { throw new InvalidSignatureException(); } Uri certUrl; try { certUrl = new Uri(signatureChainUrl); } catch { throw new InvalidSignatureException(); } // Verify SignatureCertChainUrl is Signature request.Headers.TryGetValue("Signature", out var signature); if (string.IsNullOrWhiteSpace(signature)) { throw new InvalidSignatureException(); } var body = new StreamReader(request.Body).ReadToEnd(); request.Body.Position = 0; if (string.IsNullOrWhiteSpace(body)) { throw new InvalidSignatureException(); } var valid = await RequestVerification.Verify(signature, certUrl, body); if (!valid) { throw new InvalidSignatureException(); } }
private static async Task <bool> ValidateRequestAsync(HttpRequest request, SkillRequest skillRequest) { request.Headers.TryGetValue("SignatureCertChainUrl", out var signatureChainUrl); if (string.IsNullOrWhiteSpace(signatureChainUrl)) { return(false); } Uri certUrl; try { certUrl = new Uri(signatureChainUrl); } catch { return(false); } request.Headers.TryGetValue("Signature", out var signature); if (string.IsNullOrWhiteSpace(signature)) { return(false); } request.Body.Position = 0; var body = await request.ReadAsStringAsync(); request.Body.Position = 0; if (string.IsNullOrWhiteSpace(body)) { return(false); } bool isTimestampValid = RequestVerification.RequestTimestampWithinTolerance(skillRequest); bool valid = await RequestVerification.Verify(signature, certUrl, body); if (!valid || !isTimestampValid) { return(false); } else { return(true); } }
/// <summary> /// Authorize the SkillRequest is coming from Alexa. /// </summary> /// <param name="skillRequest">Incoming SkillRequest from Alexa.</param> /// <param name="requestBody">Full request body from Alexa.</param> /// <param name="signatureChainUrl">Signature Chain Url. This is the SignatureCertChainUrl header value.</param> /// <param name="signature">Signature. This is the Signature header value.</param> /// <returns>True if this is a valid SkillRequest otherwise false.</returns> public virtual async Task <bool> ValidateSkillRequest(CrunchRequest skillRequest, string requestBody, string signatureChainUrl, string signature) { if (skillRequest == null) { _logger.LogError("Validation failed. No incoming skill request."); return(false); } if (string.IsNullOrWhiteSpace(signatureChainUrl)) { _logger.LogError("Validation failed. Empty SignatureCertChainUrl header."); return(false); } Uri certUrl; try { certUrl = new Uri(signatureChainUrl); } catch { _logger.LogError($"Validation failed. SignatureChainUrl not valid: {signatureChainUrl}."); return(false); } if (string.IsNullOrWhiteSpace(signature)) { _logger.LogError("Validation failed. Empty Signature header."); return(false); } if (!RequestVerification.RequestTimestampWithinTolerance(skillRequest)) { _logger.LogError("Validation failed. Request timestamp outside of tolerance."); return(false); } if (!await RequestVerification.Verify(signature, certUrl, requestBody)) { _logger.LogError("Validation failed. Alexa certificate validation failed."); return(false); } return(true); }
/// <summary> /// Validates the request. /// </summary> /// <param name="signature">The Signature value.</param> /// <param name="signatureCertChainUrl">The SignatureCertChainUrl value.</param> /// <param name="body">The body value.</param> /// <returns></returns> private static async Task <bool> IsRequestValid(string signature, Uri signatureCertChainUrl, string body) { return(await RequestVerification.Verify(signature, signatureCertChainUrl, body)); }
public async Task InvokeAsync(HttpContext context) { string bodyStr; using (var reader = new StreamReader(context.Request.Body)) { bodyStr = reader.ReadToEnd(); } if (environment.IsProduction()) { // Verify SignatureCertChainUrl is present context.Request.Headers.TryGetValue("SignatureCertChainUrl", out var signatureChainUrl); if (String.IsNullOrWhiteSpace(signatureChainUrl)) { context.Response.StatusCode = StatusCodes.Status400BadRequest; return; } Uri certUrl; try { certUrl = new Uri(signatureChainUrl); } catch { context.Response.StatusCode = StatusCodes.Status400BadRequest; return; } // Verify SignatureCertChainUrl is Signature context.Request.Headers.TryGetValue("Signature", out var signature); if (String.IsNullOrWhiteSpace(signature)) { context.Response.StatusCode = StatusCodes.Status400BadRequest; return; } if (String.IsNullOrWhiteSpace(bodyStr)) { context.Response.StatusCode = StatusCodes.Status400BadRequest; return; } var valid = await RequestVerification.Verify(signature, certUrl, bodyStr); if (!valid) { context.Response.StatusCode = StatusCodes.Status400BadRequest; return; } } var skillRequest = JsonConvert.DeserializeObject <SkillRequest>(bodyStr); if (skillRequest == null) { context.Response.StatusCode = StatusCodes.Status400BadRequest; return; } var skillResponse = await skillRequestHandler.HandleRequestAsync(skillRequest); await context.Response.WriteAsync(JsonConvert.SerializeObject(skillResponse)); }
public IActionResult HandleSkillRequest() { string body; using (var reader = new StreamReader(Request.Body, Encoding.UTF8)) { body = reader.ReadToEnd(); m_Logger.LogDebug("body: " + body); } SkillRequest input = JsonConvert.DeserializeObject <SkillRequest>(body); string signatureCertChainUrl = Request.Headers["SignatureCertChainUrl"]; string signature = Request.Headers["Signature"]; m_Logger.LogDebug("signatureCertChainUrl: " + signatureCertChainUrl); m_Logger.LogDebug("signature: " + signature); if (string.IsNullOrEmpty(signatureCertChainUrl) || string.IsNullOrEmpty(signature)) { return(BadRequest()); } m_Logger.LogDebug("HandleSkillRequest: " + input.Session.Application.ApplicationId); if (input.Session.Application.ApplicationId != _appid) { m_Logger.LogDebug("ApplicationId wrong"); return(BadRequest()); } if (!RequestVerification.VerifyCertificateUrl(new Uri(signatureCertChainUrl))) { m_Logger.LogDebug("VerifyCertificateUrl: false"); return(BadRequest()); } var certificate = RequestVerification.GetCertificate(new Uri(signatureCertChainUrl)).Result; if (!RequestVerification.VerifyChain(certificate)) { m_Logger.LogDebug("VerifyChain: false"); return(BadRequest()); } if (!RequestVerification.AssertHashMatch(certificate, signature, body)) { m_Logger.LogDebug("AssertHashMatch: false"); return(BadRequest()); } if (!RequestVerification.RequestTimestampWithinTolerance(input)) { m_Logger.LogDebug("RequestTimestampWithinTolerance: false"); return(BadRequest()); } var requestType = input.GetRequestType(); if (requestType == typeof(IntentRequest)) { m_Logger.LogInformation("requestType IntentRequest"); var response = HandleIntents(input); return(Ok(response)); } if (requestType == typeof(LaunchRequest)) { m_Logger.LogInformation("requestType LaunchRequest"); return(Ok(BuildResponse(Statics.WelcomeMessage, false))); } m_Logger.LogWarning("ErrorResponse"); return(Ok(BuildResponse(Statics.ErrorMessage, true))); }
public async ValueTask <bool> IsRequestValidAsync(string encodedSignature, Uri signatureCertChainUrl, string request) { return(await RequestVerification.Verify(encodedSignature, signatureCertChainUrl, request)); }
protected async Task <ActionResult> CheckBadRequest(SkillRequest skillRequest) { try { if (!RequestVerification.RequestTimestampWithinTolerance(skillRequest)) { LogMessage("Request failed due to TimestampTolerance", SeverityLevel.Error, null); return(BadRequest()); } var sigCertChainUrl = Request.Headers["SignatureCertChainUrl"]; if (String.IsNullOrWhiteSpace(sigCertChainUrl)) { LogMessage("Request failed due to no SignatureCertChainUrl", SeverityLevel.Error, null); return(BadRequest()); } var signature = Request.Headers["Signature"]; if (String.IsNullOrWhiteSpace(signature)) { LogMessage("Request failed due to no Signature", SeverityLevel.Error, null); return(BadRequest()); } var sigCertChainPath = new Uri(sigCertChainUrl); if (!RequestVerification.VerifyCertificateUrl(sigCertChainPath)) { LogMessage($"Request failed due to an invalid Certificate Url ({sigCertChainPath})", SeverityLevel.Error, null); return(BadRequest()); } //var cert = await RequestVerification.GetCertificate(sigCertChainPath); //if (!RequestVerification.VerifyChain(cert)) //{ // LogMessage("Request failed due to invalid Certificate Chain", SeverityLevel.Error, null); // return BadRequest(); //} //Request.Body.Position = 0; var body = await new StreamReader(Request.Body, Encoding.UTF8).ReadToEndAsync(); //Request.Body.Position = 0; if (!await RequestVerification.Verify(signature, sigCertChainPath, body)) { LogMessage($"Request verification failed! (sig: {signature}, sig cert chain: {sigCertChainPath}, request details: {await GetRequestDetails()})", SeverityLevel.Error, null); return(BadRequest()); } } catch (Exception exc) { LogMessage($"Request failed because of unknown error. Request: {await GetRequestDetails()}", SeverityLevel.Error, new Dictionary <string, string>() { { "StackTrace", exc.StackTrace } }); return(BadRequest()); } //Success, let's log the request info temporarily LogMessage($"Successful request: {await GetRequestDetails()}", SeverityLevel.Verbose, "AlexaBaseController", "CheckBadRequest"); return(null); }
/// <summary> /// Validates the timestamp. /// </summary> /// <param name="skillRequest">The current skill request.</param> private static bool IsTimestampValid(SkillRequest skillRequest) { return(RequestVerification.RequestTimestampWithinTolerance(skillRequest)); }