There are many ways to build authentication in an API-first product like SparkPost, and the one that we chose early on is the use of API keys. Injecting your API key as a raw Authorization header or via standard HTTP Basic Auth makes it very easy to use our APIs. API keys like this are a common standard for webservices, but how secure is this system?
When using any webservice, if an attacker gains your API key they can act on your behalf, and do things like (in our case):
- send their email for free through your account
- download your recipients list and feed them to spammers (if they are not spammers themselves)
- edit your templates to inject phishing links
- send spam or phishing on your behalf
Any of these outcomes could be very damaging to your reputation and to your business, and in the case of phishing potentially directly damage your end users. This is why it is extremely important to make sure no one can discover your API key.
Did I hear bruteforce? Our API keys are randomly generated 40-long hexadecimal strings. This makes a total of 1.4615e+48 API keys. If all 3 billion computers and smartphones in the world were trying 100 api keys per second, assuming that our servers would allow that, going through all of the possible API keys would take more than 150,000,000,000,000,000,000,000,000,000 years. So brute forcing the API key just does not make sense.
So how can someone find you API key? Because the key is passed as a header, it can be read with man-in-the-middle attacks, so you should always make sure that your client is checking the SSL certificates when connecting to our APIs (this is a major reason why we require https for API connections). Also, if you are careless with your use of public code repositories like github, your API key can easily end up exposed in the wild. This isn’t an academic problem: there are known bots crawling github to find API keys, and there have been successful attacks through that vector.
IP whitelisting to the rescue
When you create an API key, you can now specify a list of IPs that are authorized to use this key. You can specify several IP, as well as IP blocks, using the CIDR notation, so you don’t have to list your servers individually. When the API key is used, for REST APIs or SMTP, we’ll match the connecting IP against this list to allow or deny access.
With this feature, even if your API key is found or stolen, only your servers will be able to use it. Given the risks and how easy it is to set it up, we highly recommend all our customers use this feature.
A few personal recommendations around security:
- Do not keep your API keys in code. There is a lot of benefits in keeping them as environment variables, like Heroku does
- You can create an unlimited amount of API keys, and it is best for security to split the responsibilities among several API keys, instead of only one swiss-knife key. This would also allow you to have different IP whitelists per key, for even better separation of concerns
- If you work with third parties, do not share your API key but create a new one for them, with only the needed grants, and attached to their IPs
- Since API keys can only be created via the UI, enabling 2-factor authentication on your SparkPost account is a must-have and takes only 2 minutes