Say I have a JavaScript game and i want to upload the persons high score to my database to have a leaderbord or highscores. How would you prevent a user from cheating and manually changing the score value in JavaScript before I save the score in the database?
Javascript is executed in a user's browser, therefore there is no way to prevent the user from tampering with your code. Use a server-side programming language to manage the score.
One way I would do it is to send all user actions to your server, in real time or within the final value. This way you can compute the score based on that server side and validate it. I'm assuming you've got a way to simulate a game based on the actions log.
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.
Lets assume I have a Form which has 3 input fields:
gross amount
value added tax rate
net amount
The user can fill out the gross amount and the value added tax rate field. The net amount field is set readonly.
Now I want to save time and increase permformance by let javascript calculate the net amount and fill the required field and pass this value to the database.
The only thing I would check is if the net amount field is empty e.g. with Symfony NotBlank constraint.
Is this bad or bad practice to take the javascript calculated values?
Never trust the user. Do everything you can on serverside, even if you've already done it on clientside - especially not a trivially simple calculation like that that will not save you almost any time on serverside.
EDIT: Unless, as Sharky says, you don't actually care about the two other values, and are providing the calculation only as a courtesy to the user. In this case, net value is the real input field - even if it is technically readonly. Validate it and store it as such, and don't even bother transmitting the other two.
There are three dangers here:
Malicious code injection
This occurs by displaying something a user entered directly back onto the screen or another screen where the user has tampered with the data. For example, a user is asked for their name and types <script>alert('You got hacked!');</script> instead of their name. Every user that views their profile will see this code, and if you don't check, it is possible it will execute it on every person's machine that looks.
This would happen if you had a page in the system that displayed the user entered data back without checking it first, in your case perhaps a page that displays the current values from the database.
You can avoid this situation by sanitising what the user types in, or by checking it on the way out of the database.
For your situation though, if you store the values in the database as numbers instead of strings, then you won't have a problem.
Manipulating values in javascript
You have a much bigger problem though, and that is that you should perform calcuations on the server side. It is possible for the user to manipulate the value of the net amount and send anything they want to the database.
If a user is buying something from an online store, for example, and they add 5 items to their basket costing £1.00 each, then if you calculate the total in javascript (£5.00) and submit and store that, it is possible for the user to edit it and change the total to £0 and get the items for free.
For security you should of course calculate the cost on the server, and use values that you personally retrieve from the database - don't re-use any data sent from the user in the backend because they could also edit the individual item cost to £0 as well.
Javascript number accuracy
Just as a bonus, you should also be aware that your front end and back end may calculate values differently when you're adding and multiplying numbers together. Consider this code:
var total = 0.3 - 0.2;
If you expect total to be 0.1, you're wrong - the answer is something like 0.99999999998.
Javascript doesn't handle floating point numbers very accurately.
In other words, what technology would take care of doing the time tracking? Would it be the JavaScript? I don't see being able to keep track of such things with PHP.
Here's what I need to accomplish:
I need to have a long form spanning many web page reloads because it is pretty much an online test where each page load displays a new question. However, the entire form, which constitutes one test has a time limit. When the time expires if the user in question has not completed the test then he/she cannot submit a partially completed test nor attempt to do the entire test all over again within the same day (either calendar date or with 12/24 hours in between.) The user may, however, comeback the next day and attempt to finish the entire test again within the allotted time. I know I have added a lot of details and I did this just to show context, nevertheless, the main difficulty for me would be in how accomplish the time expiry feature. That is, somehow, within a series of pages that make up a form representing an online test I want to track the time starting from the first question (one page load) and upon time expiry for the test to be disabled.
Has anyone ever done this? Would anyone have any tips for me on how to accomplish this?
Any advice I can get would totally be appreciated in advance.
If you do track time on client-side - always validate it on the server-side.
Never trust the client, by itself, to validate the time. As mentioned in the comments, client-side time validation is only good for cosmetic features, never for actual validation.
The easiest way to accomplish this is to add a unique token to the form (which is not spoofable) on first navigation. Cookies, or any other sort of session management technique you get from your framework will suffice.
On form submission you can first validate this on client side and return an error if time has passed, even before actually sending the form. If successful, submit the form, and make sure you validate the token upon processing on the server.
There are two ways you could measure the "time they spent" on the form.
When the first page of the form is severed, in the PHP create a session variable containing the date. When they finish the form, you subtract the current date form the beginning date. This gives you the total time it took from when the form was served and finished. However, this is not 100% accurate as there could downtime for other reasons such as slow internet.
You could have JavaScript record the time on that page (I answered how to do that here: here) Using AJAX, this time could be sent that way or by using GET posts. The time would then be kept by PHP somehow and added up in the end.
Hope this helps! Just ask if you want an example.
In the most general terms, you'll need to set up a session on the server side to track each user and test. When the user begins the test, you stamp a variable (server side) with the test start time. As the user progresses through the test and requests additional pages, check whether the difference between the current time and that variable have exceeded the time allowed for the test. If the test has expired, instead of delivering the next test page, you can close up the test and deliver a "time's up" page to the user.
I don't know what server-side environment you're using, but it almost certainly has some sort of session management framework available. To reliably control the testing environment, you have to manage this from the server side.
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.
In my JavaScript game (made with jQuery) I have player position stored in a database. When character is moving, i just send request to specyfic URL, I.E. mysite.com/map/x1/y3 (where a character's position is x=1, y=3).
That url send coordinates to the database and checks to see if any other players are near ours. If yes, it sends also JSON object with name and coords of that players.
And here is my question - how to secure it? Some one could look into my JavaScript code and prepare url looking like mysite.com/map/x100/y234, and it will 'teleport' him into some other side of map.
Any data/computation processed in JavaScript in the browser will be insecure since all the code runs on the local machine. I would recommend to list all the parameters critical to a fair experience of play, such as the player position, score, resources... and compute the management of these parameters on the server-side. You would only gather user inputs from the browser and send the updated state to the browser for display.
Even if you choose to compute some values on the browser side to avoid latency, you should not take them into account for the global state shared by players, and you should resynchronize the local state with the global state - always in the direction global to local - from time to time.
Like in a typical form handling, you should also check that the values sent by the browser for user inputs fall into reasonable bounds, e.g. relative movement in one second is less than a certain distance.
You could obfuscate your javascript source code. That will at least deter casual cheats, however there's probably no way to make it completely secure using javascript.