开发者

How can a server authenticate an iPhone app (the code, not the user)?

Let's say I have a solution involving an iPhone app that generates some information and then sends that information to a web service for processing. It is importa开发者_JAVA百科nt that ONLY requests from instances of this particular iPhone app are allowed to be processed (there may be many instances of the app used by many different users, but I want to be sure they are all using code that I trust). In other words I want to be sure that my iPhone app cannot be (easily) impersonated by other clients. How would you do this?


All other answers give legitimate ways to provide some additional, but not perfect, security. You should know up front (since no one else has been so explicit) that it is not possible to provide theoretically secure communications such that your server can always validate that the client on the other end is a purchased copy of your application running on sanctioned hardware. You can't do this because whatever hardware level security Apple has built in to kick off a chain of trust (so that this may actually be possible for them), they don't expose to you.

Your strategy thus should be one of "many barriers", some larger, some smaller, designed to thwart varying degrees of complexity of attack and sophistication of attacker. See other answers to this question for some good ideas. How many barriers you need, and of what sophistication, depends entirely on the cost to you (economically, trust, whatever) of having an attack succeed.

Do consider also the idea that if you can avoid a "reproducible" security attack, you're better off. In other words, if someone breaks your app/protocol, and the data for other people to do that is the same for every copy/instance, then you're in more trouble, because the instructions/keys can be just posted to the web somewhere. If you can figure out a way to make every copy/client unique, then you can observe on the server and at worst, cut off known broken clients, etc. (This is hard on the iPhone platform.)


Another possibility is to ask the app for some portion of the contents of the application bundle - something like byte 59967 of the application executable, or an included plist or xib. By keeping both the file name and position asked for totally random, anyone spoofing has to embed an entire copy of your application - which makes it very easy to determine if they are spoofing your app, and possibly very easy to google for occurances.

You basically just would have the client give you a version number, and on the server you would have copies of all files for all public versions to check answers against (and to decide what challenge to send).

Since it's impossible to actually prevent this, the next best thing is to make detection of spoofing as easy to scan for as possible and so I'd think about solutions that help you n that regard rather than trying to block the unblockable (though some trivial initial blocking will keep out the riff-raff).

Basically, more layers rather than one really hard layer are what you want in securing something.


I asked a similar question a while back:

Restricting access to server to iPhone app

What I ended up doing is using a randomly-generated username (GUID). I then take the username, append a secret (hard-coded in my app, mirrored on the server), and SHA1 the result, and send that as the password.

On the server I take the username given, append the same secret, hash it, and compare it to what the client sent. Note that this needs to be sent over SSL to be even remotely secure.

Another approach would be to ship an SSL client certificate with your app bundle and configure your server to only accept connections from clients with that certificate.

The weakness with both of these is that if your app is cracked, it's trivial to extract the secret or the client cert.

If your concern is un-paid-for clients using up your server resources, you have an entirely different problem, because then your main threat model is bootleg copies of your app running on jailbroken phones. See the answers to my question for some countermeasures.


Any outgoing communication generated by your application can be intercepted and replayed later. If you wanted to be reasonably sure that a request is coming from your application, you can do things like embed public (not private) keys in your application and use it to sign your communication. However, in a situation like this, private and public keys don't do anything except provide non-repudiation (ie, prove that only the intended recipient can read the message, because they're the only one with the matching half of the keypair).

What you're looking for is providing authenticity. You could do something like perform a DH key exchange ( http://en.wikipedia.org/wiki/Diffie-Hellman_key_exchange ) to generate a shared secret (since by hard coding a secret in your app does not ensure it's a secret), then using that secret to perform a specific manipulation on your message (although this still isn't perfect authenticity).

Or you could do something like inspect your app's code signature and verify that it's an appropriate signature and that it's your app, or something similar.

Perhaps Graham Lee will pop up and give a better answer. :)

EDIT

(thinking aloud) Here's an idea: Once your app is on the store, you could extract the code signature of the publish app, put that on your server, and use that in a challenge-response. When your client connects to the server, your server could generate a random value and send it back. The client could manipulate that value using the app's built-in code signature, and return the manipulated value. Meanwhile, your server could be doing the same thing. When the server gets the manipulated value, it could compare it with its version and then terminate/continue the connection based on whether they match. Technically, this could still be spoofed (another app could steal the code signature and use it itself), but it seems like it'd be more secure.


You could hide a private key in your app that is used for a challenge-response authentication.

If this answer is too short/abstract, leave a comment and I'll explain in more detail.

Edit:

I’d like to add that I don’t think there’s a secure (as in reverse-engeneering-safe) way to do the described authentication. But in security things I’m finding myself wrong more often than never.


When the app starts up, send a token request to the server. Then have the server send a token (just some secret, newly-generated string) to the client through APNS. All subsequent communication authenticates with that token. You can even persist the token 'securely' using the Keychain iPhone-side. In the limit what you want is, indeed, impossible, but this way you rely on Apple's tools a little more.


Use your Device Id... Send Device Id with the request... each iphone will have unique Device ID

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜