Friday, May 4, 2012

Game"s score is based on a client-side countdown. How to bulletproof it?


I'm working on a game, which has score based on a JavaScript countdown: the faster you finish the level before the countdown reaches zero, the bigger your score is.



How can I make sure it is not somehow altered when I finally receive it from client-side on server-side?



My initial idea is to make two checkpoints: one at the beginning of a level and another at the end. Checkpoint is basically a session sent via AJAX to server-side PHP script which is then timestamped. So after the game is finished on client-side, the score is verified with the one on server-side. Is this kind of protection any good?



Thank you in advance!



EDIT: I'm also open to any other ways to achieve the desired functionality.


Source: Tips4all

9 comments:

  1. As others have pointed out, there's no way you can be certain that the times have not been tampered with, however there are ways to mitigate the consequences:

    If you have a (server-side) system that suspects that scores have been tampered, you can blacklist that IP address or cookie, and not show those scores to other users. Do show the scores to the hacker, though. This has several effects: Firstly, if they think they've beaten you they may move on and leave your code alone. Secondly, if your cheat detection wrongly thinks that a ninja player is hacking, the player will still see their score in the tables as normal (even if other players don't). Consequently, false positives don't matter so much, and you can use fuzzier algorithms, e.g. How does this player's rate of improvement compare to the average? Has he got a bunch of poor scores then suddenly an incredible one? Has my server seen an unusual pattern of hits from this user? Etc.

    You could probably set this up so that you could refine your detection algorithms incrementally, and blacklist players after you've got suspicious about them (and un-blacklist false positives).

    ReplyDelete
  2. Simply, you store the value in a datetime field in your database. Then, you seed your javascript with that value. Thus, any change on the client side, will not have an effect on the stored time.

    However, if you depend on the client side to get a value, you cannot do anything to make sure it's correct. The user can still spoof the ajax request with no real problem. It makes it a bit harded, but certainly doable.

    Once your countdown is somehow related to the client side, there is no escape :)

    ReplyDelete
  3. There are 2 possible scenarios which you might be facing. Let me start with the easy one:

    a) If the web application is designed such that the game starts as soon as the page is loaded, your life is going to be simple. The script which sends out the game should timestamp the database with the time at which the game was sent out. This would be the start time. The end time would be recorded when the client sends in a "level completed" message. As time is being recorded at the server side in both the cases, you do not need the client to keep time. However, there is a catch. See The Catch section below.

    b) If the client loads the application but the game begins much later when the user hits 'play' etc., your life is going to be a little more difficult. In this scenario, you would need a "level began" as well as a "level completed" message coming from the client. Again, it would be a better idea to keep time at the server and not the client. However, you would need to ensure that the client receives an ACK to the "level began" message before starting the game to ensure that the user does not play a game which is not being recorded by the server. (The "level began" message might never have reached the server).

    The Catch: You need to realise that there is no protection possible for the user cheating on his scores! JS is completely open and no matter how you implement your start / end calls to the server, any user can write a script to send similar calls to the server at whatever time interval she wishes to use. Even if you use a session / cookie, these can be easily replicated. (Using a sniffer for instance). Thus, you must realise and accept the design limitations imposed by the HTML/JS architecture and code within these limits. Hence, the best idea is to write code for the users and not to prevent the hackers from sending rogue calls. Make your game fun for the people who would be playing your game and do not worry about the hackers cheating on their scores - they would not be your target audience anyway.

    ReplyDelete
  4. First of all, forget getting the elapsed time from the client side. Any malicious user can alter the sent data.

    Server side must be the only authority for storing the time. At the beginning of the level, store the current time in the $_SESSION. At the end of the level, subtract it from the current time and it is the elapsed time for the level.

    $_SESSION['start_time'] = time();

    $elapsed_time = time() - $_SESSION['start_time'];


    You can still show the elapsed time by Javascript for the user's convenience. For the timing differences between the client and the server (which is perfectly possible), you can do synchronization by getting the elapsed_time whenever your client hit the server.

    If the level completion span between multiple sessions (like you start the level, leave the site, and come back later to finish it) you have to store it in a persistent data store (database).

    ReplyDelete
  5. You can use a timestamp in a session to store the start date and then send make JavaScript do a request when the player's done (but the second timestamp should come from PHP, or other server-side language, too).
    The ony really bullet-proof way is to show nothing to the user and to ask him to tell you every single move, check it with the server and send back what it allows him to know. But this means delay.

    ReplyDelete
  6. You could issue a unique token, that is stored within the user's session and is available to your Javascript code. When starting an AJAX request, pass this token as an additional parameter, so the server can distinguish between legimitate and spurious requests.

    This token should be valid for a single request only of course.
    In combination with the mentioned solutions (server-based time checks etc.) you should be able to build a solid scoring system.

    ReplyDelete
  7. well, thinking of this problem gives me two ideas:


    Attack your own server.
    by that i mean, send a request every 1 second, that will save the score.
    this way, the "hacker" can not send Start/End time and cheat.
    make the requests at a specific time diffrences.
    ok, so lets say we started playing, you can send a request at specific time intervals (3.4 sec? )
    if a request is not in that time frame then the user is cheating ?
    or at least marked as possible cheater.
    use a simple string. XD
    for start/end time sent to server, offcourse encrypted.
    you can try jCryption for encryption.


    since as the others said, it is not totaly fail proof ( since we are talking about client side script ) , but at least it will make it a lot harder to cheat.
    dunno, its just my two cents.

    ReplyDelete
  8. It is not possible to make it 100% bulletproof, you can only make it harder to hack if it is based on client-side

    ReplyDelete
  9. You can generate a GUID when the page is rendered. You can concatenate this GUID, the start datetime ticks, the session ID, and calculate a hash of them to validate the data when user return.

    ReplyDelete