Mastering API security is critical to building useful software. It’s also a notoriously difficult topic to master.
At its core, it deals with securing application programming interfaces (APIs), which allow applications to ask each other for information over the internet. The broad concepts behind API security are not difficult to understand, but implementation presents so many different considerations that it can be hard to see the bigger picture.
Josh Cummings, who has taught several courses on application security in Java for Pluralsight, and is a contributor to Spring Security, the predominant Java security framework for handling application security, said most of the confusion revolves around the security standard known as OAuth.
“If there’s any kind of dedicated security track at any software developer conference, almost always there’s one talk [titled something like], ‘Can you please explain OAuth to me one more time?’” Cummings said. “One that I just attended the other day — ‘OAuth: Explain It to Me Like I’m Five.’”
WHAT IS API SECURITY?
Tutorials and documentation that explain OAuth make prodigious use of diagrams to help illustrate the detailed flow of keys and secrets necessary for applications to communicate securely. Several months ago, Cummings attended a talk by Okta, a company that specializes in OAuth, which tried to illustrate to attendees the flow of keys and secrets in a three-dimensional way.
“They had made these huge posters and they had actors walking around the room trying to help people [visualize],” he said.
Why Do We Need API Security?
API security is not really taught as part of the core curriculum in college computer science classes. Most developers encounter it for the first time on the job, when they need to access or provide a secure API. At its most basic level, API security derives from the need to protect private information from people who should not have access to it.
For instance, a company that provides proprietary information to clients would want to restrict access to its API. Clients who call the company’s API should be able to retrieve the information they need, but the general public should be denied access.
Securing APIs can also be a good step toward preventing distributed denial-of-service (DDoS) attacks. APIs secured using OAuth hide APIs behind computationally inexpensive verifications, making the APIs less vulnerable to DDoS.
Even applications for end users, such as a login page on a website, is dependent on API security, because the mechanisms that allow end users to log in are, behind the scenes, also APIs.
“Anybody — meaning software or humans — can address an API with just an HTTP post,” Cummings said. “Even things that have a UI and have protection, they eventually go down to a server that is past that trust boundary, and is just going to take the username and password or whatever it needs, and the bad actor can just address that API and get the information that they need.”
Today, there are three dominant methods for providing API security: basic authentication, OAuth and mutual TLS.
The Pros and Cons of Basic Auth
Basic authentication — usually referred to as basic auth — is among the oldest and simplest methods for handling API security.
“It’s simple because it’s essentially an encoding of the user’s username and password as part of the HTTP protocol,” Cummings said. “They get sent over in a header called authorization, and browsers and web clients are already capable of sending headers. Usually it requires minimal infrastructure to get up and running.”
APIs that use basic auth just need to verify the username and password sent along with each request. The implementation is simple for both the service maintaining the API and the client that requests it.
“That’s kind of where the benefits stop,” Cummings said.
Unfortunately, steps taken to provide security breed their own security concerns. For basic auth, the main concern is that username and password combinations could get into the wrong hands, either through negligence or due to a cyberattack.
“All of a sudden, your service isn’t performing anymore, because each request is taking half a second or a second.”
“If somebody was using an end-user username and password and it was stolen, then that bad actor has access to the API permanently until your password is rotated,” Cummings said.
If the breach is undetected, the bad actor could gain access to the API indefinitely, without the end user even noticing. As a result, it’s a good practice for services that accept basic auth to only store hashed passwords. Hashing creates an encryption as unique as the password, but has the benefit that if the service were hacked, users would not have their actual passwords exposed.
Unfortunately, hackers can still use brute force to steal passwords — in essence, sending a continuous stream of possible username and password combinations at the API until they guess a valid combination. The trick to prevent brute force password cracking is to use a computationally intensive hashing algorithm, which significantly reduces the volume of passwords hackers can try within a given time frame.
“The bad side of that is that with HTTP basic, that means that the password is getting hashed on every single request,” Cummings said. “And so all of a sudden, your service isn’t performing anymore, because each request is taking half a second or a second.”
The Evolution of OAuth
The first version of OAuth was published in a Request for Comment in 2010. Mark Cheshire, director of product at Red Hat, said the new protocol didn’t have security problems like existing ones did, but its complexity made it difficult to adopt correctly.
“In the very first version of OAuth, OAuth 1.0, that did a very good job on security, but it was at the expense of usability,” Cheshire said. “One of the ways in which OAuth [1.0] achieved good security was the API consumer — the client — would have to sign every API transaction that they would send in. Additional tooling was needed by developers to be able to do that, and they’d get it wrong, so that wasn’t a good path. Then a second version of OAuth came out, and that provided a lot better usability.”
OAuth 2.0, which came out in 2012, is currently the industry standard for handling API security. The protocol revolves around three roles and their specific interactions. Apart from the client, which is the application requesting access to an API, and the API server, which is the application providing the API, OAuth 2.0 introduces a third role — the authorization server — which is an application that knows whether the client is authorized to access the API server.
“It began with a simple idea of, ‘We’d like to have the end user be able to decide what is done with their data.’”
These roles and interactions are seen in situations where, for example, a website asks the end user to sign in using Google or Facebook.
“It began with a simple idea of, ‘We’d like to have the end user be able to decide what is done with their data,’” Cummings from Spring Security said. “Because websites and companies started to coordinate with one another, there was a need for one company to need another company’s data.”
In this case, the website is the client requesting access to information from Google or Facebook, and Google or Facebook is acting as both the API server with the requested information and the authorization server keeping track of whether the client is authorized. The client website presents a sign-in page to the end user with the option of signing in through Facebook, and if the user chooses that option, the client is then able to pull the information it needs from Facebook’s API, such as the user’s name.
These interactions and authorizations are tracked using something called a bearer token, which behaves like a ticket. If client applications requesting access to the API server don’t have a bearer token, they are directed to the authorization server to obtain the token, and then return to the API server with the token to get the information requested.
Advantages of Using OAuth
The advantage of using a bearer token is that the client gets to hang on to it, so the client doesn’t have to go to the authorization server every single time they want to access the same API server. The token also has an expiration date, so if the token is stolen by an attacker, the attacker won’t have access to the API server indefinitely.
Another advantage of OAuth is that it allows the concepts of authentication and authorization to be separated, Cummings said.
“The reason for that is to give flexibility in your architecture,” he said. “The simplest authorization rule that you could say is, if you’re authenticated, if I know who you are, then you’re authorized to do this.... But if you couldn’t separate those two notions, there would be no way for you to have those finer-grained controls.”
By “finer-grained controls,” Cummings is referring to the concept of roles and access levels, authorizing and restricting access to different information based on the “type” of access a client has. This is difficult to do with basic auth, because in that case the API server is only verifying, through a username and password — whether the client is someone who has access, not what type of access they have. In OAuth, the authorization server handles authentication of the client, and then gives the client the bearer token that specifies the type of access they have to the API server.
“If you prove who you are, then now you can do all of the things,” Cummings said about basic auth. “In that case, we’d be simply relying on humans to know, ‘Even though there’s a button there that I could click on, I know I’m not supposed to click that button, because there’s someone else who’s supposed to do that.’ Depending on how sophisticated all of that is, you likely want to have some programmatic enforcement of those kinds of things.”
The ability to separate authorization from authentication also gives companies that are API providers the option to outsource their authentication, like companies that ask users to login through Google or Facebook do.
“You can follow the principle of ‘do one thing and do it well.’”
“When you’re a small company, you might not want to take on the liability of making people pick a username and password,” Cummings said. “If there’s a data breach, then I have to worry about the fact that people have to change their passwords.... They can turn all of that over to Google or to Facebook — if [Google or Facebook] say that you’re a trustworthy person, then I will believe you’re trustworthy.”
Even for API providers that don’t outsource authentication to another company, separating authentication from authorization makes code easier to write and maintain.
“You don’t want your business applications to have to worry about those things,” Cummings said. “OAuth gives you the flexibility to be able to say, ‘Let me redirect you over to the other service, whose sole job is authenticating people and authorizing actions.’ You can follow the principle of ‘do one thing and do it well.’ The authorization server is the thing that handles all authorization requests regardless of the circumstances, so your API only needs to verify the token.”
This separation of responsibility also allows API providers to purchase API security management tools from third parties that handle much of the configuration for you.
“API management tools are all about providing an access control layer for APIs, separating out responsibility for that to an external product,” Cheshire from Red Hat said. “You put an API gateway in that handles all of this access control layer without burdening the application itself with implementing all of these different complicated flows.”
Disadvantages of Using OAuth
Cummings said one of the disadvantages of OAuth is the importance of the authorization server to the protocol.
“It does push a heavier workload onto this centralized authorization server,” he said. “But that can be mitigated by passing tokens by value instead of by reference, and one of the ways to do that is with a spec called JWT.”
Bearer tokens following the JWT spec allow API providers to validate the token against the authorization server without sending a request to the authorization server every time. When OAuth first came out, every time the API server received a token from a client, the API server had to make a separate call to the authorization server to check the token’s validity.
“That authorization server is going to melt in production,” Cummings said. “In a big deployment, where you might have one API that talks to another API that talks to another API — that’s really not uncommon to go two or three services deep in a big application. And if each one of them on every request is having to talk to the authorization server to ask them whether or not the token is valid.... In a high-volume service that’s taking 5,000 requests a second, that authorization server is taking 15,000 requests per second, because each service along the way has to go through the server.”
Using the JWT standard decreases the negative effects of having a “single point of failure” in the OAuth flow, he said.
But the biggest disadvantage of OAuth is still its complexity. Compared to basic auth, OAuth is a labyrinth of choices and configurations, especially for developers writing code for the client requesting API access.
“Some enterprises would make the wrong decision in one of the combinations, and it would end up opening up a security hole.”
“The client is more complicated because the developer has more choices,” Cummings said. “There are at least two major flows, and then there is another minor one.”
Each OAuth flow addresses a different type of client — for instance, whether the client is another back-end server requesting data from the API server, or whether the client is a front-end website coded in JavaScript, or whether it is an app on a mobile phone. Different types of clients require different security considerations.
“The front channel, being the browser, is a lot harder to secure than the back channel,” Cummings said. “If you store things in cookies, if you store things in local storage or session storage, it’s not an easy thing to make sure that those things can’t be seen by bad actors who can potentially run arbitrary JavaScript on your page. Because of that, those flows if you have a front-end negotiator are more complicated, to try and accommodate the different kinds of bad things that a bad actor could do.”
It’s not a simple trade-off between security and complexity when it comes to API security, however. A complex protocol can be confusing to developers in charge of implementing API security for their companies. If developers do not understand the security protocol they are implementing and do it incorrectly, it opens up the API to security vulnerabilities.
“[OAuth] is still very much open to interpretation, there’s so many different options that any implementation could choose,” Cheshire said. “It means that some enterprises would make the wrong decision in one of the combinations, and it would end up opening up a security hole.”
Tips for Implementing OAuth Correctly
Does OAuth need to be so complex? Cummings said that, unfortunately, its current level of complexity isn’t arbitrary. The different choices available to developers exist to allow implementation of different flows and to address specific security concerns.
“When I’m talking to people about why it’s so complicated, I’ll ask them questions like: ‘Well let’s start with HTTP basic and see the problems with it. Well, now what should we do?’” he said. “Slowly but surely, and we all come to realize that the things that OAuth is accomplishing are the things that they need in order to ensure that they can trust the payload.... Honestly, for my part, OAuth is the simplest thing that I know that can handle delegated authority in a distributed system.”
But that’s not to understate the danger of implementing a complex security protocol. OWASP Top Ten, an annual list of the most critical security risks to web applications, lists security misconfiguration at No. 6. Cheshire recommended that developers implementing OAuth take advantage of existing libraries.
“Most programming languages and frameworks include libraries,” Cheshire said. “And each framework typically has its own kind of top top list — there’s usually not just one alternative, usually there’s several alternatives available in the community to help.”
“I don’t run into a lot of folks who are out there, implementing OAuth themselves.”
Cummings agrees: Writing an authorization server from scratch is almost always a mistake.
“I don’t run into a lot of folks who are out there, implementing OAuth themselves — and if they are, I would strongly encourage them to find the appropriate library or framework that matches up with their language, on the API security side,” he said. “On the authentication side, I strongly encourage them to look at a service.... Sometimes we’re worried about paying money to do something for us that we software engineers feel like we can build ourselves, but that kind of hubris in the security space is something that folks tamp down on and say, ‘You know what, these are the professionals.’”
Cummings also recommends staying current on dependencies and making use of code reviews to help catch vulnerabilities and mistakes in security configurations.
“It sounds really simple, but code review helps out a lot,” he said. “A lot of mistakes are because we’re inside of our own heads.... Stay as up to date as possible on your dependencies. There are tools out there that can audit you, so staying as up to date as possible on those versions will help to ensure that you don’t have security misconfigurations.”
Pros and Cons of Mutual TLS
A final type of API security protocol to consider is mutual TLS authentication. It requires both the API server and the client to present signed certificates proving identity — something that usually only servers present.
“In the past, it used to be very common, it used to be the primary way for securing important API resources,” Cheshire said. “You would see that in banking applications, maybe government organizations. Then with the emergence of more secure authentication mechanisms for APIs, like OAuth, we actually saw a decline in the use of mutual TLS.”
Mutual TLS declined in popularity because it’s harder than basic auth and OAuth to scale.
“You need to share the client certificate between the API consumer and the API provider, and it’s quite complicated to share client certificates when you don’t control both ends,” Cheshire said. “It’s not easy to distribute certificates to hundreds or thousands of consumers.”
These days, although mutual TLS isn’t used very much on its own, Cheshire said the protocol is starting to see a resurgence among companies looking for added protection on their internal network traffic against hackers.
“Once a hacker is in a private network, they basically can roam around from one service to another if there are no secure endpoints, and if traffic isn’t encrypted,” he said. “[Mutual TLS] is an extra line of defense to make sure that even if a hacker gets into a network, it’s still not enough for them to access private and confidential data.”
Some companies use OAuth to secure public-facing APIs and mutual TLS to secure internal APIs. As with other areas of security, it’s not necessarily about picking the best method, but using methods that address the security concerns specific to your use case.