Skip to content

Instantly share code, notes, and snippets.

@acamino
Created October 10, 2017 21:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save acamino/91d21da5dbb88be5d8a69e4a48c9d045 to your computer and use it in GitHub Desktop.
Save acamino/91d21da5dbb88be5d8a69e4a48c9d045 to your computer and use it in GitHub Desktop.
Secure your C# / ASP.NET Core by validating incoming Twilio Requests
using Microsoft.AspNetCore.Mvc;
using Twilio.TwiML;
using ValidateRequestExample.Filters;
namespace ValidateRequestExample.Controllers
{
public class IncomingController : Controller
{
[ValidateTwilioRequest]
[Produces("text/xml")]
public IActionResult Voice(string from)
{
var message = "Thanks for calling! " +
$"Your phone number is {from}. " +
"I got your call because of Twilio\'s webhook. " +
"Goodbye!";
var response = new VoiceResponse();
response.Say(string.Format(message, from));
response.Hangup();
return Content(response.ToString());
}
[ValidateTwilioRequest]
[Produces("text/xml")]
public IActionResult Message(string body)
{
var message = $"Your text to me was {body.Length} characters long. " +
"Webhooks are neat :)";
var response = new MessagingResponse();
response.Message(new Message(message));
return Content(response.ToString());
}
}
}
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Configuration;
using Twilio.Security;
namespace ValidateRequestExample.Filters
{
[AttributeUsage(AttributeTargets.Method)]
public class ValidateTwilioRequestAttribute : ActionFilterAttribute
{
private readonly RequestValidator _requestValidator;
private static IConfigurationRoot Configuration =>
new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", true, true).Build();
public ValidateTwilioRequestAttribute()
{
var authToken = Configuration["TwilioAuthToken"];
_requestValidator = new RequestValidator(authToken);
}
public override void OnActionExecuting(ActionExecutingContext actionContext)
{
var context = actionContext.HttpContext;
if (!IsValidRequest(context.Request))
{
actionContext.HttpContext.Response.StatusCode = StatusCodes.Status403Forbidden;
}
base.OnActionExecuting(actionContext);
}
private bool IsValidRequest(HttpRequest request) {
var requestUrl = RequestRawUrl(request);
var parameters = ToDictionary(request.Form);
var signature = request.Headers["X-Twilio-Signature"];
return _requestValidator.Validate(requestUrl, parameters, signature);
}
private static string RequestRawUrl(HttpRequest request)
{
return $"{request.Scheme}://{request.Host}{request.Path}{request.QueryString}";
}
private static IDictionary<string, string> ToDictionary(IFormCollection collection)
{
return collection.Keys
.Select(key => new { Key = key, Value = collection[key] })
.ToDictionary(p => p.Key, p => p.Value.ToString());
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment