views:

163

answers:

3

I'm building a solution consisting of an app and a server. Server provides some methods (json) and the app uses them. My aim is to make those API methods inaccessible to other clients. What is the best way to do so? Should I take a look at certificates (to sign every outgoing request)? If yes, where do I start and what is the performance impact of doing so? What are alternatives?

A: 

I will now freely admit that it's an interesting question, but I have no idea how it could be done.

Original answer:

Interesting question. Assuming people can't reverse-engineer the iPhone app, the only solution that comes to mind would be to sign requests with a public key, or some other secret known only to the application. By that, I mean adding an extra argument to every API call that is a hash of the destination URL and other arguments combined with a secret known only to your server and application.

To expand upon this: suppose your API call has arguments foo, bar and qux. I would add a signature argument, the value of which could be something as simple as sorting the other arguments by name, concatenating them with their values, adding a secret, and hashing the lot. Then on the server side, I would do the same thing (excepting the signature argument) and check that the hash matches the one we were given in the request.

Dave
"Assuming people can't reverse-engineer" but they can and it's fairly easy, especially if you have a jailbroken iPhone.
Ben S
In which case I take back my comments -- apart from it being an interesting problem.
Dave
A: 

Consider authenticated HTTP.

For a cheaper alternative, there's shared secret/hash scheme. The client and the server have a shared secret string of text. Upon request, the client hashes together (using MD5, or SHA1, or SHA something else - you choose) the request fields and the secret. The hash value is attached to the request - say, as another POST field.

The server does the same operation with the request and with its copy of the secret, then compares the hash values. If they don't match - service denied.

For added security, you may encrypt the hash with a RSA public key. The client has the public key, the server keeps the private key. The server decrypts the hash with the private key, then the same. I did that with a C++ WinMobile client and a PHP-based service - works like a charm. No experience with crypto on iPhone, though.

UPDATE: now that I think of it, if we assume that the attacker has complete control over the client (ahem jailbroken iPhone and a debugger), the problem, as formulated above, is not solvable in theory. After all, the attacker might use your bits to access the service. Reverse-engineer the executable, find the relevant functions and call them with desired data. Build some global state, if necessary. Alternatively, they can automate your UI, screen scraper style. Such is the sad state of affairs.

Seva Alekseyev
It would be pretty easy to find the secret string by dumping the string table of the app. Also, encrypting anything with the server's public key is useless since an invalid client could also do that.
Ben S
Right. I take back the "impervious to RevEng" thing. :(
Seva Alekseyev
+1  A: 

Put another way, you need a way to distinguish a valid client's request from an invalid client's request. That means the client needs to present credentials that demonstrate the request comes from a valid source.

SSL certificates are an excellent way to assert identity that can be validated. The validity of an SSL certificate can be confirmed if the certificate contains a valid signature created by another certificate known to be secure, a root cert. As noted in other answers an embedded certificate won't do the job because that certificate can be compromised by dissecting the app. Once it is compromised, you can't accept any requests presenting it, locking out all your users.

Instead of one embedded app cert, you need to issue a separate certificate to each valid user. To do that, you need to set up (or outsource to) a Certificate Authority and issue individual, signed certificates to valid clients. Some of these certificate will be compromised by the user -- either because they were hacked, careless or intentionally trying to defraud your service. You'll need to watch for these stolen certificates, place them on a certificate revocation list (CRL) and refuse service to these compromised certificates. Any web server is able to refuse a connection based on a CRL.

This doesn't solve the security issues, it just moves them out of the app. It is still possible for someone to create what appears to be a valid certificate through social engineering or by stealing your root certificate and manufacturing new signed certificates. (These are problems all PKI providers face.)

There will be a performance hit. How much of a hit depends on the number of requests from the app. The iPhone NSURLConnection class provides support for SSL client certificates and client certificates can be installed in the phone from an e-mail or authenticated web request. Managing the infrastructure to support the client certs will require more effort than coding it into the app.

Incidentally, voting down any answer you don't like creates a chilling effect in the community. You're not nearly as likely to get advice -- good or bad -- if you're going to take a whack at everyone's reputation score.

John Franklin
thanks for your answer. I'm wondering how other services work about this issue, because it seems to be a very common problem. To create individual certificates looks like a little bit complex option - this is not an enterprise app, it will be provided through appstore (in unforeseen amount of downloads of course...). But yes, it looks like interesting solution, thanks. BTW, I didn't vote down any answers - someone other did
Konstantin
John Franklin