# How can I set my server to only accept requests from my own client app? (similar to SSL Client Certificates)

I'd like to have my server APIs only accept requests from my own app, to prevent other "rogue" clients of my service.

As i understand it, the way to do this would be with a "client certificate" that the app sends, and that the web server is configured to verify.

However, I'm hosting my app in Heroku, and I believe it's not possible to do that, so I'm looking for something as good as possible that would allow me to achieve this.

I thought that maybe I could have a key pair, where the client uses a private key to sign a certain agreed-upon token (plus some random salt, so that the encrypted string is always different), and the server uses the public key to verify the token (and rejects duplicate salts to prevent replay). Or maybe the client signs the whole request with its private key, or something like that.

The idea would be that even if someone manages to get around our SSL pinning (with something like iOS kill switch, potentially) and inspect our traffic and figure out how our API works, they still can't call us unless they reverse engineer the binary to extract that certificate / private key. I understand that it's possible to do that, I'm just trying to put up as many barriers as possible.

What are good ways of doing this?

Thanks!
Daniel

• If you can't use SSL client certs then do some additional crypto on top of SSL. – user42178 Feb 17 '15 at 13:03
• You can build a ssl-like process. But you shouldn't encrypt all data with asymmetric encryption because its slow. Hardcode servers public key to your app, create a random crypto string and after encrypting it with servers public key, send it to server. On the serverside you can decrypt the key that your client sent and start encrypting the data with this key since both client and server know it. But use SSL even you have your own encryption layer – Batuhan Feb 17 '15 at 13:25
• SSL was deprecated over a decade ago, I sure hope you aren't using SSL. TLSv1 or later is the only acceptable secure transport layer. – rook Feb 17 '15 at 14:46
• @Rook I'm probably using TLS. Whatever's "the default"? I bought a certificate and gave it to Heroku. Sorry, but I'm a n00b at the details of this. – Daniel Magliola Feb 18 '15 at 14:13

This type of problem lends itself to Cargo-Cult Security type "solutions".

In the real world there is no possible mechanism that can prevent a rogue client from connecting to your service. A VPN is a proven security system that allows trusted clients access to a trusted network, but the internet is inherently untrustworthy. The attacker will have access to any secret embedded in your app, or stored in app memory, TLS client certificates rely upon a secret.

When designing a web service never forget: "The client is the attacker, and can never be trusted." If you have made this mistake, then you need to go back to the drawing board.

• I understand this, but my intention is to make it as hard / annoying as possible to raise the "minimum motivation level" needed to actually do this. My server is secure and you can't do anything nasty to it from the outside (that I know of), but I still don't want people making their own clients. So far, if I don't check anything on the server, you don't need to touch the app binary to extract any secrets. Forcing an attacker to do so is one more hurdle, one more hoop, that will hopefully dissuade them. – Daniel Magliola Feb 18 '15 at 10:06
• @Daniel Magliola The only one you are fooling with cargo-cult security is yourself. – rook Feb 18 '15 at 13:44
• @DanielMagliola that's DRM, and will always eventually fail – Natanael Mar 20 '15 at 14:34
• DRM and code obfuscation will indeed never stop a motivated attacker, but if his objective is just to make it more annoying to create a custom client, it nevertheless is the valid approach. – Dillinur Apr 30 '15 at 12:27

Note

This answer is only applicable under the stated assumptions. I have made them based upon the explicit wording of the question, which explicitly allows for a known attack vector to not be mitigated.

Security is a relative balance between the value of loss should an asset be compromised, and the effort (incl. cost etc.) that an adversary is willing to make to achieve such compromise. It is the author's prerogative to decide upon such a balance as they have the full picture regarding stakeholders.

Assumptions

The threat you are attempting to mitigate is one of an adversary who can read / tamper with their own communications, impersonate the client, but not reverse engineer the contents of the binary (either due to a lack of technical capability, or a lack of willingness).

TL;DR

HMAC(message | nonce, key) along with the client message / nonce "in the clear" (over TLS, but without any further encryption).

Your question is one of authentication, but you appear to be attempting to solve it with encryption (yes there is some crossover in certain circumstances, but separating the two will make the answer easier).

If a secret key (not an asymmetric private key; just a sufficiently large, cryptographically secure, random number) is stored in the binary (as you were proposing with a public/private key-pair) then it is not revealed by knowledge of the HMAC/plaintext pair.

Your server is also knowledgeable of the key, computes the HMAC for the message received, and discards any client communications that are invalid. The nonce is provided by the server to the client before it sends the message, and is unique. It acts to protect against replays of intercepted messages.

Caveat

As noted earlier and in other answers / comments, one may still obtain the key from the binary. For those who are interested there is a really cool technique that calculates the entropy for all regions of the binary, and then maps the linear position to a Hilbert curve. Machine code regions will have a relatively lower entropy than 'key' regions. Chris Domas demonstrates this in one of his videos; possibly his TED talk although I can't remember (watch the TED video either way).

• again, that merely moves the client secret around - a malicious user would still be able to find it and use it for his own bogus app. – AviD Apr 30 '15 at 17:46
• I agree. However, as I stated in the paragraph regarding assumptions, this is a risk that the author is explicitly willing to take. Security is a relative balance between the value of loss should an asset be compromised, and the effort (incl. cost etc.) that an adversary is willing to make to achieve such compromise. It is the author's prerogative to make such a balance as they have the full picture regarding stakeholders. I will update my answer accordingly. – Arran Schlosberg Apr 30 '15 at 22:07

You can go with any of the tunneling mechanism to accept the particular IP's in the server side or else simply configure your firewall to accept the list of trusted clients.

• Unfortunately, my client is a mobile app, so I can't whitelist IPs... Any other ideas? – Daniel Magliola Feb 18 '15 at 10:02
• In case you can try for google oAuth mechanism or OTP to client as banks doing. – user45475 Feb 18 '15 at 20:27

Use OAuth2.0 . It not only authorize the user, but also client application with client_id and client_key properties.

• What does prevent an application from spoofing those attributes? – Dillinur Apr 30 '15 at 12:28
• I am not sure but maybe you can store them into local db in the client app with encryption in development time. In run time, the app gets the data an sends to server in oauth post body. In the server side you can know from which server does the request come from..According to the credentials, you can send token to client.. And if you use ssl, then no network sniffer catch it. – yeulucay May 8 '15 at 8:46
• "store them into local db in the client app" - Then I just copy the local db from the client app to my clone app. "with encryption in development time" - if your app can decrypt the data, so can my clone app. Whatever information I need to do that can be extracted from your app. If your app can not decrypt the data, then my app doesn't need to be able to do that either. – Philipp Jul 26 at 8:29