I'm building a client/server iPhone game, where I would like to keep third-party clients from accessing the server. This is for two reasons: first, my revenue model is to sell the client and give away the service, and second I want to avoid the proliferation of clients that facilitate cheating.
I'm writing the first version of the server in rails, but I'm considering moving to erlang at some point.
I'm considering two approaches:
Generate a "username" (say, a GUID) and hash it (SHA256 or MD5) with a secret shipped with the app, and use the result as the "password". When the client connects with the server, both are sent via HTTP Basic Auth over https. The server hashes the username with the same secret and makes sure that they match.
Ship a client certificate with the iPhone app. The server is configured to require the client certificate to be present.
The first approach has the advantage of being simple, low overhead, and it may be easier to obfuscate the secret in the app.
The second approach is well tested and proven, but might be higher overhead. However, my knowledge of client certificates is at the "read about it in the Delta Airlines in-flight magazine" level. How much bandwidth and processing overhead would this incur? The actual data transferred per request is on the order of a kilobyte.
No way is perfect--but a challenge/response is better than a key.
A certificate SHOULD use challenge/response. You send a random string, it encrypts it using the certificate's private key, then you get it back and decrypt it with the public key.
Depending on how well supported the stuff is on the iPhone, implementing the thing will be between trivial and challenging.
A nice middle-road I use is xor. It's slightly more secure than a password, trivial to implement and takes at least an hour or two of dedication to hack.
Your app ships with a number built in (key).
When an app connects to you, you generate a random number (with the same number of bits as the key) and send it to the phone
The app gets the number, xor's it with the key and sends the result back.
On the server you xor the returned result with the key which should result in your original random number.
This is only slightly hacker resistant, but you can employ other techniques to make it better like changing the key each time you update your software, hiding the random number with some other random number, etc. There are a lot of tricks to hiding this, but eventually hackers will find it. Changing the methodology with each update might help.
Anyway, xor is a hack but it works for cases where sending a password is just a little to hackable.
The difference between xor and public key is that xor is EASILY reversible by just monitoring a successful conversation, public key is (theoretically) not reversible without significant resources and time.
Who is your adversary here? Both methods fail to prevent cracked copies of the application from connecting to the server. I think that's the most common problem with iPhone game (or general) development for paid apps.
However, this may protect the server from other non-iPhone clients, as it deters programmers from reverse engineering the network packet interfaces between the iPhone and the server.
Have your game users authenticate with their account through OAuth, to authorize them to make game state changes on your server.
If you can't manage to authenticate users, you'd need to authenticate your game application instance somehow. Having authentication credentials embedded in the binary would be a bad idea as application piracy is prevalent and would render your method highly insecure. My SO question on how to limit Apple iPhone application piracy might be of use to you in other ways.
Related
I am working through some security concepts right now and I was curious if this method has been tried and/or if it is safe taking into consideration "Brute Forcing" is still possible.
Take for example a Microsoft WebAPI Template in Visual Studio where you access a endpoint using a "GET".
The Endpoint would be accessible by any user/application
The String value that a user/application would get from this endpoint would be the password they need, but encrypted using a "KeyValue"
After a TLS Transmission of this Encrypted Value, the user/application would decrypt the String using their "KeyValue"
Is this a secure practice?
Thanks for indulging me and look forward to your responses.
EDIT: Added Further Clarification with Image to Help Illustrate
Suppose the following 2 Scenarios:
Communication between Server and Client
a. Your Server serves the Client application with an encrypted password.
b. The Client can request any password.
c. The passwords are encrypted with a shared Key that is known by both server and client application
As James K Polk already pointed out:
A knowledgable Attacker can and will analyse your deployed application and at some point will find your hardcoded decryption key ("KeyValue"). What prevents him from requesting every password that is stored on the Server?
Rule of thumb here would be: "Do not trust the client side."
Communication between Server and Server
a. You have 2 server applications. Application A is acting as some kind of database server. Application B is your Back-End for a user application of some kind.
b. Application A serves paswords to any requester, not only Server B. With no type of authentication whatsoever.
c. Confidentiality is guaranteed through a shared and hard-coded Key.
I think you are trying to overcomplicate things hoping that no one is able to piece together the puzzle.
Someone with enough time and effort might be able to get information about your server compilation and/or be able to get the Code of Application B. Which again defaults in the scenario of 1. Another point is that there are enough bots out there randomly scanning ips to check responses. Application A might be found and even-though they do not have the shared key might be able to piece together the purpose of Application A and make this server a priority target.
Is this a safe practice?
No. It is never a good idea to give away possibly confidential information for free. Encrypted or not. You wouldn't let people freely download your database would you?
What you should do
All Authentication/Authorization (for example a user login, that's what I expect is your reason to exchange the passwords) should be done on the server side since you're in control of this environment.
Since you didn't tell us what you're actually trying to accomplish I'd recommend you read up on common attack vectors and find out about common ways to mitigate these.
A few suggestions from me:
Communication between 2 End-points -> SSL/TLS
Authorization / Authentication
Open Web Application Security Project and their Top 10 (2017)
I read a lot that you can't restrict your Public REST API to only your mobile application, but I have an idea and I want opinions on it:
Variable App Key Method
Mobile App
Get IP address of current connection
Use a secret algorithm to generate a hashed AppKey from IP address.
Send the AppKey with each API request
Server Side
Check the IP address of incoming request
Generate AuthKey from that IP address using same secret algorithm.
Compare AuthKey with AppKey, if they match then you know that your
Application is talking to you, because only the application knows
the secret algorithm.
When IP address changes:
On mobile App regenerate the AppKey using the new IP address
Server side will always generate same key because it depends
on IP address of the request
The main advantage of this is that the AppKey will always change, which is better than hardcoding 1 application key inside the code, which can be easily stolen by reading request headers. And even if you stole the AppKey from a user you must be using the same IP address where that key was generated.
Any thoughts?
The "secret" algorithm would have to be in the app... given to everybody. It is not secret at all. Security by obscurity is bad anyway, you should not have supposedly secret algorithms, because it's hopeless to keep them confidential. In this case the algorithm is trivially revealed.
Also refer to Schneier's law. :)
Edit:
So theoretically, this can never be secure, because any algorithm you put into the app needs to run on the client, and hence can be analysed and decompiled. But one can argue that it doesn't need to be theoretically secure, it is ok if it's "secure enough", ie. the risk is low enough, because for example the effort needed to get to the algorithm is too much.
But then consider the two possible options:
This is a really cool API that everybody totally wants to build a client for, or there is at least one such party. In this case, no effort is too much, and the algorithm will be "broken", that is, it will be decompiled and implemented in a different client.
People don't care all that much about this API, it is not very important for anybody else to build a client. In this case they probably won't build a client anyway, and much simpler methods can be used to prevent other clients from popping up with a reasonable success.
But obviously, it's your choice, an approach similar to what you describied does raise the bar somewhat - just don't expect it to be actually secure, because it will not be.
A client asked me to do a back-end server for its iPhone application and want only users who bought the application to be able to call the server.
The problem is that he doesn't want to add a login system to the application, so that it seems to me there is no completely safe way to prevent someone without his application calls the server.
In any case, even if it can not be completely prevented, it would be sufficient to make it difficult to access servers without the application.
What is the best way to achieve this? Again, I do not need to fully protect the connection, there is no transit of sensitive information, I just want to make things a little more complicated for people who want to take advantage of server without paying the application.
The idea that seems most simple is to encrypt the data with a key stored within the client and known to the server, so that the message can be decrypted only decompiling the code and finding the key (of course instead of a key you could put a list of keys, which change every 6/12/24 hours).
Could this be a reasonable solution?
This will never be possible. Welcome to the nature of the client-server architecture. You can never trust the client. Just make sure the functionality you are exposing is safe.
well if its a paid app you could release the app for free with all the functionally locked down until a user does a in app purchase and then you could verify the receipt on your server therefore proving that the device is a iOS Device?
sharing a key between the client and the server seems to be a good way to go. But instead of depending on the stored keys only, try combining them with a Unique identifier, such as UUID and send it to server both with the combined key, and the UUID itself.
At that point users UUID will be his identifier (username) and the combined key will be his token (password). And this will be a login-like mechanism.
An SSL connection is not enought to prevent other people from getting the URL for the requests? Or even better using an SSL connection with a basic auth?
I have written an iPhone application communicating with a server. The app sends a message to the server and prints the result.
Now I have a question: Is there a way to know if the message sent to the server came from an iPhone?
I am asking this because I want to prevent attackers from sending messages from somewhere else and flooding the server.
If you use in-app purchases, then there is a full authentication chain that validates device X purchased the app. You're server can track this and then only give full responses to previously authenticated devices.
This approach also keeps pirated apps pretty much out of the picture.
This approach wouldn't stop a concerted DDOS attack, but your server can at least ignore non-valid clients and thus reduce its workload significantly. Since your server is ignoring invalid requests here, it also makes it less appealing to potential non-device users and the illicit user would probably only attack you if they disliked you, as opposed to them just bogging down your server for its free web services.
If you don't use in app purchases, you could set up your own authentication process and give a token to the device and have your server remember said tokens, and then later only serve valid responses for requests that had the said token (appropriately hashed and salted). This approach would not stop pirated apps from using your service, but would effectively stop non-devices from using your web service (again, except for concerted hacking efforts).
An even simpler approach is to have an obfuscated request format that would take a concerted effort to reverse engineer.
In all of these approaches, you might have to monitor your server for unusual activity and then taking appropriate steps.
I would encourage you to match your efforts to the expected risk. You can spend days, months, even years, properly securing an app, make sure the cost is worth the reward.
You could do some form of authentication, encryption or fingerprinting, eg. using SHA, MD5, etc. That way you could make it difficult (but not impossible) for an attacker to abuse your server.
You can't tell it's from an iPhone until you have received and examined the connection on the server. If you do that, you have already opened the possibility of a DOS (Denial of service) attack due to connection exhaustion.
I'm developing a program with a client/server model where the client logs on to the server, and the server assigns a session id/handshake which the client will use to identify/authorize its subsequent messages to the server.
I'm wondering what length should the handshake be for it to be reasonably secure but also short enough to minimize data overhead, since I'd like to have it be low latency.
I'm thinking of using MD5 or murmurhash2 with the username and a random number salt with a collision detection, but I'm wondering if there's a more efficient solution (i.e. a better algorithm) and whether 32bits is too much/too little for this kind of thing.
Any input is highly appreciated.
I would use a HTTPS connection for your client/server communications.
It's easy to use (almost all the major SDKs implement it) and it provides good encription.
Regards.
PD: In reference of encryption method I would use Whirlpool because Mr. Rivest said in 2005 it was broken.
This may not be as simple as it looks. Note that if you send anything in clear over the network (e.g. session id/handshake), anyone can eavesdrop the communication and reuse this value to act as the client.
If you cannot use https, as the first answer suggested, you probably need to look at key agreement protocols. Once both parties agree on a shared secret key (which cannot be reconstructed based on observed communications), you can use it to authenticate all the remaining transmissions with a MAC (e.g. HMAC).
Whatever you do, don't use MD5, it's so totally broken. Whirlpool may also not be the good option, it's slower and there is a recent (theoretical) attack on the main part of it, see
ASIACRYPT 2009 Program.
I would stick with SHA-256 for now.