Security Tip: Protecting Production APIs

[Tip#29] Protecting the integrity of your data is just as important as stopping hackers.

Security Tip: Protecting Production APIs

Firstly, what I mean by “production APIs” here are third-party APIs that your application connects to. Billing providers like Stripe immediately come to mind, as well as mail gateways like Postmark, and notification endpoints like Slack. These are the services your app communicates with as part of it’s normal operation, and should be considered just as important to secure as your application itself.

Your app will typically use API keys to connect to these services with, and you’ll often have at least two sets of keys: one for production use, and a second set for staging/testing/dev environments.

The production keys should only ever be used on production, and should only be known by whoever manages your production environment. While the testing keys should be used everywhere else… But how can you be sure?

Since security is all about sensible paranoia, it’s always worth taking extra steps to prevent security risks.

My solution is to prevent production API keys from being used in non-production environments at the Service Provider level. app()->isProduction() is your friend when it comes to detecting production environments, and some APIs, such as Stripe, even generate keys with prefixes that identify the type of key they are, which is fantastic for blocking production keys outside of production.

Stripe production keys:

pk_live_*
sk_live_*

Stripe test keys:

pk_test_*
sk_test_*

Knowing this prefix, you can do something like this in your AppServiceProvider:

protected function registerStripe()
{
    $secret = config('services.stripe.secret');

    if (! app()->isProduction() && ! Str::startsWith($secret, 'sk_test_')) {
        throw new Exception('ERROR: Stripe secret for dev/testing key should start with: sk_test_*');
    }

    Stripe::setApiKey($secret);
}

If the API doesn’t distinguish between the different keys, you’ll have to get more creative though.

One idea is to hard-code the first 2-3 characters of your staging keys into the code and require the prefix when not in production. It won’t expose anything if the code is leaked, and if the staging key is changed, you can commit a fix pretty quickly. (Just make sure the prefix doesn’t also match the production key!)


If you've made it this far, please share this Security Tip and Securing Laravel with your Laravel friends, colleagues, and enemies! The more folks we have learning about security, the more secure code will be written, and the safer the whole community and our users will be. Also, if you tag me I'll give it a retweet, and you can find all my socials on Pinkary.