We have a mobile app for iOS and Android available in the Apple and Google Play stores. The app communicates with our server’s Web Services over HTTPS.
We have attackers able to spoof the app traffic. This probably means our attackers are decrypting and monitoring the HTTPS-encrypted Web Services request/response with a tool such as Fiddler.
Our next step is to encrypt inside the mobile app. We encrypt the Web Service payload in both directions using AES in CBC mode with HMAC. This means both our server and the downloadable mobile app have a shared secret key (actually, at least two).
The problem is that it’s quite possible to reverse-engineer iOS or Android mobile apps and harvest any secret keys. To be sure, we have a higher level of security. It takes more expertise to reverse-engineer a mobile app than it takes to observe HTTPS traffic via Fiddler.
We may not be a big enough target for anyone to bother with harvesting our secret keys. But we’d like to grow to the point where the attack is worthwhile!
Any key-exchange protocol that I’m aware of requires the mobile app to have a secret key somewhere in the process. With the app available as a free download from Apple App Store and Google Play, I simply have no way to ensure its secret remains secret.
Arxan.com claims to provide an Enterprise-grade solution which appears to be a sufficiently-complex process of hiding the keys from would-be attackers. I’m not yet ready to ask them about pricing!
Looked at one way, my question is, “How do I protect a secret key in a mobile app in the wild?” I have seen two clear answers:
- You can’t.
- Use HTTPS. However, we do this and it’s clear to us that our traffic is still being monitored.
So, I think my question becomes one of Authentication as opposed to Authorization: On the server side, how do I distinguish between an attacker pretending to be our mobile app, and legitimate traffic from our app?
Assuming that we are encrypting and correctly using HMAC, a valid message tells us:
- The message has not been altered.
- The sender is in possession of our shared secret key(s).
Everything to this point depends on the secret key not being compromised.
The only answer I’ve thought of so far is traffic analysis. We detect brute-force attack traffic and certain other traffic profiles. We detect various forms of replay attack.
We could thus infer that our secret key HAS been compromised, if it ever is, and invalidate the key (thus invalidating all mobile installs in the wild). But it stands to reason that if an attacker can figure out one secret key, that attacker can figure out the next key as well. Nor do we want to invalidate our entire legitimate installed-app user base!
We can install a certificate inside our app, but does that solve the problem? And if so, how? Don’t we have the same issue of the app being reverse-engineered and spoofed?
EDIT: What are we trying to protect?
Our attacker can run a password list against us by spoofing our app's User Login web sequence. Since our attacker is able to observe HTTPS traffic as it exits the app, our attacker knows how to construct the web service request and authentication.
We can encrypt the login (and other) information before it leaves the app. This should prevent both sniffing and spoofing, assuming our attacker does not possess the secret keys used in the encryption.
Given that inbound (to the server) traffic is more important to protect, Public Key encryption would be a possibility. Only the server could decrypt it. However, since the key is public, our attacker could still run a password list pretending to be the app.
So what are we trying to protect? We're trying to protect ourselves from an attacker breaking into user accounts via our web services. Specifically, how might we protect ourselves from an attacker sufficiently motivated to reverse-engineer our mobile app in the wild?
SECOND EDIT: Let's try restating the problem.
How might we design a robust and secure Web Services API? It must be able to withstand observation by a would-be attacker. We must be able to distinguish and reject spurious messages from a would-be attacker.
Specifically, we want to:
Prevent our attacker from using our Web Services API to run a password list and potentially log in to a member account. We have other brute-force detection measures in place, but we'd like to directly secure our API from such attack.
Prevent our attacker from using our Web Services API to probe our server for other attack possibilities.