0

I'm working in a scenario where I have a backend (let's call it the server) and a frontend client app (let's call it the client).

The client is entirely headless, and can connect to any instance of the backend installed on a server (supply the URL).

Over time, we can expect the backend to grow and branch into new API versions. We cannot assume the client will maintain parity with the backend, so the client may connect to an instance of the backend with an API version that it cannot support.

The client needs to know the API version of the connected backend so it can take action/adjust its functionality accordingly.

My question is: How can the client securely know the API version of the backend?

The glaringly obvious answer is: The backend advertises its API version in a header.

This, however, is uncomfortable for a variety of reasons --- as a rule, advertising software versions to all and sundry is a bad idea.

Only the client application needs to know the API version.

One approach is to implement an API key system, where the backend can issue keys which should be supplied by the client to unlock sensitive API endpoints.

However, the scenario I'm working with is user-facing – one instance of the client, supporting many API versions, may be used to connect to many instances of the backend.

The specific scenario is a headless CMS, with a management app that needs to support remote installs of the backend with an initially unknown API version. The login screen currently has fields for server URL, username and password, and adding a fourth for "API Key" becomes a bit cumbersome.

So is there another approach I've failed to hit upon yet? The API Key seems to be the most feasible so far, but I don't necessarily want end users to supply keys upon login.

  • 3
    Why isn't the title of your question "How can the client securely know the API version of the backend?"? The current title seems to ask a different question. – Dan Pichelman Sep 26 '18 at 16:17
  • @DanPichelman good point, I've updated it. Was struggling to succinctly describe the true issue (probably because I was still trying to interpret it myself when writing the question). – Ilmiont Sep 28 '18 at 10:17
3

one instance of the client, supporting many API versions

In my opinion, the issue is that your client does not support a single version of the API that it requests with every call.

Look at some popular APIs and you'll see that they support a version parameter specified in the query string or in a header, for example:

?api-version={version}

Accept: application/vnd.github.v3+json

The client should be built to work with only one version and ask for that version when it uses the API, as opposed to being some Swiss army tool that can handle multiple versions.

When the client's version is no longer supported on the back-end, then it's time to upgrade the client.

| improve this answer | |
2

Forget the "API key" as you've described it.

If you bury a secret in client side code, I can usually press F12 and find it.

An important rule to remember is that any computer outside your complete control is by definition insecure. This means that all client side software (e.g., all JavaScript) is at risk for reverse engineering, disassembly, etc.

If you have a web server, there's no way to guarantee that the code on the other end of the connection came from you or not.

However, all is not lost. Since your users already have to log into the backend boxes, you can securely implement a GetVersion() function that does not advertise to all and sundry. It's only available to people and code that have already authenticated themselves using a userid/password.

| improve this answer | |
0

My question is: How can the client securely know the API version of the backend?

As already mentioned by @Dan Pichelman a web App is easy to reverse engineer, but from your question is not clear to me if your API is serving a Web App, a Mobile App or both.

In the case a Mobile App is being used as the client it will not be so trivial as using F12 in the Web App, but tools like Xposed will make possible to reverse engineer it.

So a bullet proof solution is not possible, but for Mobile Apps you can make it more secure and difficult to reverse engineer by using some Mobile API Techniques to secure the API Key and other improvements to strength the security of your API when serving a Mobile App, like:

  • Certificate Pinning to protect the communication channel between the Mobile App and the API.
  • HMAC of signed/encrypted messages.
  • Signed JWT Tokens with encrypted content.
  • OAUTH2 as a more secure alternative for authenticate your users.
  • Mobile App Attestation services.

So is there another approach I've failed to hit upon yet?

The best approach in my opinion is to not have a client that supports several Api versions, but instead to have a client that is agnostic of the back-end API version and an API back-end that is agnostic of the client using it.

How can I achieve this, may be the question in your mind now?

For me I would go with GraphpQL to achieve it. Just put a GraphQL server sitting between your existing API and your client, thus any burden of dealing with API changes will go into the GraphQL server, not into your App.

If you have not designed yet your traditional API you may go only with using GraphQL to expose your data to the clients.

A good and recent article that walks you through GraphQL may be this one, where you can see a comparison between traditional use of REST APIs and a GraphQL API. Around the start of the second third of the page you have a section about "Wrapping a REST API with GraphQL in 3 simple steps" that may help you to better understand how to use GraphQL compared with a traditional API.

JWT Token

Token Based Authentication

JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties.

Certificate Pinning

Pinning is the process of associating a host with their expected X509 certificate or public key. Once a certificate or public key is known or seen for a host, the certificate or public key is associated or 'pinned' to the host. If more than one certificate or public key is acceptable, then the program holds a pinset (taking from Jon Larimer and Kenny Root Google I/O talk). In this case, the advertised identity must match one of the elements in the pinset.

OAUTH2

The OAuth 2.0 authorization framework enables a third-party application to obtain limited access to an HTTP service, either on behalf of a resource owner by orchestrating an approval interaction between the resource owner and the HTTP service, or by allowing the third-party application to obtain access on its own behalf. This specification replaces and obsoletes the OAuth 1.0 protocol described in RFC 5849.

GraphQL

GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data. GraphQL provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools.

HMAC

Hash-based message authentication codes (or HMACs) are a tool for calculating message authentication codes using a cryptographic hash function coupled with a secret key. You can use an HMAC to verify both the integrity and authenticity of a message.

Disclaimer: I do not work or have any relation with Prisma, but I work at Approov.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.