Advertisement
  1. Code
  2. Yii
Code

Building Your Startup: Securing an API

by
Difficulty:IntermediateLength:ShortLanguages:
This post is part of a series called Building Your Startup With PHP.
Building Your Startup: Leveraging Crowdfunding
Building Your Startup: Approaching Major Feature Enhancements
Final product image
What You'll Be Creating

Welcome to the Building Your Startup With PHP series, which is guiding readers through the launch of an actual startup, Meeting Planner. Each episode details different coding and business challenges, with detailed examples you can use to learn.

Introduction

Recently, I introduced you to Yii's simple REST API generation and Meeting Planner's new "RESTful" service API. At that time, I mentioned that these APIs were only loosely secured. Sure, there was a shared secret between the client and the server, but there were a couple of problems.

First, the secret key and user tokens were repeatedly transmitted in query parameters of SSL calls. And there was no other authenticity check for the data, allowing a middle-person attack.

In today's episode, I'll guide you through how I secured the API against these weaknesses for a more robust API.

If you've been reading our startup series, you've probably already tried Meeting Planner and Simple Planner, but if not, please do. Scheduling a meeting is easy:

As usual, I'll be participating in the comments below, so please offer your thoughts. You can also reach me on Twitter @lookahead_io. I'm always especially intrigued if you want to suggest new features or topics for future tutorials.

As a reminder, all of the code for Meeting Planner is written in the Yii2 Framework for PHP. If you'd like to learn more about Yii2, check out our parallel series Programming With Yii2.

The Initial API Security

Let's begin by taking a look at the early API security I coded. We'll presume there's a mobile app that I've shared an $app_id and $app_secret with. Only API callers with these keys are accepted.

For example, the app tries to register its owner, likely a new Meeting Planner user:

The app calls the above actionRegister via https://api.meetingplanner.io/user-token/register/ with arguments as follows:

  • $app_id and $app_secret for authentication
  • $source = 'facebook' for the OAuth service we're using, and accompanying $oauth_token from that service
  • $email, $firstname, and $lastname provided via OAuth

All of those are query arguments such as:

Service::verifyAccess($app_id,$app_secret) looks up the keys to authenticate the call as shown below:

Because the keys and the data were sent via SSL, they're pretty secure but not invincible. Neither is the secret key safe on users' iPhones for certain.

How can we make this more secure? Here are a few ideas:

  1. Don't ever transmit the secret key over the Internet.
  2. Don't transmit any of the data as URL parameters which might show up in server logs.
  3. Sign all the data to verify its accuracy.

These are actually standard practices used for securing APIs.

Note: An example of the risk of transmitting data that could be exposed in server logs would be the email and the Facebook OAuth token. If found in logs, these could be used with the Facebook API to access someone's Facebook account.

Implementing Better API Security

Using Hash Signatures

First, I'm going to stop transmitting the $app_secret. Instead, we'll sign the outgoing data with it before making an API call. 

So we'll alphabetize the variables and concatenate them into a string, like this:

Resulting in:

Then, we'll hash the data with PHP's hash_hmac and the sha256 algorithm using our secret key.

Building Your Startup Securing API - PHP hash_hmac docs

This creates a unique hash code based on the arguments of the API call and our shared secret key:

Now, we can make a call on the API without transmitting the secret key. Instead, we transmit the signature of the hashed data above.

I've been using Postman to test the API, but you can also use cURL:

Building Your Startup Securing API - Testing the API with a signature

Here's the receiving API code that responded to the call above:

Furthermore, as I reviewed last time, each user receives their own token when they access Meeting Planner through the API, e.g. via their mobile phone. So, subsequent to registration, we can sign calls with their individual token and don't need to transmit either the application's secret key or the user's individual token.

Sending Data in the HTTPS Headers

Next, we'll migrate sending data in the headers. You can do this easily with Postman or cURL. Here's Postman:

Building Your Startup Securing API - Testing the API sending data in the headers

And here's cURL:

Here's the receiving code which gets the API data from HTTPS Headers:

In Closing

We began today with the following goals:

  1. Don't ever transmit the secret key over the Internet.
  2. Don't transmit any of the data as URL parameters which might show up in server logs.
  3. Sign all the data to verify its accuracy.

And we accomplished all of these goals with only modest changes to our API code. It was fun making these changes and seeing how easily we can better secure an API. I hope you enjoyed following along with today's episode.

I regularly monitor the comments, so please join in the discussion. You can also reach me on Twitter @lookahead_io directly. And, of course, watch for upcoming tutorials here in the Building Your Startup With PHP series.

If you didn't earlier, try scheduling a meeting at Meeting Planner and let me know what you think. I especially appreciate feature requests.

Related Links

Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.