Design Considerations for API Security

Security has to be a key part of any development project, especially if it contains APIs. It’s almost impossible to build a 100% secure system. Instead, our goal is to design a system as much harder to hack as possible.

The Balance between Security and User Experience

One of the main challenges in security design is to find the right balance between security and user experience. We can design a system with very complex passwords or several factors of authentication. Your system will be very secure and your passwords almost unbreakable with more than 20 characters. However, who is going to remember this kind of password? Most likely your users will end up writing down these passwords on a piece of paper, post-its, mobile notes... which will ruin the ultimate goal of your passwords.


The Principle of psychological acceptability

This principle states that security mechanisms should not make the resource more difficult to access than if the mechanisms were not present. Good examples that follow this principle are:
  • Face ID in Apple phones introduces another factor of authentication, but it does not add any difficulty to the end user. On the contrary, the end user hardly notices the device was blocked.
  • Apple also offers unlocking your Mac with your Apple watch instead of retyping your password. Again, this adds a factor of authentication but improves user experience.


Performance Vs Security

We need to consider the cost of the overhead we add to our systems operations/transactions when implementing security mechanisms. Examples of API security mechanisms that can kill performance

The use of TLS or API keys in all API calls. 

If you have a transaction that goes through multiple APIs (following API led connectivity each transaction would go through exp, proc and sys), the overhead of encrypting and decrypting at every hop can create too much latency. A good balance might be using TLS/mTLS only at exp layer and client id enforcement for internal traffic over HTTP (exp to proc and proc to sys). We just need to make sure that internal traffic is protected at network-security level. Another option would be to use an optimized device for TLS communication such as a hardware load balancer in standalone deployments or DLBs in Cloudhub.

Transport-level security Vs message-level security: 

When we use TLS messages are protected while they are in transit. This means that, as soon as our message leaves the transport channel, it will be in clear text. The protection in TLS is point-to-point.

So if I send my credentials from the web browser to a web server in HTTPS, my credentials are protected in the channel, but as soon as the web server gets my credentials they are in clear text. In that case, if the web server sends them to an Identity Provider to validate my credentials they might go in cleartext. That’s not acceptable in many scenarios.

However this comes at some cost. First of all, encryption happens at application level, which will affect considerably the performance. Immagine a transaction between mule apps where all messages need to be encrypted/decrypted by the mule runtime. 

Secondly, TLS is a standard, you can be sure that almost any device/system on the other side know TLS and support it. On the hand, message encryption is dependant on the application. We need to know and implement the encryption mechanism on both sides of the communication to make it work. This sometimes is less scalable and not compatible in all scenarios

Token Validity Period

In an OAuth context reducing the validity period of the access tokens will increase security. However, refresh tokens flows will increase considerably the traffic in your network and create bottlenecks/latency, as they happen much more often.

To avoid this from happening, even if we don’t know all the diff channels our transaction will go through, the solution is message-encryption. With message-level security the message is protected by itself and we don’t rely on the transport layer for security. 


The Weakest Link Rule

Any system is no stronger than its weakest link. We need to have a proper security design in all the communication links of our architecture. The weakest link is not always a system, an API or a communication channel. In many cases, the humans are the weakest link and sometimes we underestimate the damage it can create bad end-user habits or behaviours. That’s why most of social engineering attacks target humans. Thread modelling is one of the techniques to identify the weakest links
Previous Post Next Post