27

[I know there have been similar questions about preventing cheating on high score lists, but no answer didn't really help me for JavaScript based games, so please try to think about my question, before telling me about similar posts. I ask about best practices because the JavaScript is always visible for the user and therefore it is not possible to prevent cheating completly, I just want to make it harder.]

I'm developing a JavaScript based game that works in the browser. I want to make a high score list that contains the user name and the score of all users. To achieve that the browser sends the username and the score to my server (via AJAX).

Submitting fake scores to this list would be fairly easy: One could take a look at the AJAX requests and then make an own AJAX request with a faked score. Using something like a token that has to be send with the other data is pointless, as it will be easy to discover.

My only approach, that would prevent cheating, would be to send a description of every user action to the server and calculate the score there. But this is not really practicable as it would be too much for the server.

I accepted an answer, but in case anyone has other ideas about how to make cheating harder, please create another answer!

js-coder
  • 8,134
  • 9
  • 42
  • 59

10 Answers10

17

I like to play cheat the cheater - something like using a token to authenticate the score that changes every time the update is called... but I accept the cheat score that gets posted using a duplicate token. Then I display that cheat score to only the cheater, so it appears that it worked, but now the cheater is seeing his results in a sandbox.

Matt H
  • 6,422
  • 2
  • 28
  • 32
  • 3
    That's definitly good for rejecting some faked scores, but I don't think it will stop many cheaters. One could just prevent the first request and use the token for the request with the cheated score. - +1 for the nice idea though! – js-coder Dec 29 '11 at 16:57
13

You pretty much answered your own question. If you want to really make it harder for users to cheat, send game log to the server, where you'll calculate the score.

You don't have to send all the events, just ones that affect result score.

There are some techniques, though, that may help you:

  • include signature in your request. Something like MD5(secret_key + params). Although, "secret key" will have to be in JS source, it will effectively protect you from simple request interception (see Tamper Data and Charles)

  • if it's a multiplayer game, accept scores calculated by clients and compare them. Cheaters will be pretty visible (assuming that the majority of users are honest).

  • you can set a score cap, an "unreachable" result. Everyone who posts score higher than this is a cheater. For example, speed typing game: no one can type correct text at 1500 chars/minute, even 700 is pretty damn hard (though achievable).

Kevin Ji
  • 10,479
  • 4
  • 40
  • 63
Sergio Tulentsev
  • 226,338
  • 43
  • 373
  • 367
  • I already figured out the *unreachable result* idea - but it won't stop the cheater from trying it again with a reachable score. | Calculating everything on the server is not really possible for me. I don't own a server that will be able to handle that for many users. – js-coder Dec 29 '11 at 16:52
  • 1
    You can always elicit the clients' help in calculating scores. Store the logs, give them to clients, let them calculate the score, then upload the result back to you. You pay for the bandwidth and (temporary) log storage, but there's no calculation load on the server. – Matt H Dec 29 '11 at 17:03
  • 1
    JS games are hard to protect when the source is open to read. try implementing a reversible encryption of data for the server to decode. Also, obfuscate/variable & name replace/minify the JS code of this encryption algorithm. although still tamperable by reverse engineering the code and knowing how the encryption works, it at least helps by garbling up the transmitted data (esp when using the firefox TamperData add-on) – Joseph Dec 29 '11 at 17:08
  • 2
    This doesn't really matter, but your score cap is a bad example. Plenty of people can break 1500 chars/minute with a stenograph, and for some reason those people like to go to websites with typing high score lists. –  Jan 03 '12 at 08:07
  • @skier88: I meant real typing :-) – Sergio Tulentsev Jan 03 '12 at 08:22
  • 2
    Modern stenographs (with experienced stenographers) output real, correct, precise english. I actually know for a fact that at least one typing website draws a large number of legitimate scores from people with stenographs plugged into their computer. So ... just saying... –  Jan 03 '12 at 08:54
  • @skier88: okay, maybe it's a bad example :-) – Sergio Tulentsev Jan 03 '12 at 08:57
5

On score submit:

  1. Request some token from the server, this should be time based and only valid for about 2 seconds
  2. Only accept submits that include a valid hash of this token, some salt and the score.

This prevents manual tampering with the request as it would timeout the score. If you want to account for high-latency give it a little more time until the timeout.

The hashing function:

Scramble the hashing function inside packed code (http://dean.edwards.name/packer/ really produces nasty to read code) if you use jQuery or some other library just drop the hashing functionality inside the library file and it gets pretty bad to find, escpecially if you use a function name like "h" :)

Handling the score-variable itself:

Well everybody with a debugging console can change the variable on runtime when doing this but if you encapsulate your whole Javascript inside a function and call it nothing is in the global namespace and it's much harder to get to the variables:

(function() {
  //your js code here
})();
bardiir
  • 14,556
  • 9
  • 41
  • 66
  • 2
    It would not prevent cheating at all, it's enough to copy and paste some code. – Ismael Luceno Jan 04 '12 at 20:02
  • This does prevent 'tampering' with the code to unlock possible levels or modes that can normally not be accessed. Like, I 'hacked' http://nyan.cat/ to unlock the animations that appear when you leave it running for a longer time (don't know if it still works, there was beer involved). – Halcyon Jan 06 '12 at 17:09
  • In Chrome (and probably firefox aswell) you can edit the javascript source live in the debugger. So while it would prevent window.game.score = 9999 or window.player.health = Infinity; it would not protect against any this.score = 9999 or this.health = Infinity; – Johan May 27 '13 at 12:00
3

I have had lots of thoughts about it and, eventually, decided to only have local individual highscores, so cheating is not really beneficial for player and not harmful to others. Yet my game is just a simple minesweeper, and there were people who complained about the lack of competitive table.

Option 2, is approach taken by WebSudoku - to show your place "among the people of internet". So you will not see any other results, and people wont see your results - but you can compare yourself to crowd.

p.s: And seriously - any kid with Firebug/WebInspector can easily hack your JS game and, eventually, to be able to reach very high score.

c69
  • 19,951
  • 7
  • 52
  • 82
2

If you are relying on the client to send the final score to the server, then there is no way (afaik) to prevent a genius from cheating. But I think you might be able to prevent stupid people (and honest people) from cheating, so that only geniuses and their friends will dominate your leaderboards.

There are two ways I can think of

1.) "security through obscurity."

Come up with an algorithm that transforms simple scores into something else (and to transform them back). Then obfuscate it. Complicate it. Write a function that multiplies it by q and divides it by ralph. Apply a bunch of functions to it, and among the 5-15 functions that do random stuff to it, include one that multiplies the number by 19 ( a prime number ). On your server, check to make sure every incoming number (or letter) is divisible by 19, and decode

You have to write a bunch of complex code that transforms simple scores into something crazy-looking. You have to write a series of functions in the least-efficient, most spaghetti-code fashion possible. Use One thing you cold do is to have a set of disallowed values. I.e., perhaps all points awarded are even. If anyone tries to submit an odd number, they are obviously cheating (and very stupid).

2.) time

You should be able to know when the user started the game. You should have a session started and record when they requested the page. Then you should also be able to tell when they submitted their score. And you should also know what the time series is for max points. I.e. can you get 5 points per minute, 100 per minute, minute^3, etc... If user submits more points than are possible during that time, they are cheating.

You could also strike a balance between server and client processing and make the client should send progress update every x minutes by ajax. And if it fails to report, you assume it's been compromised (much like in Bond movies, when he's infiltrating the enemy's lair and he snaps some guard's neck. When the guard doesn't respond to his next 10-minutely check-in, the alarms will go off).

If you've ever played Zynga Poker, you've probably seen what happens when someone at the table has a slow internet connection.

Buttle Butkus
  • 9,206
  • 13
  • 79
  • 120
1

I used a system using a time based request having 3 parameters

req number, curr time, score 

The req number is returned from server in the response to the update score request , each time this is a new random value.

The curr time is calculated not from computer clock but from start of game and is synced with server using an ajax request.

Update score request is sent after short intervals (around 30 sec max).

Following checks are applied on the server

Time is within 10 seconds range from the server clock.
there has been not more than 40 seconds since the req number was sent.
the score change sent after 30 seconds is possible (within 2 x humanly possible range)

Score is updated only if the above checks are passed or the user gets a disconnection message :(

This is simpler than most methods and works out to eliminate all casual hackers (well, unless they read this and want to go to the trouble of updating score quickly or making a script of their own).

arkoak
  • 2,437
  • 21
  • 35
1

If not cheating is more important than the game itself, try to construct and present your game in a way that it looks like finding the solution to a math problem. So the server will give an instance of the problem to the client (example A: a chess board about to be won in 3 moves, example B: a geometry dash randomly generated level) and the user will have to solve it and post back a solution (example A: the winning moves, example b: the exact timestamps and intensity of jumps to avoid obstacles)

With this approach, it is key that the server doesn't send the same level twice, or else the cheater can plan and "design" his solution in advance. Also, the game information must be randomly generated in the server and not sent via seed, or else the cheater can fake the seed and design his solution with time.

The given time for valid submissions must be also tracked in the server so that they will only have "playing" time and no "designing" time. If the cheater is good enough to design a solution as fast as honest players can win the game, then they are talented enough to win the game honestly and deserve their points.

Back in the server, you will need to check that the submitted solution is valid for that instance.

Of course this approach requires lots of extra work: More instances of games (ideally infinite and non repeating), server side generation, server side validation of submissions, time caps, etc.

Note: I know these approach was already suggested in multiple solutions some years ago, I wanted to add my humble contribution.

fran
  • 326
  • 3
  • 15
  • It's a nice idea but I think this will only work well if the source code of the client isn't accessible. For example if the client is a web browser, all the code to solve the levels can be found by potential cheaters – js-coder Mar 16 '16 at 15:25
  • Well, in many cases the source code only holds the rules of the game, and not any clues on how to win. For example, a chess puzzle or an arcade game where you have to jump to avoid obstacles, the code will detect if the user hits an obstacle but it won't help you win or give you clues. If the cheater modifies the code to make, let's say, obstacles dissappear, then he will "win locally", but the game will submit a solution that the server will not validate, as for that level instance, the solution will hit the obstacles – fran Jul 26 '16 at 16:34
1

Depending on the nature of the game, you could use other players to verify the results. In simple games this works great, on others you have to be clever and develop many aspects around this feature. E.g. sometimes is possible to replay and verify results based on logged actions. This trick works specially well for Human versus AI, as long as the model is deterministic.

Another option is redefining the score concept to be more user-centric, this is pretty easy to implement, but tends to be hard to devise, and only applies to a few categories of games.

Purely speculative approaches are also possible, it's sometimes pretty easy to know when some parameters don't fit. It would not avoid cheating, but would moderate it a lot.

The most complicated part is getting a small enough replay log, but since most data isn't random (except for player actions, which, actually aren't that random because depend on the game) it's essentially a matter of getting the design right.

Also, if gameplay is extended enough, for action games and the like you can get a lot of compression from doing some approximation, merging (e.g. motion vectors), and clipping uninteresting stuff.

Ismael Luceno
  • 2,055
  • 15
  • 26
  • What exactly do you mean with *you could use other players to verify the results*? – js-coder Jan 04 '12 at 20:51
  • In the simplest form, the user is required to process other's players data while running the game, besides his own. E.g. just before submitting his own score. This is based on the assumption that sending a small payload is cheap, so you must be clever about that (simplify, then divide and conquer). – Ismael Luceno Jan 04 '12 at 21:20
  • This doesn't have to be instantaneous, you could just have a private high score table and only move it publicly once verified. – Ismael Luceno Jan 04 '12 at 21:22
  • Let me expand the answer a bit... – Ismael Luceno Jan 04 '12 at 21:31
1

Ideally you would send your entire event log to the server for checking. Perhaps you can implement a heuristic so you can easily determine if the score is within a set of bounds. For instance, if the total game time is 5 seconds you might expect a much lower score than with a much longer game time.

Alternatively, you could choose to manually check the event log for really high scores (the overall top-X, which should be fairly stable).

You will need a seeded random number generator if you're doing anything with randomness (like random events). Which might be tricky if you hadn't already thought of it.


You can find many more resources but it really just boils down to server-side checking. JavaScript is not unique in this, but likely easiest to exploit because you not only see the client-server communication but also the client-side source code!

HTML5 Multiplayer Game Security Solutions

http://lanyrd.com/2011/jsconf/sfggb/

Games like Starcraft only record the mouse clicks and key presses. The actual commands are then simulated. I expect 'Worms Armageddon' to do something similar but their random events (like the bounciness of bananas) aren't seeded properly so in the instant replay you might get a different result.

You could imagine something similar for MMORPGs. The server calculates your position based on the keypresses, the client merely tries to give a good early interpretation but you may warp around when you're lagging because the server will place you elsewhere on the map because it didn't get the keypress events timely.

If you attack something, the server will check if you're close enough and how much damage you can expect to deal with current stats and equipment.

Community
  • 1
  • 1
Halcyon
  • 57,230
  • 10
  • 89
  • 128
1

Record key points in game, then score is submitted with these key points. When people look high scores, they can also see overview of played game, if it looks like it is impossible to play like that without cheating, then people can report these suspicious scores to admins.

newbie
  • 24,286
  • 80
  • 201
  • 301