There is no absolute way to achieve this goal. If you have a web service that uses a shared credential (one bundled in the application), then it will be possible to reverse engineer that credential. Ultimately it is impossible to ensure that a client running on another machine is "your" client.
There have been many discussions of this. It is not hopeless, only impossible to solve 100% (or even 90%). A simple shared secret over SSL will stop the majority of your attackers without harming your users or costing a lot to develop. It is obfuscation, not security, but cheap and "mostly effective" is much better than expensive and "mostly effective."
If you have a very high-value product, then it may warrant more aggressive (expensive) solutions. All of these solutions include one of two things:
- Authenticating the user rather than the program, or
- Continual vigilance, watching for new attacks and responding with fixes that patch them.
The latter is very expensive and never ends. Make sure it's worth it.
Some other useful discussions:
EDIT I wanted to point out one thing about my mention of "shared secret over SSL." Remember that if you don't verify the certificate, you are subject to very easy man-in-the-middle attacks. Readily available proxies like Charles can do this. The best approach is to make sure that the SSL certificate being returned is signed by your root certificate, not just "any trusted certificate." You can reconfigure which certificates are trusted by your application with SecTrustSetAnchorCertificates()
. iOS5:PTL covers this technique in Chapter 11 (page 221). I've also wrapped this into a library called RNPinnedCertValidator.
Another good layer is to implement a challenge-response system where the server authenticates that the client has the shared secret without ever putting it on the wire. The Wikipedia article on Challenge-resonse authentication includes a good explanation of the algorithm.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…