Tuck in your APIs safe and sound with these guiding principles for API security

how to build secure APIs

Joyce Lin
Joyce Lin
Sep 22, 2018 · 12 min read

Headlines about cyberattacks are splashed all over the news, and there’s more attacks that we don’t ever hear about. From a security standpoint, modern software’s reliance on APIs is a double-edged sword. APIs allow us integrate with cloud services and to scale our business more easily. However, APIs also increase our attack surface, by opening up access points through which an attacker can penetrate our environment.

When you build your API, you’re exposing your business to potential vulnerabilities. Hackers gonna hack. Black hat hackers try to ferret out confidential user data or compromise critical business services. Even without any malice, users can unintentionally overwhelm your servers without any notice.

Building secure APIs is the responsibility of every developer, not just the InfoSec team.

Protect your APIs with these guiding principles

7 Guiding Principles for API security

Validate API requests just as rigorously as you’d vet input to your standard web app. Even though you may think requests are only going to come from your mobile app or a trusted third-party, in most cases, an attacker can send a request directly to your API.

So treat all request data received by your API as untrusted, including headers, and don’t rely only on cookies for authentication, as it may make your API vulnerable to cross-site request forgery (CSRF).

- Clint Gibler, NCC Group

When you’re building your own APIs, keep the following principles for API security in mind.

#1 Validate user input

The server should validate parameters and payloads against a specific set of expectations. For example, ensuring that input is treated as the appropriate data type, or verifying that the incoming Content-Type header and content are the same.

Besides protecting against external security attacks, this optimization can save unnecessary load on your system. Take, for example, a Node package lookup system. We know that an NPM package can only be 212 characters, and all ASCII. You can quickly return if the lookup is out of those criteria.

#2 Protect your data

Encryption is your friend

Your data is vulnerable while in transit and at rest. Encryption is your friend. Encrypt sensitive data before sending it, before storing it, and use encrypted connections (TLS) to protect your data in transit.

Never include your keys or other sensitive information in your URLs or query parameters. They’re not secure for many reasons. If you plan to send secrets for authentication, try including them in a header. Other sensitive information can be sent as an encrypted payload.

#3 Enforce limits

In general, DDoS attacks are perpetrated by large botnets that make many requests simultaneously to the target, such as a web app. Since the server can’t handle all of those requests at the same time, legitimate users cannot use it.

- Clint Gibler, NCC Group

Besides limiting the number of requests a client can send over a certain period of time, there’s other ways to control the load on your system:

  • Amount of data transmitted
  • Number of requests submitted from the same IP
  • Results returned per query
  • Number of concurrent sessions
  • Duration of a session
  • Longevity of an access token

#4 Follow an authentication protocol

Salt and hash your secrets

Follow an authentication protocol that allows the server to verify the user is who they say they are.

Never store passwords in plaintext. Keys, tokens, and other sensitive credentials should be salted and hashed for an additional layer of security in case of a data breach.

#5 Establish an authorization policy

Not everyone should have access to everything. Provide access to resources only as it becomes necessary.

Role-based access controls make it easy to provide and revoke access. Follow the Principle of Least Privilege (PoLP) and allow users and applications to access only the information and resources that are necessary for its legitimate purpose.

— Hamidreza Hamedtoolloei, Intuit

#6 Handle and log errors

Studies show the average time to detect a breach is over 200 days. Logging error messages can alert the team to unusual activity and provide clues about a breach that has occurred.

#7 Test and monitor your APIs

Make sure your APIs are behaving as expected

Finally, a benefit to being paranoid! Security though obscurity, or relying on the secrecy of your system’s design or implementation as the main method of providing security, is never a sound strategy.

Periodic auditing can help identify vulnerabilities and alert you when something is going awry. At scale, you can employ some white hat testing or chaos engineering methods to poke at your API and fortify your system’s resilience.

The difference between Authentication and Authorization

As an analogy, say somebody asks where I’m from. If I’m talking to someone in the US, I’ll say that I’m from Chicago. If I’m traveling abroad in Istanbul, I’ll say that I’m from the US.

In the same way, the context matters when talking about “auth”. If the conversation is about building APIs, I probably mean “auth” to encompass both authentication and authorization. If the conversation is about the security of APIs, I should talk about authentication and authorization separately. Saying “auth” would be ambiguous without more context clues.

Authentication is verifying that you are who you say you are. A user would prove their identity by providing information that is known only to the user and the authentication system, like a password or fingerprint.

Authorization is verifying if you have permission to access a resource. An administrator will grant rights to access protected resources. Authorization typically requires authentication as a precursor to providing access to protected resources.

Balancing Usability with Security

User experience and security don’t always go hand in hand. It’s important for developers to learn how to satisfy both requirements.

Balancing usability with security is tricky

A recipe for using JSON Web Tokens (JWT) to authenticate and authorize requests in Postman

As you get started developing ironclad APIs, let’s take a look at how we can use Postman to authorize our requests. In this example, we’ll use JSON Web Tokens to secure and access our API.

What is JWT?

JWT is commonly used for authorization. JWTs can be signed using a secret or a public/private key pair. Once a user is logged in, each subsequent request will require the JWT, allowing the user to access routes, services, and resources that are permitted with that token.

Set up an API with JWT authentication

For this example, make sure you have Node.js and the npm package manager installed on your machine. Get started by cloning the repository, install the dependencies with npm install, and then start your server locally with node.server.js.

Run your server locally

Click the Run in Postman button at the bottom of the README file to import the sample Postman collection into the Postman app. If you’re working off your own API, substitute your endpoints for the example included in this Postman collection.

The first request in the collection is a POST request to create user. If you already have a user, use the second request in the collection to create a new session. In both cases, you will see the access token included in the JSON response object.

POST request to create a session

Save the JWT as a variable

Instead, let’s save the JWT as a variable so that we can reuse the token over and over again in future requests. Create a new environment. Under the Tests tab, save the access token as an environment variable with pm.environment.set(), and re-run the request.

Save the access token as an environment variable under the Tests tab

Under the Quick Look icon, we can see that our JWT is saved as an environment variable. Now we can use our token in subsequent requests.

JWT saved as an environment variable

Add JWT to headers in Postman

Option 1: add an authorization header

If your authorization accepts a custom syntax, you can manually tweak the prefix here (e.g. Token <your-access-token> instead of Bearer <your-access-token).

Option 1: add a header

Option 2: use an authorization helper

Option 2: use an Authorization helper

Click the orange Preview Request button to see a temporary header has been added under the Headers tab. This temporary header is not saved with your request or collection.

Option 2: generates temporary headers

What’s the difference between these 2 approaches? The approach you use should depend on how you’re planning to use it.

Option 1: add an authorization header

  • Authorization header is displayed explicitly in the API documentation.
  • With both of these options, you can share the request and collection with your teammates. Header is saved with the request and collection under the header property.

Option 2: use an authorization helper

  • With both of these options, you can share the request and collection with your teammates. Authorization is saved under the auth property.

Scripts to check token expiration

Once again, there are 2 approaches for checking the expiration of your JWT. The approach you use choose will depend on your specific circumstances.

Option 1: Separate request at the beginning of the collection

Option 2: Pre-request script to run before each request

Check for token expiration before sending your request

This option is good if you’re working with a large collection that might take a while to run, or you have a short-lived token that could expire soon. In this case, add some logic in a pre-request script to check if the current token is expired. If the token is expired, get a fresh one (e.g. using pm.sendRequest()) and then reset your new token’s time to live. With this approach, remember that you can use a collection- or folder-level script to run this check prior to every request in the collection or folder.

Sessions to keep stuff private

Yes, you can!

Postman gives you the best of both worlds — collaboration with security, so that API keys and passwords don’t have to pass through your network.

Sessions are an additional layer within the Postman app that stores variable values locally. By default, sessions do not sync with Postman servers. Changes captured in the individual session remain local to your Postman instance, unless you explicitly sync to the cloud.

Go to your Settings, and toggle off “Automatically persist variable values”.

Under your Settings, toggle off “Automatically persist variable values”

Now when you send a request and set a variable, the CURRENT VALUE is populated. You can think of this as a value that’s stored in a local session.

Current values are stored in the local session

If you want to share this value with your teammates or sync it to the Postman servers, this requires another step to to explicitly sync to the cloud. To sync all of your Current Values to the Initial Values, click Persist All. To sync only a single Current Value to the Initial Value, copy and paste the value from the 3rd column to the second column.

Persist your local changes and sync to the cloud

Session variables allow you to reuse data and keep it secure while working in a collaborative environment. They allow you more granular control over syncing to the server or sharing information with your teammates. Learn more about sessions or watch a video about working with sessions.

A final thought on building secure APIs

Protocols and methods that were previously deemed best practices by the experts become obsolete as new vulnerabilities are discovered and new technologies emerge. Developers with a security mindset are the frontline of defense in information security.

Having a security mindset is part of every developer’s job

API security is not the sole burden of the user, and building secure APIs is not the sole responsibility of the InfoSec team. Having a security mindset and healthy paranoia puts a spotlight on potential vulnerabilities and risks during development. Building secure APIs will minimize the exposure of current and future services.

Better Practices

For individual engineers to the largest teams, Better Practices is intended to distill knowledge from the Postman community. This is a place to learn about modern software practices together! Read more: https://medium.com/better-practices/introducing-better-practices-e9cf14cf0c88

Thanks to Abhinav Asthana

Joyce Lin

Written by

Joyce Lin

coding and cats in San Francisco

Better Practices

For individual engineers to the largest teams, Better Practices is intended to distill knowledge from the Postman community. This is a place to learn about modern software practices together! Read more: https://medium.com/better-practices/introducing-better-practices-e9cf14cf0c88

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade