11

I am developing an iPhone app together with web services. The iPhone app will use GET or POST to retrieve data from the web services such as http://www.myserver.com/api/top10songs.json to get data for top ten songs for example.

There is no user account and password for the iPhone app. What is the best practice to ensure that only my iPhone app have access to the web API http://www.myserver.com/api/top10songs.json? iPhone SDK's UIDevice uniqueueIdentifier is not sufficient as anyone can fake the device id as parameter making the API call using wget, curl or web browsers.

The web services API will not be published. The data of the web services is not secret and private, I just want to prevent abuse as there are also API to write some data to the server such as usage log.

Gaius Parx
  • 1,065
  • 1
  • 11
  • 18

8 Answers8

6

What you can do is get a secret key that only you know, Include that in an md5 hashed signature, typically you can structure signatures as a s tring of your parameters a nd values and the secret appended at the end, then take the md5 hash of that...Do this both in your client and service side and match the signature string, only if the signatures match do you get granted access...Since t he secret is only present i n the signature it w ill be hard to reverse engineer and crack..

Daniel
  • 22,363
  • 9
  • 64
  • 71
  • 1
    how would that be difficult to crack? You just read the HTTP request and read the md5 value of your parameter? – erotsppa Jul 13 '09 at 18:10
  • 2
    well if u sniff the http request and resend it just like that sure youll get some response, but no one will be able to generate their own requests because they will not know the secret – Daniel Jul 13 '09 at 18:44
  • To get past that, one can just use some transport level security so when sniffed the data will be encrypted – Daniel Jul 13 '09 at 18:45
  • 1
    You can also hash the secret + current time. Send the time in plain text along with the hash to the server. The server can check that the time is in some reasonable offset from now to deter replay attacks. Since the server knows the secret it can verify the hash by hashing the secret + time sent by the client. Not perfect, but provides some protection against replays. – Matt Dotson Nov 18 '11 at 04:49
5

Here's an expansion on Daniel's suggestion.

Have some shared secret that the server and client know. Say some long random string.

Then, when the client connects, have the client generate another random string, append that to the end of the shared string, then calculate the MD5 hash.

Send both the randomly generated string and the hash as parameters in the request. The server knows the secret string, so it can generate a hash of its own and make sure it matches the one it received from the client.

It's not completely secure, as someone could decompile your app to determine the secret string, but it's probably the best you'll get without a lot of extra work.

Herms
  • 37,540
  • 12
  • 78
  • 101
  • Herms, can you give an example of how you would send the request? From what I understand, you are sending the md5(secretkey+anotherrandom) over the network? Couldn't someone just un-md5 that request and read the secretkey straight out? – erotsppa Jul 13 '09 at 18:20
  • There's no "un-md5" possible as it's a one-way hashing algorithm. The best they could do (on this front) is hash a string and look for a collision (using so-called "rainbow tables"). But the randomness plus the secret key makes a "rainbow table" attack prohibitive. – bbrown Jul 13 '09 at 20:57
  • bbrown is correct. MD5 is a one-way hash, so you don't have to worry about someone decrypting it to figure out the secret. – Herms Jul 14 '09 at 13:31
  • If someone catches one combination of hash & random string sent, they could just use that pair for requests. Or am I missing something? edit: I could use the URL as part of the random string. that way at least they can't replay any request, only the ones they caught. – oberhamsi Mar 15 '14 at 11:27
3

Use some form of digital signatures in your request. While it's rather hard to make this completely tamper proof (as is anything with regard to security). It's not that hard to get it 'good enough' to prevent most abuse.

Of course this highly depends on the sensitivity of the data, if your data transactions involve million dollar transactions, you'll want it a lot more secure than some simple usage statistic logging (if it's hard enough to tamper and it will gain little to no gain to the attacker except piss you of, it's safe to assume people won't bother...)

Pieter
  • 17,435
  • 8
  • 50
  • 89
3

I asked an Apple security engineer about this at WWDC and he said that there is no unassailable way to accomplish this. The best you can do is to make it not worth the effort involved.

I also asked him about possibly using push notifications as a means of doing this and he thought it was a very good idea. The basic idea is that the first access would trigger a push notification in your server that would be sent to the user's iPhone. Since your application is open, it would call into the application:didReceiveRemoteNotification: method and deliver a payload of your own choosing. If you make that payload a nonce, then your application can send the nonce on the next request and you've completed the circle.

You can store the UDID after that and discard any requests bearing unverified UDIDs. As far as brute-force guessing of necessary parameters, you should be implementing a rate-limiting algorithm no matter what.

bbrown
  • 6,370
  • 5
  • 37
  • 43
  • If push notifications aren't your thing, then the only other course of action that I've come across that raises the bar sufficiently is a key exchange. Look at the CryptoExercise sample app to find out how to generate a random symmetric key on the iPhone and use a public key to encrypt it and send it to another iPhone. It's not perfect, but used in conjunction with other countermeasures and you've got some hope of protecting your assets. – bbrown Jul 13 '09 at 21:09
1

A very cheap way to do this could be getting the iPhone software to send extra data with the query, such as a long password string so that someone can't access the feed.

Someone could reverse engineer what you have done or listen to data sent over the network to discover the password and if bandwidth limitations are the reason for doing this, then a simple password should be good enough.

Of course this method has it's problems and certificate based authentication will actually be secure, although it will be harder to code.

Brock Woolf
  • 46,656
  • 50
  • 121
  • 144
1

The most secure solution is probably a digital signature on the request. You can keep a secret key inside the iPhone app, and use it to sign the requests, which you can then verify on the server side. This avoids sending the key/password to the server, which would allow someone to capture it with a network sniffer.

A simple solution might be just to use HTTPS - keeping the contents of your messages secure despite the presence of potential eavesdroppers is the whole point of HTTPS. I'm not sure if you can do self-signed certificates with the standard NSURLConnection stuff, but if you have a server-side certificate, you're at least protected from eavesdropping. And it's a lot less code for you to write (actually, none).

I suppose if you use HTTPS as your only security, then you're potentially open to someone guessing the URL. If that's a concern, adding just about any kind of parameter validation to the web service will take care of that.

Mark Bessey
  • 19,598
  • 4
  • 47
  • 69
0

The problem with most if not all solutions here is that they are rather prone to breaking once you add proxies in the mix. If a proxy connects to your webservice, is that OK? After all, it is probably doing so on behalf of an iPhone somewhere - perhaps in China? And if it's OK for a proxy to impersonate an iPhone, then how do you determine which impersonations are OK?

MSalters
  • 173,980
  • 10
  • 155
  • 350
  • A proxy should send all data to the server that the iPhone sent to the proxy, so I don't see a problem. – Herms Jul 13 '09 at 15:24
0

Have some kind of key that changes every 5 minutes based on an algorithm which uses the current time (GMT). Always allow the last two keys in. This isn't perfect, of course, but it keeps the target moving, and you can combine it with other strategies and tactics.

I assume you just want to dissuade use of your service. Obviously you haven't set up your app to be secure.

Nosredna
  • 83,000
  • 15
  • 95
  • 122