11 min read

In this article, by Tim Rogers author of Twilio Best Practices, we’ll see how to keep our Twilio account and applications (and ultimately credit) secure by:

  • Enabling two-factor authentication on our Twilio account
  • Verifying that requests to our application are really coming from Twilio
  • Setting up a circuit breaker for our account and any subaccounts

(For more resources related to this topic, see here.)

Enabling two-factor authentication

Twilio offers two-factor authentication functionality that we can enable on our account.

This will give you much greater security if someone tries to break into your account following the something you know and something you have model. Apart from your password, Twilio will send you an SMS or call you when a login attempt is made, requiring you to enter a one-time password.

Not only will this largely prevent malicious access to your account, but you’ll also know that someone is attempting to access your account, and what’s more, that they have your password.

It’s worth noting that, unsurprisingly, you can quite easily roll two-factor authentication functionality for your own application using Twilio’s call and SMS functionality. Check out https://www.twilio.com/docs/howto/two-factor-authentication for help with getting started.

There are two steps to enable two-factor authentication:

  1. First, you’ll need to add a phone number. You can do this from your Twilio dashboard by clicking on the dropdown in the top-right corner, and then clicking on the first entry with your name and e-mail address.Twilio Best Practices
  2. Next, click on Add phone number, and then enter your phone number. Twilio will send you an SMS (or alternatively, call you if you’d like), thereby ensuring that you own the phone number that you’ve provided.Twilio Best Practices

Once you’ve added and verified your phone number on your user profile, you’ll need to set up two-factor authentication on your account(s). To get to the right place, click on Account Settings in the dropdown.

Twilio Best Practices

If your login has been given access to another user’s Twilio account, (that is, the account you access from the Switch Accounts menu option) an administrator on that account will need to repeat this process.

From this page, you’ll be able to choose between two different two-factor options (you can also disable the feature here):

  • Once Per Computer: This will effectively make the device you’re using trusted, which means that subsequent logins for the next 30 days won’t require you to use your phone.
  • Every log-in: Every time you try to log in to Twilio, you’ll have to provide a one-time password from your phone.

Once you’re done, click on the Save Settings button at the bottom of your page to set up the two-factor authentication.

There are a couple of other features you might want to check out on the Account Settings page.

You can reset your API credentials if you accidentally reveal them and you can disable parts of Twilio’s Request Inspector which might potentially store sensitive information from your application and require passwords in order to access recordings and media you send in MMS messages.

Verifying that requests are from Twilio

If parties other than Twilio are able to make requests to your application, they can potentially change and corrupt data or access sensitive information.

Without authentication measures, if an attacker was able to guess the URLs of the endpoints on your application that Twilio hits with its webhooks, they could wreak havoc. For instance, they could spoof fake SMS messages so that they appear to come from users or they could access the private phones numbers of users they should only be able to call through a public line you provide.

There are two routes you can take to prevent this, ensuring with a reasonable degree of certainty that a request genuinely comes from Twilio:

  • Set up HTTP Basic Authentication
  • Verify the signature of requests to ensure they’re signed by Twilio

HTTP Basic Authentication

HTTP Basic Authentication simply allows you to require a username and password to access your web server’s resources.

If you’re working with PHP, you’ll want to set this up on the web server level. This is possible in most servers, including:

  • Apache ()
  • Nginx ()
  • IIS ()

If you’re not using one of these, you can be virtually certain anyway that this option will be available to you; simply have a look at its documentation or search the web.

Alternatively, you can implement Basic Authentication in your PHP code using code along these lines. We’ll store the username and password in environment variables for security:

<?php
if (!isset($_SERVER['PHP_AUTH_USER'])) {
// The user didn't even try to authenticate, so sent 401 Unauthorized
header('WWW-Authenticate: Basic realm="Twilio only!"');
header('HTTP/1.0 401 Unauthorized');
exit;
} elseif ($_SERVER['PHP_AUTH_USER'] == $_ENV["TWILIO_USERNAME"] && $_SERVER['PHP_AUTH_PW'] == $_ENV["TWILIO_PASSWORD"]) {
// The user authenticated successfully, so perform actions and output TwiML
} else {
// The user tried to authenticate, but didn't have the right credentials
header('WWW-Authenticate: Basic realm="Twilio only!"');
header('HTTP/1.0 401 Unauthorized');
exit;
}
?>

Let’s go through this bit by bit:

  • If $_SERVER[‘PHP_AUTH_USER’] isn’t set, then no username and password has been provided, so we respond with a 401 Unauthorized error (that is, a header request, and the user provides a username and password, as well as the WWW-Authenticate header), which will make browsers display Twilio only! in the login dialog.
  • If the provided username and password do match what is stored in the TWILIO_USERNAME and TWILIO_PASSWORD environment variables respectively, then we perform actions that the request requires and respond with TwiML.
  • If a username and password was provided, but didn’t match those we expected, then we send our 401 error and associated headers again.

When we’re providing a URL to Twilio (for instance, when initiating a call via the REST API, or setting it for incoming calls or SMS messages from our Dashboard), we can set the username and password in this format:

Twilio Best Practices

Verifying the signature

Alternatively, instead of using a username and password, we can verify the cryptographic signature Twilio generates with its requests based upon our auth token which is sent in the X-Twilio-Signature header.

The scheme for doing this is somewhat complicated (you can find it in full at https://www.twilio.com/docs/security#validating-requests) but fortunately, Twilio provides validation functionality in their API libraries alongside code samples.

For this method of verification to be available, you’ll need to serve your application over HTTPS with Transport Layer Security (TLS) enabled. In fact, you should always do this with your Twilio application, as a good security practice.

Following the SSLv3 vulnerability discovered in October, 2014 known as POODLE, you’ll want to double-check the security of any SSL configuration. See https://www.digitalocean.com/community/tutorials/how-to-protect-your-server-against-the-poodle-sslv3-vulnerability for details.

In PHP, we’d execute the following:

<?php
// Load auth token from the TWILIO_AUTH_TOKEN environment variable
$authToken = $_ENV['TWILIO_AUTH_TOKEN'];
// You'll need to make sure the Twilio library is included, either by requiring
// it manually or loading Composer's autoload.php
$validator = new Services_Twilio_RequestValidator($authToken);
$url = $_SERVER["SCRIPT_URI"];
$vars = $_GET;
$signature = $_SERVER["HTTP_X_TWILIO_SIGNATURE"];
if ($validator->validate($signature, $url, $vars)) {
// This request definitely came from Twilio, so continue onwards...
} else {
// Watch out - this is not a real request from Twilio.
header('HTTP/1.0 401 Unauthorized');
}
?>

Here, we instantiate a Services_Twilio_RequestValidator object from the API library with our auth token before passing in the requested URL, the request body ($_GET in this case, but for a POST request, this would be $_POST), and the signature.

We then call the validator’s validate method with these pieces of data, allowing it to generate the signature itself, and comparing it against what we received in the X-Twilio-Signature header. If it matches, the request is genuine, but if not, the request is spoofed and is not from Twilio.

Building a circuit breaker

Using Twilio’s Usage Triggers allows us to build a circuit breaker.

In short, this will let us know when one of our subaccounts passes certain amounts of usage, which will help us detect possible abuse of our account, as well as mistakes in our code. It can even help detect abuse if we were running a multitenant app (that is, offering Twilio-based services to our users).

When our specified usage threshold is surpassed, Twilio will send a webhook to a URL of our choice. From this URL, we can perform a range of actions, whether that is sending ourselves an e-mail or even suspending the account in question.

Here, we’ll just run through a quick example of suspending an account if it spends more than $50 in one day.

We’ll set up our Usage Trigger using the Twilio dashboard. To do this, first log in, and then switch to the appropriate subaccount you’d like to set up the trigger for by clicking on your name in the top-right corner. Next, click on Subaccounts, and then click on the desired account.

Next, click on Usage in the navigation bar, then click on Triggers underneath, and then click on the Create Usage Trigger button.

Fill out the fields as shown in the following image. First, you’ll need to click on the Trigger a webhook link on the right-hand side of the page where Send an email appears in the screenshot to set up a webhook, replacing the URL with one that would be accessible from a domain of your own, of course.

Twilio Best Practices

We might also want to automate this process of setting up a usage trigger using the REST API. For example, we might want to automatically suspend a subaccount we’ve just created for a customer if their usage goes beyond reasonable limits. In order to do so, we’d do the same thing we did previously in PHP like this:

<?php
$accountSid = $_ENV['TWILIO_ACCOUNT_SID'];
$authToken = $_ENV['TWILIO_AUTH_TOKEN'];
$subaccountSid = '<the SID of the subaccount>';
// You'll need to make sure the Twilio library is included, either by requiring
// it manually or loading Composer's autoload.php
$client = new Services_Twilio($accountSid, $authToken);
$account = $client->accounts->get($subaccountSid);
$account->usage_triggers->create(
'totalprice',
'+50',
'https://twiliobestpractices.com/path/to/trigger_action.php',
array(
   'Recurring' => 'daily',
   'TriggerBy' => 'price',
   'FriendlyName' => 'Suspend if uses more than $50 per day'
)
);
?>

Both options do exactly the same thing. They create a trigger that will send a webhook to when more than $50 is spent by our subaccount on any one day.

It’s completely up to us what we do from the endpoint that receives the webhook. Anything we can program is possible, from suspending the account to calling an engineer to look into it.

Here’s some example code to go with the usage trigger we just set up that will automatically suspend the account once it goes over $50 spend in a day.

In this code sample, we also verify the authenticity of the request, as we saw previously, making sure that this is a genuine Usage Trigger webhook from Twilio:

<?php
// Before starting, you'll need to require the Twilio PHP library
// We'll load the SID of the subaccount that the trigger relates to and its
// auth token from environment variables, but in reality, you're likely to be
// loading them from a database of your users' details based on a passed-in ID,
// or something along those lines.
$subaccountSid = $_ENV['TWILIO_SUBACCOUNT_SID'];
$subaccountAuthToken = $_ENV['TWILIO_SUBACCOUNT_AUTH_TOKEN'];
$url = $_SERVER['SCRIPT_URI'];
$signature = $_SERVER['HTTP_X_TWILIO_SIGNATURE'];
$validator = new Services_Twilio_RequestValidator($subaccountAuthToken);
if ($validator->validate($signature, $url, $_POST)) {
   $client = new Services_Twilio($subaccountSid, $subaccountAuthToken);
   $client->account->update(array('Status' => 'suspended'));
} else {
   header('HTTP/1.0 401 Unauthorized');
}
?>

We’ve shown you examples of doing all of this using the PHP library, but you can do it with any of Twilio’s libraries . You can also do this directly with the REST API using a tool such as Postman.

Summary

In this article, we saw three helpful tips to keep your Twilio account and application secure:

  • First, we enabled Two-Factor Authentication to keep our account secure, even if someone finds out our password.
  • Next, we learned how to make sure that the requests your app receives genuinely come from Twilio, by either using the HTTP Basic Authentication or by verifying the cryptographic request signature.
  • Finally, we set up alerts to inform us and take appropriate action when certain usage thresholds are reached using Twilio’s Usage Triggers, helping protect your app from abuse and coding errors.

Resources for Article:


Further resources on this subject:


LEAVE A REPLY

Please enter your comment!
Please enter your name here