0

I am planning to create an internal API for mobile devices for a company.

They are planning to use this internal mobile app to get data from custom ERP, uploading contract, etc. Thus, it will be sending sensitive data. The user of this API is limited to their small number of employee, around 20+

Unfortunately, VPN is not a solution on this case. So, the API will have a public facing IP.

As an initial solution, I was thinking to create a REST API based on Node JS and place them in an public facing instance of AWS EC2.

To restrict the access to this internal API, I will try to whitelist the IP address range of their telco company and embed client certificate uniquely for each user on their mobile devices.

Also, I will implement authentication apart from client certificate, HTTPS, certificate pinning, HMAC based on device identity (IMEI, UUID), timestamp.

Is this approach (client-certificate) is less secure than VPN? Is using Client Certificate authentication makes the backend safer to attack? (Let's assume that the certificate is never exported from the device)

Is there any chance that if I'm using AWS EC2, I could incorporate any other services in AWS that could secure this API and restrict them only to certain user?

Is there any safer way to secure this approach?

Is there any best practices to secure an internal API for mobile devices? Nowadays, mobile app is pretty useful for mobile worker. I was wondering how big companies overcome this problem to secure their mobile API?

Thank you. I would be grateful if someone could help me on giving suggestions.

3
  • Is the sensitive data covered by any sort of law or regulation?
    – Daisetsu
    Apr 24, 2016 at 2:14
  • Fortunately no, but this data is confidential to this company.
    – Sylvester
    Apr 24, 2016 at 12:07
  • HTTPS with client certificates is all you need to be honest. Device IMEI and UUID should be considered public info just like an user-agent, so IMO it's not worth it to authenticate using that. Jul 31, 2016 at 14:00

2 Answers 2

1

There's nothing inherently wrong with using what you've described. With certificate pinning, and strong user authentication you're going to be on par with most normal TLS web traffic.

Ensure that you're restricting communication in your certificates to only secure ciphers, setting a reasonable expiration date, and distributing the certificates in a secure out of band manner (don't just email the certs to the device).

Lastly the one pitfall I could see is the manner in which you do certificate pinning. There's two approaches to 'certificate pinning'. You could pin the entire certificate, and fail the connectin if that differes, or you could check that the keys used in the certificate stay the same.

While it will take more effort to check the keys, I suggest you go that route. It allows you to update the certificate server side, and have the client still accept it assuming your key doesn't change. This provides the security of expiring certificates whenever you want, but still maintaining pinning.

I would caution you about using AWS for sensitive data. While your data isn't subject to regulatory restrictions, you still should consider the location of your data, what laws it could be subject to. How well does Amazon AWS scub their drives after use? What SLA does AWS provide? I haven't used AWS personally, I'm just echoing what I've heard from others at this point.

3
  • Thank you so much for your comments. Ok, I will try to learn more about storing data in AWS :)
    – Sylvester
    Apr 24, 2016 at 20:43
  • If you liked my answer, you can upvote it. Thanks.
    – Daisetsu
    Apr 24, 2016 at 20:49
  • For system->system calls, if the client system doesn't change (i.e. not a web browser or actively changing clientbase), you don't even need "real" certificates -- a strong self signed certificate is good enough, and because you distribute it to your client systems, they all know the source is valid without a 3rd party signature. Jul 31, 2016 at 13:39
0

Adding to the high-level look at good API design that @Daisetsu provided, the best way to actually secure a web-based REST API boils down to two choices:

1 Send everything over HTTPS. Allow the user to auth with the API to get a session key, and just include that in every future Query.

GOOD: Everything is secure.

BAD: Cost of negotiating the HTTPS connection takes more server resources (not an issue unless you have a heavy-use API) and the turn-around time on a call will be longer.

2 Utilize an HMAC (signature) and send it along with every request.

2 is what a lot of the Amazon Web Services APIs use and the most popular method for implementing the approach is typically referred to as "2-legged OAuth".

2 can look confusing/random/insanely complex given your comfort level with security so I'll outline the gist of how it works:

  • The SERVER and CLIENT share 2 values: a public and private key.
  • The public key can be known by more people, that's fine.
  • The private key CANNOT. It must only be known by the server and the client.
  • When the client makes a request to the server, it sends along 2 important things: the public key and an HMAC (aka a "signature") The signature represents a hash of the parameters included in the request: /search.json?public_key=123456&term=shritam&range=180days&sig=dKdjalkjDKd97daskdDKl2
  • The hash is calculated by combining all the parameters that make up the query into a string, then running the string and the secret key through a hashing algorithm like MD5, SHA-1, SHA-256, etc.
  • The server receives the request and before doing anything else, using the public key given in the request, it looks up the user's secret key.
  • Then the server re-combines all the request parameters in EXACTLY THE SAME MANNER the client did it, and hashes them with the secret key it just pulled from the database for that user.
  • If the hashes match, the request is executed. If the hashes do not match, the request is denied.

Given how pedantic and finicky the nature of generating a hash is (if the input is 1 character different, like an extra space, the resulting hash is different) there have to be REALLY specific rules on how the parameters are combined, how they are encoded, how they are hashed with the secret key and so on.

Thankfully the OAuth 1.0 spec (Sections 3.4.1 through 3.4.2) do exactly that; they lay out exactly the process both server and client need to follow when generating that hash, so any OAuth-compliant client or server can communicate with one another more effectively.

Side-note: OAuth 2.0 is out, grab that!

Regardless of if you use OAuth or not, you just have to make sure your clients and server all agree on HOW the string is created and signed. Amazon Web Services uses a slightly different method to generate the string to sign by inserting newlines where as OAuth just concatenates everything together.

I have seen some APIs online that generate the HMAC by having the person hash their public key with their secret key and send that along; in that case you are essentially turning the HMAC into a session ID and risk the same side-jacking problems that sessions-over-unsecured-APIs suffer from.

Keep in mind that any parameter you include in the HMAC generation cannot be changed by a man-in-the-middle intercepting and re-submitting your query.

Any parameter that IS NOT part of the HMAC calculation, can be changed by a man-in-the-middle and resubmitted because it is not part of the signature, so when the server goes to recalculate the HMAC it won't see the mis-matched hashes caused by the change.

These are the highlights of securing an HTTP-based (not HTTPS) REST API.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .