1

I'm building a backend for the mobile app with a public-facing HTTP API endpoint. Despite being publicly visible, this endpoint is only meant to be used by my app, i.e. I don't want people to send random requests to it using wget or anything similar.

My idea was to configure a SSL/TLS on my server, thus making the API only available over HTTPS and enforce a client certificate check on the server. Every copy of the app will have the (same) client certificate bundled with it.

Note that I'm not doing this for the purpose of a user authentication, just for limiting access from sources other than my app.

Is is a valid solution? It appeals to me a lot because of how simple it is. Are there any obvious flaws with it? How likely is that the certificate will be unbundled from the app and used for malicious purposes?

5

I don't want people to send random requests to it using wget or anything similar. [...] Every copy of the app will have the (same) client certificate bundled with it.

Ok, that's a bad idea. It won't work. Roughly summed up: if a secret value is copied into more than two places, then it no longer is a secret. In that case, if some people have any interest in "sending random requests using wget", then they just have to extract the certificate and private key from any copy of your application, which is a trivial bout of reverse engineering.

Think about it: if hiding a secret value in a widely copied application worked, then there would be no possible DVD ripping. Music editors would not wail and grind their teeth at the thought of software-based piracy. There would be no cheating in online games.

The usual catch-phrase used to describe this situation is: client-enforced security does not work.


Mind the context, though. Extracting a private key from a compiled application that uses that key is not hard; however, that does not mean that people will do it. Apathy is one of the strongest forces in the computer universe. Such reverse engineering will happen only if somebody, somewhere, becomes motivated enough to invest a couple hours of his time (at most) on that task. This may happen only if there is anything to gain in, indeed, "sending random requests with wget" to your server.

Many weak systems, even applications which try to enforce client-side security, fail to be attacked simply because nobody bothers to do it.

2

Your solution regarding authentication is fine, because it's based on mutual authentication.

In case you are using Apache it can be easily achieved (after setting up the CA and client key material) by adding the following lines to the configuration:

SSLVerifyClient require

In order to protect your key material on the mobile phone you need to take care of storing your keys and certificates in a secure way.

In iOS the keychain would be a appropriate location or similarly the keystore in Android.

If a key gets lost you can still put it on the revocation list (CRL).

2

Hold on! Remember that if you want to use client authenticated TLS you'll need to include the private key as well as the certificate. That means the app will include a hardcoded private key and certificate. So here are a couple risks you need to consider:

1) What happens if someone reverse engineers your app and extracts the hard coded private key?

2) What happens when the hard coded certificate expires?

Bottom line here is that anything hardcoded in source code is a bad idea.

It would be better if you added an enrolment element to your user registration code that will allow a new user to generate the required key material and certificates in partnership with your web site. The private key should be generated on the device and the certificate signed by your web site CA. You don't need to worry about trusted third parties because only your site needs to trust the CA and the client certificates.

You will also have to include mechanisms for revocation and re-issuance of new keys, because you will need to handle the lost/broken/stolen device scenarios.

  • Enrolment element for the user registration sounds like a way to go in case when client-based cert is used for authenticating the user. I'm going to, on the other hand, authenticate a device. The issue of someone stealing my app's private key is definitely real and I'm trying to understand the potential negative impact of it. BTW, how would enrolment work in your approach? It seems that the app would need to send a CSR to my API -- in this case an intruder can obtain this network information via sniffing and enrol with his own freshly-generated key, doesn't he? – Sergey Mikhanov Jul 20 '14 at 17:14
  • Sergey, The best method is to use a PKCS#10 CSR, which is self signed. Only the public key is sent for signing, so there is no risk to the protocol. Even if the attacker were to intercept the public key what is he going to do with it? The attacker needs the private key to do anything damaging and this is safely stored on the device and never leaves. If the attacker wants to enrol his own key then he is doing it through legitimate means. Remember its his own key through the valid registration API, so no longer an attacker, but a user. – NRCocker Jul 23 '14 at 4:54
2

This approach is weak as a security control and adds no authentication value. Other commentators are correct that a certificate embedded in an app is easily extracted by a malicious actor. HOWEVER, there is a secure way to do this.

Your goal of hiding the server API interface behind a TLS connection requiring mutual authentication in order to prevent it from being discoverable and potentially attackable across the network is sound and strongly recommended. Unfortunately, the overhead to do this properly is too great for use-cases that do not require strong security.

The client-side certificate must be issued per user. To do this, you have to have the appropriate PKI components facing the Internet or be contracted to a thrid-party who does. Your licensing and application installation must include a process for the user to register with the CA and receive a unique certificate which can then be stored by the app (using an OS encrypted certificate store or other secure means) and used for TLS authentication exactly as you had thought to use a cert distributed in the app.

Also, you may need to give thought to managing certificate revocation, which your web server would need to check as part of validating the cert prior to completing the TLS handshake. For example, if your customer is paying a monthly fee for service and you issue certs with a 1 year expiration, you should probably revoke the certs of customers who no longer receive your service, but who's certs have not expired.

Large enterprises are using certificates for this and similar purposes. They can stand-up CAs and the management for them fairly easily and justify the cost across many use cases including protecting Internet published services in exactly this way.

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.