Any player can easily cheat on this game by changing the amount of cupcakes through the browser console. I wanted to know if there was a way to prevent the user from doing so. This is also posted on github.
var numberOfCupcakesDisplay = document.getElementById("numberOfCupcakes");
var cupcake = document.getElementById("cupcake");
function updateValues() {
numberOfCupcakesDisplay.innerHTML = amountOfCupcakes.toString();
//displays number of cupcakes to screen
document.getElementById("amountOfToasters").innerHTML = amountOfToasters.toString();
//displays number of toasters to screen
document.getElementById("toasterButton").innerHTML = "        " + Math.round(costOfToasters).toString() + " cc";
//changes cost of toaster every time it is bought by 110%
}
cupcake.addEventListener('webkitAnimationEnd', function(e){
e.preventDefault();
this.style.webkitAnimationName = '';
}, false);
function clickCupcake() {
++amountOfCupcakes;
cupcake.style.animation = "shiftCupcake";
cupcake.style.webkitAnimationName = "shiftCupcake";
}
updateValues();
Yeah!! As other answers mention it is IMPOSSIBLE to prevent users from changing the values from browser console. In other words, You are simply asking How to write JS code so that user can not debug it. You can always use some methods which make life hard for people who want to cheat on the game.
1.Obfuscate the code.
Look at these links for more information on obfuscation.
SO: How to obfuscate Javascript
Jsobfuscate.com
2.Do not store the game's control values in global variable.
Do not store control values in global variables. Instead define a class and have these variables as private to it So that user has to dig in deep in order to find out where to put the breakpoints.
3.Minify/Compress your javascripts.
Obfuscation more or less covers minification as well.
You cannot prevent this. The best you can do is minify the JS so it's harder for players to find the right values to change. In fact, you can't prevent this with any game or indeed application; the user's computer controls all of the information so they can do anything they want to it.
The only way to be secure against this is to do all of the processing on a server you control. Even though, players can lie about their input data (hence aimbotting or other hacks).
by changing the amount of cupcakes through the browser console
Well, technically you can prevent this by creating a new scope:
(function(){
var cupcakes = 10;
})();
console.log(cupcakes); // ReferenceError: cupcakes is not defined
But note that there are still ways to "cheat," even with this protection (i.e. edit the JS source code). And if you are sending the result to a server... well, that will be even harder if not impossible to secure, since you can easily send a simple HTTP request via XMLHttpRequest.
There may actually be a way to reach your goal. But it depends on the game's logic.
If you can simulate the game on your server, you can generate random IDs for the cakes and when the game creates a new cake (on client), it would request an ID for it. Later when the cake is "destroyed", it would contact the server and provide it with the cake's ID. The final score is then computed on the server from the IDs it received.
This way you can track what was actually done by the user.
But an adversary can listen the network requests and determine the request for creating a new ID. The same way he can determine the request to tell the server this ID has been "destroyed".
If your game logic allows, you can e.g. tell the server to only generate one ID every 5 seconds or so. You can also mark as spoofed all results where all cakes were "destroyed" and none was missed (if the game is difficult enough).
So, it's still not 100% secure, but you might be able to reach a relatively high level of spoofing protection. On the other hand, it adds a lot of code complications and you must weigh the pros and cons.
Related
I have a game with a worldwide highscore feature. It uses the firebase database, and writes the user's score if it is the highscore. The rules state that anyone can read or write, so other people can view the highscore.
My problem is that it's easy to manipulate the highscore without actually getting a score. How can I make it so when you achieve a new highscore, it is written to the database, but if you go into the console and change the data, it won't allow you to change it?
if (score > worldScore) {
database.ref().update({highscore: score});
}
You can see that it is very easy to change the data.
In the Firebase console, there is never any restrictions on what you can read or write in the database. Security rules never apply there.
Strictly speaking, unless you involve some serverside component that can one way or another confirm the score was achieved legitimately, this is not possible. Clientside data is always subject to user manipulation; any confirmation checks on that data which you perform on the client would also be subject to user manipulation.
(As for how to actually perform that serverside confirmation: it'll depend on the details of the game, but one way might be to have the client periodically send significant game data to the server; if the server can determine that any of the data has changed in ways that should be impossible according to the game rules -- like a score jumping too far in too short a period of time -- then ignore any future score submissions from that user. Even this isn't perfect: the user can still cheat by manipulating the data that gets sent in that periodic poll, but they'd have to keep their changes at least within the bounds of plausibility.)
Typically you'll want to store not just the score, but also the way the player achieved that score. For example: if it is a board game, write their moves in addition tot he result. If you have both you can:
Verify that the score they wrote is indeed the score that is gotten by applying the moves.
Perform some analysis to detect if the moves seem likely to be computer generated.
Both of these processes are cases of "trusted code", i.e. code that should be running in a trusted environment. For this you can use either an environment you control (a private server, your laptop, etc), Cloud Functions for Firebase, or (in some cases) Firebase's server side security rules. Which ones are feasible depends on your exact use-case, and your available time.
Suppose you are designing a PC game that keeps track of high scores. In addition to keeping local scores, a global high score server is set up that is accessed by the game over the internet. Players should be able to submit their high scores to the global high score list right after they have completed a game, or later, from their local high score list. This must be a common problem; arcade games on modern game consoles often feature a global high score list that works like this.
My question boils down to: how can you prevent someone from submitting bogus high scores? Or, stated another way, how can the global high score server be sure that a submitted score was really produced by a run through the game?
The more I thought about this, the more I think it may be an unsolvable problem.
What you'd commonly do to verify that a message originated from a certain source is have the source digitally sign the message. You could certainly do that in this case, but the real problem is that the player, by having the software, also has the software's private key. No matter how obfuscated it might be, it can be reverse engineered, or even just plucked from memory.
Another option would be to send along a replay of the player's game to the high score server, which would quickly run the replay and verify that the submitted score matches the outcome of the replay. This doesn't solve the problem, but it certainly makes it more difficult to forge a bogus high score if you also have to produce a very complex replay that "proves" it.
Is this a problem that has a solution, or is it really unsolvable? Are there techniques used by the home game console developers to prevent this sort of exploit, or do they simply rely on the console preventing unauthorized code from running?
For a PC game where the score is generated by the client, this is not a solvable problem since the client is inherently untrustworthy.
The only thing you can try to do is make it harder for someone to submit a fake score.
Some thoughts:
Protect the in-memory score.
You can use API's like CryptProtectMemory to hide the score in memory - a simple memory write will not work. However, with an attached debugger or via injecting code into your process, they could still modify the score. You can look into various schemes for trying to defeat debuggers.
Protect the score en-route to the server.
You can encrypt the data being sent to the service, as you suggest, but since the untrusted party has control over the key, this is merely obfuscation and offers no solid protection.
Validate the score at the service.
I'd be loathe to do this, beyond very simple checks. A bug here will result in you rejecting valid scores. It'll be impossible to distinguish between cheaters and strong players.
At this point, you really have to ask your self if the engineering effort is really worth it. What if someone posts an invalid score? What do you actually lose? I would do the bare minimum to protect against a kid with a simple script. I.e., don't have your score submission be just:
http://myservice.com/submitscore.aspx?PlayerName=Michael&Score=999999999
I would just use simple protection in memory against casual snoops, some simple obfuscation on the wire (hash the score with a server cookie) and be done.
To my knowledge, this is unsolvable.
I have seen many people try to obfuscate the encryption key. I have seen a few people include other sanity checks like time elapsed, or enemies remaining. I have never seen one that sends a replay, though of course it is possible.
In a website that will remain unamed, they setup a fake send high score routine that is easily found. If a perpetrator uses it, their IP address will be automatically banned from future updates.
"Another option would be to send along a replay of the player's game ... This doesn't solve the problem, "
Really? Why not?
"you also have to produce a very complex replay that "proves" [the score]."
Are you suggesting someone could fake the replay? Reason out a super-high-score solution without actually playing the game? Fake the timestamps and everything? Pull a Donald Crowhurst?
Why not just play the game rather than attempt to fake a log of playing the game?
Or... if it's that easy to fake a history of game play that leads to a super high score, perhaps the game is misdesigned. If the game is "hard", the person must make all the right choices. If the game is easy, then the score doesn't reflect the player's choices and is fakable.
Think of it this way. Pick any game or sport. Someone says that -- say -- Switzerland beat New Zealand in a yacht race. You would challenge them by seeking substantiating details on the venue, the boats, the teams and the individual races to convince yourself it was true. Certainly, they could fake it, but if they've got a rich set of details covering the race, then... how's that not "proof"?
Forget the cryptogaphic issue; if your code can be hacked on the local machine, how do you keep someone from setting a crazy high score artificially and then transmitting it using the existing trusted mechanism?
Until you can establish trust in the code itself, a crypto mechanism for the communications isn't going to be the real problem.
Send the hash of the (software + a random salt) along with the score. Check this hash with the server. If it matches (meaning that the software is unaltered) accept it. Otherwise, the score comes from a "modded" version of the game. Reject it. The random salt should change every time the hash is generated (current sys time or something like that)
Check Quake III Arena source code. Their version was quite fool proof. Unfortunately, I don't remember the link now.
Let's say I'm making an HTML5 game using JavaScript and the <canvas> The varaibles are stored in the DOM such as level, exp, current_map, and the like.
Obviously, they can be edited client-side using Firebug. What would I have to do to maximize security, so it would be really hard to edit (and cheat)?
Don't store the variables in the DOM if you wish a reasonable level of security. JavaScript, even if obfuscated, can easily be reverse engineered. That defeats any local encryption mechanisms.
Store key variables server-side and use https to maximize security. Even so, the client code (JavaScript) is quite vulnerable to hacking.
You can use Object.freeze or a polyfill or a framework which does the hiding for you.
Check out http://netjs.codeplex.com/
You could also optionally implement some type of signing system but nothing is really impenetrable. For instance objects locked with Object.freeze or Object.watch can still be manually modified in memory.
What are you really trying to accomplish in the end?
What you could do is send a representation of the matrix of the game or the game itself or a special hash or a combination of both and tally the score at the server... causing the user to not only have to modify the score but to correctly modify the state of the game.
Server-side game logic
You need to keep the sensitive data on the server and a local copy on the browser for display purposes only. Then for every action that changes these values the server should be the one responsible for verifying them. For example if the player needs to solve a puzzle you should never verify the solution client side, but take for example the hash value of the ordered pieces represented as a string and send it to the server to verify that the hash value is correct. Then increase the xp/level of the player and send the information back to the client.
Anything that is living in the client can be modified. That is because in MMORPG the character's data is living on the server, so players can't hack their characters using any memory tools, hex editor, etc (they actually "can", but because the server keep the correct version of the character's data is useless).
A good example was Diablo 2: you have actually two different characters: one for single player (and Network playing with other players where one was the server), and one for Battle.net. In the first case, people could "hack" the character's level and points just editing the memory on the fly or the character file with an hex editor. But that wasn't possible with the character you was using on Battle.net.
Another simple example could be a quiz where you have a limited time to answer. If you handle everything on client side, players could hack it and modify the elapsed time and always get the best score: so you need to store the timestamp on the server as well, and use that value as comparison when you get the answer.
To sum up, it doesn't matter if it's JavaScript, C++ or Assembly: the rule is always "Don't rely on client". If you need security for you game data, you have to use something where the clients have no access: the server.
Thanks to the recent browsers enhancements, developing games with canvas and javascript has become a good option, but now that the code is easily accessible, just writing
javascript:score=99999
or
javascript:lives=99
Will spoil the game objectives.
I know that with some server-side checking something can be done, but I would prefer to access the server just to store player stats at the end, or even have it client only in most cases.
I wonder if at least the are some best pratices to start with.
(using not so obvious variables names is a start, but not enough)
-Added-
Thanks for the replies, I was looking to improve the client-side code, enough to stop "casual hackers", but still leaving the code as clean as possible.
Anyone that really wants to hack it will succeed anyway, even with server-side checks, as I've seen it in many flash games.
I'll say what I said at my comment: put every source code in (function(){ }());. Then, the variables and functions can't be accessed from outside.
Example:
(function(){
var a = 'Foo';
var b = 42;
function helloWorld(a,b){
for(i=0;i<b;i++)console.log(a);
}
helloWorld(a,b);
});
//Can't access to a, b, or helloWorld using javascript: or default console of Google Chrome,
//but people still can see by looking source code and may be modified by other tools
//(see comments of Tom & user120242)
I 'learned' this technique this when I dig into Les Paul Google Doodle.
To be more secure (not completely secure, but it'll annoy some hackers), compress and obfuscate your script by tools something like YUI compressor or packer.
One way is to send a record of every move to the server as well, then to verify that those moves would have got that score.
That's easy for games like solitaire or chess, but not really for more complex games.
A simpler version of that is to work out the max points that could be obtained per second, or per move, then to verify that the score isn't higher than your theoretical maximum.
Another way is for each move to be recorded on the server, and to total up the score there. That means there is no send at the end of the game, and that those variables are only for display, not the real score.
Offline games could be starred on the highscore table or something to show they aren't verified.
It's worth pointing out that with any javascript debugger, such as the Inspector in Webkit, Firebug for Firefox or Dragonfly on Opera it's trivial to change the value of variables on the client side, even if your code is in a closure. Any form of obfuscation is pointless, as again it's easy to watch which variable corresponds to the score as the game is played, and any encoding or whatever can simply be read out of the code.
In order of preference:
Send player moves or statistics to server. Prevent strange behavior.
eg: Score too high, invalid actions, actions that cannot be replayed, etc
Prevent strange behavior on client-side. Same as above but not on server. eg: sudden lives changed, moving too fast, etc
Create obfuscated JS output (which you should be doing to reduce JS size anyways) eg: GWT (Java to JS compiler), Google Closure Compiler (ADVANCED_OPTIMIZATIONS will obfuscate more, --output-wrapper (function(){%output%})() to wrap in closure), Yahoo Compressor
Obfuscate variable values eg: Encode strings (xor, substitution, BASE64), don't use normal variable increments
Use a closure to encapsulate variable names: (function(){code here})()
EDIT: I want to make clear that the best solution is still to move calculations to the server, as Rich Bradshaw had said. These things can only do so much, even after you obfuscate the code.
Here's a link that also applies to your Javascript game, and I think is probably the best possible answer to your question: What is the best way to stop people hacking the PHP-based highscore table of a Flash game
The most important idea to get from that link is:
The objective isn't to stop this
attack; it's to make the attack more
expensive than just getting really
good at the game and beating it.
I'm implementing a simple game in Javascript, and am interested in having an online highscores table for it, so that players can compete against one another. I've two concerns about this:
What is the simplest server-side program I need for this purpose? I don't need a full-fledged "web application", just something simple that gets POST requests with highscores, updates a database and sends back lists of scores. I'm familiar with Django. What are your suggestions?
How can I make the highscores table reasonably secure? I'm aware that making it bulletproof against competent and dedicated hackers is difficult, but I wouldn't want anyone with access to the Javascript sourcecode to be able to submit fictitious scores too simply. Any tools for this purpose?
It's going to be pretty hard to secure the high scores. I mean, it's not enough to ensure that it comes from your page, because if, say, the JavaScript function is submitHighScore(n) then they can always type javascript:submitHighScore(10000000) in the address bar on that page and have it work.
What comes to mind is perhaps some sort of hash function that generates specific codes that match certain levels in the game. When submitting the score it would also submit this hash, so users would have had to get to this level in order to get that equivalent score.
Another option would be for the game to pull in some kind of key that only works temporarily, so as you went along the key would change and then the score would be submitted to a central server intermittently.
Keep in mind that really determined individuals can always just track the data being sent to your data and decompile it.
You could go the Broderbund route and ask the player trivia questions which are validated server-side to ensure they really did pass the level they said they did...something like "What color was the monster in the previous level?"
To submit score securely, sign it (you'd also need to ensure that the score isn't faked before it's signed and sent, but that's another problem).
Hide a secret in JS code, and send highscore + hash(highscore + secret) to the server. The hash could be MD5/SHA1 — there are easy to find JS implementations.
Of course it won't stand anyone carefully analysing the JS code, but at least someone won't be able to submit fake highscore just by tampering with HTTP traffic.
On hiding stuff in JS:
You can't really hide it (it's ultimately futile like DRM), but you can try hard to obfuscate it and make debugging painful.
Don't put the secret as a literal in the source code - compute it at run time combining results of several functions, local and global-ish variables.
Minify all code, remove sourcemaps.
Add bits of code that don't do anything, but seem to be important, to make debugging more confusing.
Don't put anything in global scope, but do rely on shared mutable state by passing closures and arrays around.
Rely on Date and timers to cause race conditions to make your code produce wrong results if it's paused in the debugger (just don't make it too tight to allow it to run on slow machines).
If the game is deterministic (like a puzzle game), then users could submit highscore in form of a log of steps taken to win (user's input) that you'd replay on the server to calculate the score.
This would change attack from finding/emulating score-submitting function to witing AI or hacking the game itself to make it easier to play (but still within its basic rules).
1.) Any CGI script that can talk to a database and understand JSON, or other format of your choice, will do the work.
However, if you're familiar with Django, building your server on top of Django would be the most simple, in the sense of what you have to learn and how much application code you have to write. Seemingly simple CGI script can turn out rather complex if you write it from scratch.
I found django-piston to be a handy Django app to quickly write a REST-style API server. It supports JSON so it should be easy to interface with your JavaScript game.
2.) The most casual cracker will go for a replay attack and its variants: peek at the page source and execute a JavaScript function, intercept HTTP requests and resend it (should be easy with a Firefox add-on like Tamper Data).
To counteract the former, you can obfuscate the source code and HTTP body;
Minify the JavaScript code
Encode the message you send to the server with Base64 or other encoding algorithm
The latter can be prevented by requiring all update requests to include an one-time password ("session token" in the Wikipedia article) that was recently acquired from the server.
I am thinking about this myself. What seems to be the most reasonable solution to me is this:
1) Sessions, to disallow tampering with the scoretable outside the game.
2) Log every action in the game and send it to the score server. The server will then calculate if those actions actually give such score. If you also log the time spent playing the game, you can further minimize the chance of an attacker to bother himself enough to break your game. This will also enable you to make a replay script like Arcade servers with hi-score tables have and in case of a suspicious score, you can watch the replay and decide for yourself if the score is real. The cheater would have to use a clever bot to play your game - and unless you have a game for real prizes, noone will try that hard.
If the cheater won't even analyze your code, sessions will stop him. If he reads your code, he would quickly break anything similar to hashed scores, secrets, tokens and whatsoever. But if you make the game-logging script thorough enough, he will give up.
In answer to your question:
1.) This depends on your environment and coding preference. PHP, Python, ASP.NET are a few that come to mind. Sense you already know Python (from your profile) you can use a Python CGI script to do this or use one of the many frameworks for Python (Zope, Django, Pylons,...).
see: http://www.python.org/doc/essays/ppt/sd99east/index.htm
for info on Python CGI.
2.) A few tricks for security: (none or full-proof)
Hidden Text Box in HTML with encoded value that server checks to match a cookie to ensure high score comes from your page.
Server Script only accepts values from a specific domain
You could use a combination of one of the methods above, as well as simply requiring the user to be registered to be able to post high scores. Non registered users could view their current score compared to existing high scores, but in order to post your high score online, you must have already logged in with your registered account, or provide it when the app goes to update the score online.
A simple message along the lines of "Your high score is X, and ranks ### in the high score table. To post this score online, please register with us first".
The better I think, is to make the calculation of the score directly into the python files of your django app.
Instead of calculate it in the javascript file. You send the datas to compare with your data basis with a POST request, then you calculate the score and you store it in your data basis. Like this, you don't make circulate the score across the web to your servers. Which is completely safe because you are only doing local stuffs.