views:

202

answers:

9

Lets say that in a browser based game, completing some action (for simplicity lets say someone clicks on a link that increases their score by 100) clicking on this link which would have a url for example increase_score.pl?amount=100 what kind of prevention is there from someone simply sending requests to the web server to execute this command:

  1. Over and over again without actually doing the task of clicking on the link and
  2. Sending a false request to the server where amount is set to something rediculus like 100000.

I am aware of checking HTTP_REFERER however I know people can get around that (not sure how exactly) and other than some bounds checking for the 2nd option I'm kind of stumped. Anyone ever experience similar problems? Solutions?

+1  A: 

Token with cookie/session.

Ahmet Kakıcı
+15  A: 

Nothing can stop them from doing this if you implement your game how you propose.

You need to implement game logic on the server and assign points only once the server validates the action.

For example: on SO when someone votes your question up, this isn't sent as a command to increase your reputation. The web-app just says to the server user X voted question Y up. The server then validates the data and assigns the points if everything checks out. (Not to say SO is a game, but the logic required is similar.)

Ben S
What?! SO's not a game?!
JB
@JB: Hahahaha, yes it is... and my score is **over 9000**! :D
R. Bemrose
@JB: Of course not. It's a simply a community with a mechanism for -- hey! I've almost got my score up to 700! C'mon, just one more up-vote for the big round number, come to daddy....
BlairHippo
+1  A: 

You could make the link dynamic and have a hash that changed at the end of it. Verify that the hash is correct given that period of time.

This would vary in complexity depending on how often you allowed clicks.

sparks
+3  A: 

The logic of the game (application) should be based on the rule to not trust anything that comes from the user.

HTTP_REFERER can be spoofed with any web client.

Alexandru Luchian
Oh yes, never trust the client...
sleske
A: 

Expanding on Ahmet's response, every time they load a page, generate a random key. Store the key in the user session. Add the random key to every link, so that the new link to get those 100 points is:

increase_score.pl?amount=100&token=AF32Z90

When every link is clicked, check to make sure the token matches the one in the session, and then make a new key and store it in the session. One new random key for every time they make a request.

If they give you the wrong key, they're trying to reload a page.

Dean J
Just don't ban people for doing this - there are legitimate reasons for reloading a page, like trying to see if anything changed, or restarting the browser.
romkyns
What you've done is made your app more complicated, and required corresponding complexity in a cheat program. This is not an arms race you want to get into, since cheaters have effectively unlimited time to study your Javascript and you can't change it in real time to respond.
David Thornley
Actually, this might cause a problem - if the user arrives at a page with such a link and refreshes, the random value will change and the link becomes un-legit when it was never clicked.
Frank DeRosa
That's still insecure, as you can modify the amount= and keep the token. The safe way is to generate a token per *link*, then use just the token as the parameter, and look up the real action when a token is submitted. That way the user can only invoke an action that was really on the page. Of course you invalidate all tokens once one token comes back, or after a timeout... that prevents replay attacks.
sleske
1. Who said anything about Javascript? 2. If you refresh, you should also refresh the tokens. 3. And yes, you probably don't want amount=x as a parameter.
Dean J
A: 

I would suggest making a URL specific to each action. Something along the lines of:

/score/link_88_clicked/
/score/link_69_clicked/
/score/link_42_clicked/

Each of these links can do two things:

  1. Mark in the session that the link has been clicked so that it wont track that link again.
  2. Add to their score.
Jack M.
This wouldn't scale well and needlessly obfuscates the application.
Ben S
URL obfuscation is what I was after. Simply make it harder for the player to modify the URL and achieve a score advantage. I'm curious as to why this wouldn't scale well, however? A mod_perl handler parsing the scores and dispatching to a method call seems like it would scale just fine.
Jack M.
+4  A: 

Short version: you can't. Every piece of data you get from the client (browser) can be manually spoofed by somebody who knows what they're doing.

You need to fundamentally re-think how the application is structured. You need to code the server side of the app in such a way that it treats every piece of data coming from the client as a pack of filthy filthy lies until it can prove to itself that the data is, in fact, plausible. You need to avoid giving the server a mindset of "If the client tells me to do this, clearly it was allowed to tell me to do this."

WRONG WAY:
Client: Player Steve says to give Player Steve one gazillion points.
Server: Okay!

RIGHT WAY:
Client: Player Steve says to give Player Steve one gazillion points.
Server: Well, let me first check to see if Player Steve is, at this moment in time, allowed to give himself one gazillion points ... ah. He isn't. Please display this "Go Fsck Yourself, Cheater" message to Player Steve.

As for telling who's logged-in, that's a simple matter of handing the client a cookie with a damn-near-impossible-to-guess value that you keep track of on the server -- but I'll assume you know how to deal with session management. :-) (And if you don't, Google awaits.)

BlairHippo
Daddy, there's your big round number.
glenn jackman
+1  A: 

A few things to note here.

First, your server requests for something like this should be POST, not GET. Only GET requests should be idempotent, and not doing so is actually a violation of the HTTP specification.

Secondly, what you're looking at here is the classic Client Trust Problem. You have to trust the client to send scores or other game-interval information to the server, but you don't want the client to send illegitimate data. Preventing disallowed actions is easy - but preventing foul-play data in an allowed action is much more problematic.

Ben S makes a great point about how you design the communication protocols between a client and a server like this. Allowing point values to be sent as trusted data is generally going to be a bad idea. It's preferable to indicate that an action took place, and let the server figoure out how many points should be assigned, if at all. But sometimes you can't get around that. Consider the scenario of a racing game. The client has to send the user's time and it can't be abstracted away into some other call like "completedLevelFour". So what do you do now?

The token approach that Ahmet and Dean suggest is sound - but it's not perfect. Firstly, the token still has to be transmitted to the client, which means it's discoverable by the potential attacker and could be used maliciously. Also, what if your game API needs to be stateless? That means session-based token authentication is out. And now you get into the deep, dark bowels of the Client Trust Problem.

There's very little you can do make it 100% foolproof. But you can make it very inconvenient to cheat. Consider Facebook's security model (every API request is signed). This is pretty good and requires the attacker to actually dig into your client side code before they can figure out how to spoof a reqeust.

Another approach is server replay. Like for a racing game, instead of just having a "time" value sent to the server, have checkpoints that also record time and send them all. Establish realistic minimums for each interval and verify on the server that all this data is within the established bounds.

Good luck!

Peter Bailey
+1  A: 

It sounds like one component of your game would need request throttling. Basically, you keep track of how fast a particular client is accessing your site and you start to slow down your responses to that client when their rate exceeds what you think is reasonable. There are various levels of that, starting at the low-level IP filters up to something you handle in the web server. For instance, Stackoverflow has a bit in the web application that catches what it thinks are too many edits too close together. It redirects you to a captcha that you need to respond to if you want to continue.

As for the other bits, you should validate all input not just for its form (e.g. it's a number) but also that the value is reasonable (e.g. less than 100, or whatever). If you catch a client doing something funny, remember that. If you catch the same client doing something funny often, you can ban that client.

brian d foy