35
\$\begingroup\$

I'm planning on venturing on making a single player action rpg in js/html5, and I'd like to prevent cheating. I don't need 100% protection, since it's not going to be a multiplayer game, but I want some level of protection.

So what strategies you suggest beyond minify and obfuscation?

I wouldn't bother to make some server side simple checking, but I don't want to go the Diablo 3 path keeping all my game state changes on the server side.

Since it's going to be a rpg of sorts I came up with the idea of making a stats inspector that checks abrupt changes in their values, but I'm not sure how it consistent and trusty it can be.

What about variables and functions escopes? Working on smaller escopes whenever possible is safer, but it's worth the effort?

Is there anyway for the javascript to self inspect it's text, like in a checksum?

There are browser specific solutions? I wouldn't bother to restrain it for Chrome only in the early builds.

\$\endgroup\$
5
  • \$\begingroup\$ Where is your data saved, how is your data saved? \$\endgroup\$
    – DogDog
    Sep 20, 2012 at 14:45
  • \$\begingroup\$ Funny you talk about Diable 3, the "Diablo 1 way" was exactly that, trusting the client. Do a google search if you are too young to remember what happened because of That! \$\endgroup\$
    – Valmond
    Sep 20, 2012 at 14:56
  • \$\begingroup\$ possible duplicate of How do you prevent your JavaScript / HTML5 web game from being copied or altered? \$\endgroup\$
    – House
    Sep 20, 2012 at 14:59
  • \$\begingroup\$ Apoc, right now I just have a proof of concept and I haven't implemented any kind of persistence - but I plan to implement some DB persistance in first builds and/or local storage so that players cant just keep playing from where they left. Yes, Valdmond I played my share of Diablo back then. But i'm not building a competitive multiplayer game, or a full flagged AAA. Byte56, I'm not concerned on stealing my code (who would want that crap anyway?) \$\endgroup\$ Sep 20, 2012 at 17:18
  • \$\begingroup\$ unfortunately, you have to go the diablo 3 path, if you are really concerned about hacks/cheats \$\endgroup\$ Sep 21, 2012 at 12:23

7 Answers 7

46
\$\begingroup\$

The short answer is you can't do it. Anything that runs client side, especially from source, can be modified to defeat your tactics trivially. If you put in place a client side checker to look for abrupt changes, a user can just disable the checker.

The good news is that, generally, there is very little cheating on single-player games. The only major exception being for games that have large "youtube highscore" communities like Line Rider, where players compete with each other over YouTube.

If you are aiming for that, or are just too stubborn to accept that people might cheat in the game, or are keeping high-scores yourself (which is a form of multiplayer) then what you must do is all of the calculations server-side. Yes, everything that matters. You can't even repeat the calculation client side to try to give the user the score and then 'verify' it with the server because the user can then just disable the check and disable any system that ensures there are checks.

I wish there was a better answer to this, but there isn't.

That said, there are things you can do to make it a little harder to cheat. They will not stop anyone serious from doing it and releasing a toolkit to cheat, but it will slow them down:

  • Minify and Obfuscate your JS, which absolutely will make the code harder to read. You can de-minify and sort-of de-obfuscate but you can never get back the right variable and function names, nor comments.
  • Bake in values with a different language. In this case you can use PHP or other server side languages to handle static setup variables. If the jump distance is always supposed to be 2 spaces, normally you'd define a jump distance for the player object. Don't, handle that with PHP so that the JS source ends up with 2s plastered all over the code in a million places. This has the happy additional side effect of being able to speed up your JS too.
  • With some practice, you'll get proficient with the mix and you can even custom-build your JS for each player. Which is another way to prevent cheating. If each player's code is different somehow, then it is harder to write a cheat that can be part of a toolkit.
  • Finally, you can checksum the source based on the player's identity. Say their IP address and/or username. You know what the player-specific version of the JS will be, you can bake in a checksum and require that it be the same on the other end. Easy to disable like any client-side JS, but once again makes it a little harder to make a toolkit.

So. As you see, it is probably not worth it to go this route. It is hard. Requires a lot of really silly coding practices to do, and is ultimately still relatively easy to defeat. You'll need to do all the calculations server-side to prevent cheating. Or let go, and accept that cheating will happen.

\$\endgroup\$
2
  • \$\begingroup\$ The line rider example is actually quite trivial to do server-side, by letting the user upload the map he/she has drawn and calculate the score. But games like arcades are nigh impossible to calculate the score server-side without extensive work. \$\endgroup\$
    – orlp
    Sep 21, 2012 at 12:13
  • \$\begingroup\$ @nightcracker You are correct, however even with something like Line Rider, if you only check after the game is done, the video has been made and the YouTubes already duped. You should upload the map when the user goes to hit play, calculate the path which is trivial, and then send that back. The game shouldn't be capable of calculating the path. (If we are talking about making it cheat proof, which that game is not. It is just simple enough that cheating is obvious to its fans.) \$\endgroup\$
    – DampeS8N
    Sep 21, 2012 at 12:51
15
\$\begingroup\$

I already answered a question like that here, and I'm sorry to tell but:

I wouldn't bother to make some server side simple checking, but I don't want to go the Diablo 3 path keeping all my game state changes on the server side.

Is the baddest thing you could have say here. If you wanna do an "anti-cheat" engine, you'll have to do that. You can add anything you want client-side, to facilitate the server-side work, but you must never trust the client. All Logic you have must be at least server-side. You can reproduce it client-side if you want, but no client-side only solution will do it.

And by the way, if you wanna find the weakness of your program, don't obfuscate it, let people see your code and tell you "here, you have an issue".

That's good for you, for your code, for your users and for the community.

\$\endgroup\$
6
  • 4
    \$\begingroup\$ +1 for Server authority, it just doesn't work if you try to trust the client... \$\endgroup\$
    – Valmond
    Sep 20, 2012 at 14:55
  • \$\begingroup\$ It is dangerous to reproduce things client-side. Be careful with even that, because if everything is replicated client-side, the user can cheat by disconnecting the checks with the server. They can then play the game, record a video, and become a YouTube star. This is only applicable to single-player games, which this game will be. \$\endgroup\$
    – DampeS8N
    Sep 20, 2012 at 15:05
  • \$\begingroup\$ When I talk about client-side, it's for "movements calculation", "collisions" etc... This can be done both sides even for a multiplayer game. The server-side calculations must always be considered prioritary, but this can help when there is server latency to also have it client-side. But for everything that is "check cheat" logic, then I agree that everything should be server-side. \$\endgroup\$
    – dievardump
    Sep 20, 2012 at 15:14
  • \$\begingroup\$ Yeah, I got that. But I'm doing the project as a hobby in the little free-time that I have. Doing that kind of server checking would the complexity of the project by a lot, making it nonviable. Well, I'll keep moving with the project knowing that, and if it start to get bigger and serious than I could come up with some serious server side controlling, probably with Node.js. \$\endgroup\$ Sep 20, 2012 at 17:33
  • \$\begingroup\$ this is more appropriate answer to OP \$\endgroup\$ Sep 21, 2012 at 12:14
3
\$\begingroup\$

Well, a good place to start is to use the Object.freeze function (which will enable protection against object patching).

This "prevents new properties from being added", "prevents existing properties from being removed", "prevents existing properties, or their enumerability, configurability, or writability, from being changed"; any changes to the internal state should be done through accessors. The following example works on chrome (should work on firefox, I dont know about IE though...):

var b = {}
// Fill your object with whatever you want
b.a = "ewq"
// Freeze all changes
Object.freeze(b)
// Try to put new value. This wont throw any error, put wont work either, 
// as we shall see ...
b.b = "qwe"

// Values 
console.log(b.a); // outputs "eqw"
console.log(b.b); // outputs  undefined
\$\endgroup\$
4
  • 5
    \$\begingroup\$ Even this will only slow a determined cheater down. If nothing else he can steal the source, host it on his own machine, and remove the freeze code, and then use his hosts file to trick his browser into thinking the new page is the old one, reconnecting it with the server. \$\endgroup\$
    – DampeS8N
    Sep 20, 2012 at 14:58
  • \$\begingroup\$ @DampeS8N Yes, I guess you're right. \$\endgroup\$
    – fableal
    Sep 20, 2012 at 15:16
  • \$\begingroup\$ Like I said in the OP, I just want some level of protection. \$\endgroup\$ Sep 20, 2012 at 17:36
  • 1
    \$\begingroup\$ This won't help at all! The user can just set a debugger breakpoint in the first JS function which gets executed and enter Object.freeze = function(o) {}; in the JS console. \$\endgroup\$
    – Philipp
    Jul 22, 2018 at 9:25
2
\$\begingroup\$

unfortunately, you have to go the diablo 3 path, if you are really concerned about hacks/cheats. if you are not, then basic checks you must do or its strongly advised to do.

  • buy checks - If I am buying something, I should have enough gold
  • sellchecks - If I am selling something, I need to have that item in my inventory trade checks - same as sell weapon
  • equip checks - If I am equipping a weapon, do i have/own it?
  • damage checks - If I am attacking something (enemy), I can't hit more than the maximum damage my weapon could(here you should not expect the client to tell which weapon he has used because it should have been persisted earlier)
  • crafting checks - If I crafted something, do I have all ingredients/components required?

... and so on

1 point is little bit tricky is the hero's position, since you are not much worried about it you can leave it, but its better you do that too with a minimum check like one below

  • I am at place1 @ T1, I am at place2 T2, what is the minimum time it takes to travel from place1 to place2 and it matches my T2 - T1. You can have mapping of this from small to large depending on the map size. You should have list of at least major areas like, NPC - boss, NPC - enemy spawn area (not necessarily exact location)

Hope this helps, it sounds difficult but you need to learn to make real working games

\$\endgroup\$
1
  • \$\begingroup\$ Great answer! I was writing a question on how to implement server checking, just to measure roughly how hard it is to implement server checking. You see, I don't wanna waste dozens of hours implementing a MMO-like backbone and at the end of the day it's still easily cheatable just by overriding some client request parameter or something like that. Or simply overdo what was supposed to be a simply fun game -waste effort on security instead of delivering more cool features or polish things. \$\endgroup\$ Sep 21, 2012 at 13:12
1
\$\begingroup\$

Its basically not possible. It would be so easy to work around anything you put in place to prevent cheating.

The thing is with any software you distribute people can modify it in memory easily.

Besides if they want to cheat, let them. They're just ruining the game for themselves. There's no real practical use to cheat in this situation, you'd just destroy the gameplay for yourself.

\$\endgroup\$
1
\$\begingroup\$

I had an idea for a measure you could take to prevent/reduce cheating (in addition to other answers). You could have it set up so that the client is not given all the source code at one time, rather that every time the client wants to, say, purchase a new item in the store, that the client would have to send certain information to the server, and only recieve all the information for whatever they are purchasing if the information all matches up with what it's supposed to. If it doesn't, the server blacklists their IP or something.

You could use this in conjunction with what Dampes8n said about using different source versions, that if you can figure out a way to generate a lot of different versions, so that each user would be running an entirely different source version each time, that failing the check blacklists that source version, too, that it won't ever give out the correct item info for that source version ever again.

The main reason this would be effective is that if a hacker doesn't get the hack right the first time, this would make it much harder for them to modify the hack, because every time the hack doesn't work perfectly, they have to change their IP and write the hack all over again for the new source version.

\$\endgroup\$
2
  • \$\begingroup\$ I'd be careful. The last thing you want to do is accidentally perma-ban a paying customer. \$\endgroup\$ Sep 24, 2012 at 19:36
  • \$\begingroup\$ @JohnMcDonald True, that. Perhaps just killing that source version. That way if they accidentally trigger the trap, they just have to refresh the browser, while still making hackers recode all their hacks. \$\endgroup\$ Sep 24, 2012 at 19:59
0
\$\begingroup\$

Yes, it can't fully be done. Always have check on the server. Anything that has an impact on the game should require authorization from the server.

That is the extend to which I will repeat other answers.

However, we can do a lot more towards the end of preventing cheats than just checking on the server. Well, we might have to add some special server checks. However, be aware that client side checks are not worthless, they save bandwidth and server work when cheaters are not involved.

With that said:

  • Mitigate rough clients: Serve over HTTPS, use Cross-origin resource sharing (CORS), allow only the same origin, use subresource integrity. I suggest to implement a service worker to enforce it on all requests, which will also mean that the game won't work by simply moving it to HTTP (because without HTTPS there is no service worker, the server worker is doing the client part of CORS and the server expects CORS), and if they serve over HTTPS it won't work because the server will reject the other origin.
  • Mitigate scripting: Use authentication and require a token to do any action. Each update cycle the server should give the client a new token, and the token is consumed by doing whatever it does... doing anything requires a valid token, the token is always changing, and thus not viable to guess, and if the client sends the same token twice or sends a wrong token the server knows that something is up. For extra protection: create a Message authentication code (MAC) of the token with a secret key and add it to te cookie. Modifying the cookie will kill the session (and they need to guess the key), and modifying the token will make the MAC check fail.
  • Mitigate code modifications: Aside from subresource integrity (which modern browsers will also check in runtime), keep your variables under a limited scope (using let, self executing anonymous functions, and javascript modules). Also, not rely on the DOM (the DOM is for IO only, not storage, if you need to attach attributes wrap your DOM objects and add them to wrappers). This way, whatever you on console should not be able to reach game logic (unless you exploit some browser vulnerability). You might also consider using techniques to detect developer tools (these are specific per browser, and may not work in all cases or stop working in the future... thus, this is an arms race).
  • Something is up? Did the session break? Kick the player from the current match, request to login again. Consider a captcha... that also has the benefit of telling the user that "we know something rare is going on" (it was not a random server failure), and yes, that is a form of mitigation. Oh, and do not foget to log these. You need to be able to verify why they happened, both to prevent false postives and to answer support tickets.

Yes, this are all mitigations. We can still have a custom made browser that will not check integrity and let you reach and mess with variables in local scopes... then the game code will send the modified data with the right token, and that is where the server checks come into play.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .