Secure online-game http get/post request (How to avoid repeated sending of the same http-req)
In my game/app (iPhone) the client side sends http requests (get or post) to the game http server. Requests have this form:
gameserver.com/userId/givebonus/100
This for example would give the userId a bonus of 100.
Now, we encrypt the server request and it will become something like:
gameserver.com/42c34c234c234/ghjghjg4hj32g42jh2/424j23gh4h234h2j34j23
I'm not to fuss about some hacker trying to decrypt this to unveil the meaning of all of this, what I'm worried about is sniffing. Cos once the hacker knows that:
gameserver.com/42c34c234c234/ghjghjg4hj32g42jh2/424j23gh4h234h2j34j23
Gives a bonus of +100 it could just keep sending the same request over and over again.
So how do you prevent this?
Talking with few friends these are the possible solutions, but none of them would be either easy to implement or more secure:
- Moving all (most) of the logic server side.
- Handshake the 开发者_如何学Gofirst request and respond only to that mac address. (This won't work I think)
- Changing private encryption key dynamically? How?
- Encrypt the whole requests, basically using https? (Dont know how though :( )
I'm sure there's an easier answer I dont see :P
Security is hard. Security when you're trusting the client implicitly is impossible. You need to think about how much effort you're willing to go to in order to protect this, and how much you lose if it gets compromised. Because unless you basically run everything server-side, you can expect that it will get compromised.
If you just want to stop replay attacks, you can do so simply by adding an incrementing "request count" into your command pre-encryption, and discarding any duplicate requests.
But don't be fooled into thinking this is somehow "secure", because it's not.
You could use a variant of what's used to prevent CSRF attacks on websites (I'm assuming you're controlling the server):
- Have the client make a GET request to
http://gameserver.example/userId/givebonus
.- Generate a UUID or something similar on the server side, which you store in a DB on the server, associated with that userID in some sort of "pending" table.
- The response to this GET should contain this UUID (like a hidden token in an HTML form)
- Have the client send a POST request, containing that UUID and the points you want to give.
- On the server, check against the UUID from the DB and only perform the increment if it hasn't been done before. Delete it from the pending list during the transaction.
(There are a few variants of this, whereby you could sign the token, but I think it would be hard to do a replay on a new UUID in general.)
As a side note, I'd recommend against doing increments by GET requests on http://gameserver.com/userId/givebonus/100
. GET is meant to be a safe method, i.e. you can do it as many times as you want and it won't affect the server state; this is by design of HTTP and REST. Clearly, this would cause problems if you take action on a GET. I'd suggest using POST for actions with side effect, and putting the amount and perhaps the action name within the request entity, then.
(Of course, there's no harm in using HTTPS in conjunction with that.)
精彩评论