If you’ve paid notice to the OWASP API Security Top-10, you have noticed that the 2023 version has been changed markedly. Granted, some changes are a bit semantic reshuffling, but the new entry at number 10 is anything but superficial. It’s titled “Unsafe Consumption of API’s”. You will be forgiven if this doesn’t immediately ring a bell, let alone sound an alarm. Yet it is a rising threat. It is a bit different in nature from the other threats. But I have an easy fix for you. Let me explain.
Understanding Unsafe API Consumption
What is unsafe API consumption? Businesses are increasingly consuming software systems as a service in the cloud. APIs are most definitely a very convenient way to link those cloud systems up with each other, and with remaining on-premises systems. There’s hardly any assembly required. Lovely. But are you sufficiently aware that there is an actual threat in blindly processing API responses? A threat similar to the unsafe providing of APIs?
Why Iit’s a growing threat? As a consumer of cloud services, you expect these systems to be reliable. A professional company manages them, and they likely have more expertise in securely hosting their systems than you would in an on-premises scenario. Right? Well, mostly right. You’re assuming that your providers can never fall victim to an insider threat, a malicious intrusion, or simply an erroneous update. And you’re assuming there’s no one in-between who’s messing up your messages. Yet, supply chain attacks are real.
The Importance of Trust and Verification
The Role of Zero Trust Security
There is a reason why zero trust security has become a big thing. Are you really sure that you are connected to your supplier? Are you really sure that there’s no man-in-the-middle? You would certainly not be the first to fall in a common trap. And even when you have set-up a VPN, or a Mutually Authenticated TLS connection, you could still be maliciously redirected to a third party, if you don’t take care.
Potential Risks in API Consumption
Your provider might suffer from an insider attack, or even a supply-chain attack, messing with the responses on your API calls. That’s a known way to inject false redirects, or malware, or exploding zip-files, or some random gobbledygook designed to bring your client system down. Unfortunately, it does happen, otherwise it wouldn’t have made the OWASP Top-10.
Unsafe consumption of APIs is in essence a lack of response validation. Fortunately, there’s a straightforward strategy to counter it.
How to protect against unsafe API Consumption?
As a consumer of an API, you don’t own the Open API Specification. It is provided to you by the API Owner. Moreover, its lifecycle is managed by the owner too. A responsible API owner should provide a rich specification of their API, designed to prevent misuse. After all, an Open API Specification acts as the contract between the API Provider and the API Client. A poor contract is a breeding ground for misinterpretations and conflicts. So, investing in a clear, well-written contract is an investment in a healthy relationship with your clients.
Remember, the Open API Specification formalizes the semantics of the contract, allowing for automated enforcement. It assumes a process of detailing your contract to a level that every API invocation can be validated meaningfully against it. I call it ‘API Hardening’. It takes the brittleness out of the integrations.
Unfortunately, for whatever reason, not every API Owner does provide a well-defined contract. But, this should not keep you from hardening the API Specification you are using. Especially, the definition of the information you allow to flow into your systems should be of interest.
How to get your shield up?
Using Tools for API Security Audits
You take the API Specification as provided. Let’s take the SCIMv2 API as an example. SCIM, System for Cross-domain Identity Management, is an industry standard API for user provisioning. It is widely implemented in Identity Management Systems, HR Systems and CRM Systems, for instance.
I quite randomly took the SCIM2 yaml file from gravity.io and loaded into my VS Code IDE. My first step, as always, is scanning it with the 42Crunch Audit Scanner. Turns out the API specification claims it is a swagger: ‘2.0’ file, but fails to comply to the standard. That’s bad, but unfortunately not all that uncommon. In this case, the oauth2 grant type ‘client-credentials’ is an issue. Changing it to ‘password’ satisfies at least the audit scanner. But for internal purposes, you might consider changing the security scheme into APIkey instead.
Additionally, there was a typo in a keyword to correct: Sloppy! And incidentally blocking my Scanner from doing its magic.
After these fixes, our trusted 42Crunch Audit Scanner quickly revealed ample room for improvement. A measly audit score of 10/100. Time to go to work!
Example: Improving SCIMv2 API Specifications
As you probably know, the Open API Specification has adopted JSON Schema for defining the message payloads – both outgoing requests and incoming responses. Obviously, we are going to focus on the incoming responses. In fact, there are two different types of JSON objects to consider: valid responses and error responses. Let’s use the GET /Groups as an example.
It turns out that the supplied definition allows for much more than you would wish for. However, there is valuable information hidden in the comments within the swagger file. If you dive in the actual API Specification, and look at the object descriptions, you’l find useful hints such as “description: REQUIRED”, or “description: Non-negative integer”. The sad thing is that such informative comments have no formal specification, so you cannot enforce them automatically. But, fortunately, JSON Schema has the semantics to cover our needs. In fact, it’s quite basic. Entering a “minimum: 1” to the specification makes the integer non-negative by definition. Similarly, adding the ‘required’ keyword to the object type will enable you to better validate a response automatically. Like this:
Group: {
type: object
required: [schemas, totalResults, Resources],
properties: …
There are more simple schema improvements to consider, e.g. adding a RegEx pattern for strings, a format specification for a valid URI specifying a namespace of the SCIM schemas,
schemas :
type: string,
format: uri,
maxLength: 1024
}
or an enumeration array of valid values,
enum: [book, movie, video, blog, podcast, webinar],
or anything that adds to your defensive shield.
When you’re satisfied with specifying the data you’re willing to accept, there’s one more thing to take care off. And that’s the enforcement part. By placing a 42Crunch WebAPI Firewall in-between your client and the remote service, with your improved specification of the API, you can be certain that no data that violates your API definition will get passed. Moreover, it takes your API Specification as an allowlist, meaning that only pre-specified elements are allowed to pass the firewall. So, even without the “unevaluatedProperties: false” directive, undefined properties –although technically permitted in the standard– will get blocked.
Similarly, as long as there is no http:301 (Moved Permanently) or http:308 (Permanent Redirect) response declared in your API Contract, your API Firewall will simply drop such a response. Should such a redirect ever occur, a potentially malicious redirect is effectively neutralized. You’re in charge of the responses you’re willing to accept, and using the 42Crunch API Firewall, you’re back in control. Zero unsafe consumption of APIs on your watch. That’s what defensive API Consumption is all about.
Is there a downside?
I can almost hear you objecting.
“But, but, every time my supplier has a change to their JSON Schema, I’d have to update my API Specification, and my clients would have to migrate to the new version too. Wouldn’t that be unnecessarily cumbersome?”
Well, I firmly believe that it is actually a good thing to update your API specification if you have changed its implementation or its contract. It gives consumers the opportunity to analyze the impact of the change, and only adopt the new version once they’re ready for it. You don’t ever want to break your clients, do you?
However, in this particular case, you run the client. Nevertheless, you control your own API specification. In fact, I’ve given you a tool to prevent you from getting severely broken. Who knows how your client behaves with undefined responses? You simply can’t test for everything that might happen. Remember Hyrum’s law? Staying on the safe side rather than blindly accepting changes will help you sleep better at night.
Of course, in case of an emergency change, you should have a process in place to quickly update your API Firewall. Perhaps even temporarily put your firewall in listening mode, once you’re sure the change is valid. You might also trigger an alert as soon as an API response gets rejected by the firewall. After all, it’s a security event you want to follow-up on. But that’s a small price to pay for avoiding unsafe consumption of APIs.
If you want to know more about 42Crunch, and what it can do to protect your APIs, you’ve come at the right place. We’d love to share our experience. Why not contact us right away?