Ensure web service only accessed by authorized applications
My mobile app allows users to create accounts on my service. In addition to being able to log in with external authentication providers, like Facebook, I want to give the user the option to create an account using an e-mail address.
Normally, all calls to my web service are authenticated via basic authentication over HTTPS. However, the create account function (also over HTTPS) does not have any authentication - since the user does not yet have any credentials.
If I was writing a website, I would use Captcha to stop my database from being filled up with bogus accounts via script.
How can I verify that new user requests are coming from an instance of my application and not from a bot?
If all data is sent over HTTPS, is it sufficient for the application to have a stored password to say "hey, it's me!"? What are the best practices for doing something like this?
The server is written in Java using the Spring Framework and Spring Security. It is hosted on App Engine. Cost is a concern (both network and computation). The app is a mobile game. I do not store sensitive information like credit card numbers. However, I do keep track of user purchases on the Apple and Android stores. My biggest concern is player experience. I don't want a hacker bringing down the system and ruining someone's enjoyment of the game. I also, need to make sure that the player faces as few obstacles as possible when creating an account.
I am looking for a way to ensure all calls to the service are coming from an instance of my application. User accounts are already protected because the stateless service requires that they send their credentials on every request. There are no sessions and no cookies.
I need to stop bot-spam on the unsecured calls, such as create-new-account. I cannot use captcha because it does not fit into the flow of the application.
It is for now. However, the service will eventually be used for web and desktop applications.
are you talking about securing client to server or server to server? To secure client to server the only real way to do this is with a CSRF cookie to ensure that it is coming from the correct domain. With server to server i would suggest reading up on HMAC this is the way i have recently had to secure an application API i have been working on.
What is preventing an hacker from making an account normally and then use their credentials for the api?
@beppe9000 I don't bother stopping that because input to the API is validated server side. The game is simple and the format is rigid, so there's nothing to really inject. Purchase codes are validated against third party servers before any kind of item is unlocked. Sadly we ended up shelving this project after market testing. If I do something like this again, I'll probably just pay for middleware because it has come along way since I first posted this question in 2013.
The bottom line is that you will need to embed a secret into your app. It is an unfortunate truth that DRM (which is more or less what you are trying to achieve) is impossible. A person with access to your app will always be able to recover the embedded secret, no matter what you do to protect it.
That said, there are plenty of things you can do to make your embedded secret very difficult to recover.
Construct it at Runtime - Do not store the secret in a string or configuration file anywhere in your app. Instead derive it from a series of computations at runtime. This stops attackers from simply browsing your app with a hexeditor.
Never Send it Over the Wire - Use a challenge-response system of some kind with a >128bit nonce, that way an attacker cannot MitM the SSL stream (which is easy when he controls the mobile device remember) and see the secret in the clear.
In any case, try to find a tried and tested key-scrambling mechanism and authentication protocol. Do not roll your own.
The downside of using a tried and tested algorithm to protect something that is inherently un-protectable is that tried and tested algorithms are more likely to have existing reversal algorithms. In traditional security, protecting the algorithm is unimportant; the goal is to use an algorithm that is safe (unless the key is known), even if the algorithm is public. If no such algorithm exists (in this case, because the key must be held on the client-side), security through obscurity is less unreasonable; there are no good choices.