http://www.perlmonks.org?node_id=474937


in reply to Java game linking to a perl script

halley's answer is oriented towards protecting your data in transit. sporty talks about authentication. However, I believe you are asking how to prevent people from winning by peeking at the source instead of actually playing the game.

The suggestion to use POST is good (since the request has side effects on the server), but it doesn't help the problem at hand at all.

Public key encryption might be useful, but it doesn't help the problem at hand, since the hacker can get the public key just as easily as you can get the win code.

You're faced the with the same problem faced by every maker of networked game which tracks stats/wins. And frankly, there's no good answer. The best answers are custom-made for the game they are meant to protect, and they often rely heavily on obfuscation and weak secrets.

1) Run the game on the server. The applet would serve as a GUI, nothing more. If the game is run on the server, it can validate every move, and it would decide whether the player won, not the applet. This is quite secure, but possibly very expensive in terms of server resources.

2) Add sanity checks in the clients. If there are multiple people playing the same puzzle at once, you can use the strategy StarCraft uses. Each player in the game verifies the moves of every other player. If a player performs illegal moves, the game is scrapped. Actaully, that's just the basic idea, because you don't want a player to cause the game to be scrapped when he's about to lose. It also doesn't protect from passive cheats such as map hacks. In fact, since verifying every clients' moves requires knowing the complete state of the game, there is "unlimited" information for passive cheats to use.

3) Add sanity checks in the server. For example, if the game cannot be solved in under 30 minutes, reject any code received in less than 25 minutes from the start of the game. This could be implemented as follows:

Client ====== - When the game starts, - Get a session id from the server. - When the game is won, - Send the session id along with the code. - Every TIMEOUT*0.8 minutes, - Ask the server to reset the session's timeout. Server ====== - When receiving a game start request, - Delete all sessions which have timed out. - Create a new session. - Set the session's start time to now. - Set the session's timeout to now + TIMEOUT minutes - When receiving a game win code, - Delete all sessions which have timed out. - If the code is incorrect, if the session doesn't exists, or if the session is too new to be a valid win, - Tell the client he won (to hide what is going on), but don't record it as a win. - else - Record the win. - Tell the client he won. - } - When receiving a timeout reset request, - Set the session's timeout to now + TIMEOUT minutes - Every so often, - Delete all sessions which have timed out. (The timeout business prevents the database from being filled with old + sessions.)

This isn't a foolproof solution -- this is a weak secret -- but it will be hard to figure out if you hide the fact that the game must run a minimum amount of time for a win to count.

4) Have the server validate the win. Depending on the game, it might be possible to send the steps used to win the game to the server, which could quickly replay the game. The user would have had to play the game to know the steps.

None of the above prevents a hacker from improving his best time by using a replay attack to improve his best time.

Combine obfuscation, sanity checks and server-side validation for best results.