Search code examples
restauthenticationauthorizationapi-key

Rest API: client authorization and end user authentication


I'm developing a web service (PHP) for a mobile application (Cordova), the web service provides some REST APIs.

The current scenario: the API itself, doesn't have authentication, anyone with endpoints can make requests, but at the application layer all actions require an authenticated user (the user logs in and receives a JWT), which already is implemented.

Issue: I want to protect the REST API for only authorized clients to use (API KEY?).

  1. Should I implement something like: public key and a secret (hmac)?

  2. I'm on the wrong way, I should use something like oauth (* It's a private API *).


Solution

  • It sounds like you want to authenticate the Cordova application binary in addition to the user to ensure REST API requests made to the PHP server originate from legitimate sources and not, for example, a rogue app or script which could ultimately scrape the backend data through a reverse-engineered API.

    The OAuth/OpenID flow is typically used to authenticate users, not software such as mobile apps, and it's important to remember that genuine authenticated users can still exploit REST APIs with fake software.

    You have two options:

    1. Roll your own
    2. Buy an off-the-shell solution

    Using an HMAC to sign the API requests from the mobile application is certainly a good idea, but recall an HMAC function takes a secret and message as parameters and the secret must eventually be in single form in memory (even if originally obfuscated) and could be extracted from the mobile app if using a built-in system version of HMAC which cannot be obfuscated.

    I would strongly suggest against embedding secrets in mobile apps - once the apps are publicly available on the various stores, the secrets and the APIs the mobile apps use are available through the process of reverse engineering.

    If you decide to use an HMAC request-signing approach in your app, then you should definitely implement:

    1. debug detection
    2. root/jailbreak detection
    3. instrumentation framework detection (such as Frida), and
    4. Man-in-the-Middle network proxying detection

    in parallel, encoded in the message to allow the REST API to be informed so it can make decisions to protect itself. Also, perform any of these in native code - not in Cordova Javascript code as that layer and the JS/native bridging layer introduces a weak point in the mobile app.

    You mentioned a "public key", but in asymmetric cryptography (such as RSA) that key is typically used for encryption and verification operations. The private key is used for decryption and signing operations so it is the private key you would require in the app. I would never embed this ahead of time.

    You could also include the app's developer signing authority in the HMAC message could help protect against repackaged versions signed by someone else.

    An alternative approach to in-band HMAC API request signing is to use an out-of-band tokenized approach which uses JWTs to express the validity of the mobile app. You can perform the mobile app validity test periodically on a remote software authentication server provide a JWT to the mobile app which can be included on every REST API request. For example, this is something Approov does.

    It's also vitally important not to confuse app hardening (obfuscation, string encryption, etc) with REST API protection: in the former case, you see the value in the mobile app; in the latter case, you see the value in the data behind the REST API.

    This is a difficult problem to solve effectively unless you have sufficient resources so I would suggest using a solution where someone else has solved these problems so you can focus your efforts on app features, user experience and time-to-market.

    Whatever you decide, +1 for being proactive about security, I hope this is helpful, and good luck with the project!