How to protect against Firebase Request Forgery? - javascript

If you use Firebase real time database in browser you need to share the API key so there are no way to protect the database. I have simple game (ASCII Tetris) that save the high score of the game, the problem is that anyone can spoof the request and send his own score. (here is screenshot of what one person did):
What are the solution to protect against this? I was thinking about doing the same as protection against CSRF where you create a token and validate if it's valid so only my code will have proper CSRF like token. The attacker would still be able to pause the app in debugger and check the token and send his own but this will require from him to know how to use debugger so it will be little bit harder to hack.
The firebase real time database have ".validate" rule where you can validate if token is valid (https://firebase.google.com/docs/database/security). I was also thinking of creating something like chain of checksums (like in git or block chain).
Do you think that something like this is possible to create? Do you know if there are better ways of protecting the firebase real time database for my case of saving scores? THe answer will probably be useful for other cases than simple case like mine for this simple game.

There's a surprising amount of complexity you can implement in Firebase's security rules. For example, I once saw rules that validated chess moves - pretty impressive.
Mostly I'd recommend storing enough information to replay what happened, so that you can check if the result is valid. My first Firebase game was a word typing game, so I'd store:
The seed of the game
Each keypress and its timestamp
The total score
This allows me to replay the game to check if I get the same result. But it also allows me to (in the future) write code that checks for irregular patterns in the keypresses. For example, my bots used to press a key at a very specific interval. Of course malicious users can easily make this more intelligent, but so can you improve your cheat detection code.
Such cheat detection code should of course never be present in the client, as that would give malicious users information you don't want them to have. So you'd run this code in a trusted environment, such as you development machine, a server you control, or Cloud Functions.
So my typical steps:
Store the exact moves of the user, and the seed of your PRNG, so that you can reproduce the exact game.
Use security rules to reject invalid moves as much as possible.
Use security rules to reject outcomes that are extremely unlikely, like scores higher than a certain amount (especially when you can tie it back to how long the game took).
Use server-side code to check if the moves the player made, lead to the result they got.
Consider quarantining unusually high scores, so you can validate them with a replay before posting them to the score board. This would be a combination of client-side code, and server-side security rules.
If you suspect abuse, inspect the list of moves. If this happens regularly, start automating this.
Welcome to the arms race of game developers vs malicious players. :)

Related

Prevent Cheating on Javascript Game

I'm currently developing a game using JavaScript/JQuery. It's a simple brick breaker type of game keeping score, levels etc. I'm planning on implementing a leader board that users can submit their final score to. The only problem I see with this is users manipulating the score using developer tools on most browsers. I understand that keeping things server side will resolve most of these issues, however if there is a high volume of users, it will hit my server hard with requests. Cookies - Easily changed client side. I'm honestly out of logical ideas to promote fair game play because there is ALWAYS people who seek to cheat/become top of the leader board. With that said, what's an efficient and effective way to keep track of the user's score without giving them access to changing it?
Make the page submit a complete replay of the game rather than just the final score. Given the random seed and a frame by frame record of user inputs, your server should be able to simulate and reconstruct the game and verify the score.
Obviously the replay can be faked too, but it would amount to so much work (actually playing the game and actually getting a good score, albeit with the unfair advantage of AI assistance, slowing down and other client hacks) that tool-assisted scores should deserve to be in the leaderboard.
Obfuscate their score by creating an equation that can only be calculated on the server side.
Edit: RobG is correct in that it will need to be calculated on the client side.
I hacked the Angry Birds game when it launched on chrome:
http://wesbos.com/all-levels-html5-angry-birds/
However, they have since obfuscated the code so much that its impossible to figure out which function calculates the hash..
You can't guarantee no cheating, it's impossible. The server responds to requests, that's it. It has no idea what code is running on the client, what type of user agent or environment it's in or even whether it's running your code or a facsimile.
You can take various steps to make spoofing more difficult, but you can't make it impossible. The cost of such measures (usually seen as "security") is usually balanced with the value of the asset being protected.
An idea I had was to use a game-timer. If the user changes the score to an amount that is obviously not possible given the amount of time that has passed, refuse to log the information. You could start the timer and check the timer in your server-side script.
Now of course if they change the score only by a few points this checking may fail, but, if they only add a less than impacting amount then maybe it won't matter to you as much?
Never put anything on the client. The client is in the hands of the
enemy. Never ever ever forget this.
-- The Laws of Online World Design
You could also make the leaderboard less important, by only sharing scores with 'trusted' friends. Or simply allowing people to share their score on any social networking site.
Maybe this removes the primary motivation to cheat in the first place.
You could then always compare the score implicitly with statistics you gathered, to tell if somebody is doing good or not.
Base64 encode your javascript page. That should stop people some people.
Link: http://www.opinionatedgeek.com/dotnet/tools/base64encode/

Computationally difficult [JavaScript] problem?

I need a problem that is computationally difficult (in any language), that I can easily implement in JavaScript. I'm trying to do a CAPTCHA-like test to make it unlikely that hacker is accessing my page mechanically.
Yes, I know that he could use Rhino or some other JS engine and do it -- that's why I want it to be computationally expensive, so it takes him a few hours to set up and his machine a few seconds to fake each access.
I'm think getting a bunch of large primes on the back end and sending over the product of two of them and demand that web-page factor it, but if anybody has a better idea, I'm all ears. Also, does anybody have a good library for doing that factoring thing?
You can use the same method as bitcoin, ie. reversing a secure hash.
Explained here:
http://www.tomshardware.com/reviews/bitcoin-mining-make-money,3514-3.html
Bitcoin source
https://github.com/bitcoin/bitcoin
you can implement a standard captcha and make some more checking on the client side. for exaample, add a event listener on the captcha input text to listen for key down/key up events and xor the keycodes and send them along with the captcha. add a hidden input text in the form named email or something you find on every form. robots fill those up automatically. and if you get a value for post['email'] then it's a robot because the user won't see that. also you can have a piece of code in a totally unrelated javascript that automatically adds a field in the form that is required to validate. so...captcha no captcha, you can still enhance the robot protection client side without computation difficult processes.
The problem with this is that if it is known to be NP-Hard, it's going to be a pain in the rear for human beings to solve, as well, on non-trivial instances. Visual/auditory captchas are kind of cool in that they give people a leg up... we have very sophisticated sensory organs for processing these kinds of things, and computers are not too good at it (though they are getting better all the time!).
As such, you're probably better off coming up with a unique thing that people can do very easily, but that machines are not too good at. For instance, give some simple black and white pictures and ask the user which one doesn't belong, or show some pictures of foods and ask what kind of recipe you could make with them.
Clever approach. Whenever one-way complexity is needed it makes me think of a hash. Simply hash some aspect of their user account (not anything sensitive) and send the hash to the client. You would want to truncate/pad the string to get your desired complexity level. This isn't to secure an account so md5 or any other hashing algorithm would be fine.
Here is some sample code that you might be able to leverage for the client side.

What good ways are there to prevent cheating in JavaScript multiplayer games?

Imagine a space shooter with a scrolling level. What methods are there for preventing a malicious player from modifying the game to their benefit? Things he could do that are hard to limit server-side is auto-aiming, peeking outside the visible area, speed hacking and other things.
What ways are there of preventing this? Assume that the server is any language and that the clients are connected via WebSocket.
Always assume that the code is 100% hackable. Think of ways to prevent a client completely rewritten (for the purposes of cheating) from cheating. These can be things such as methods for writing a secure game protocol, server-side detection, etc.
The server is king. Clients are hackable.
What you want to do is two things with your websocket.
Send game actions to the server and receive game state from the server.
You render the game state. and you send input to the server.
auto aiming - this one is hard to solve. You have to go for realism. If a user hits 10 headshots in 10ms then you kick him. Write a clever cheat detection algorithm.
peeking outside the visibile area - solved by only sending the visible area to each client
speeding hacking - solved by handling input correctly. You receive an event that user a moved forward and you control how fast he goes.
You can NOT solve these problems by minifying code. Code on the client is ONLY there to handle input and display output. ALL logic has to be done on the server.
You simply need to write server side validation . The only thing is that a game input is significantly harder to validate then form input due to complexity. It's the exact same thing you would do to make forms secure.
You need to be really careful with your "input is valid" detection though. You do not want to kick/ban highly skilled players from your game. It's very hard to hit the balance of too lax on bot detection and too strict on bot detection. The whole realm of bot detection is very hard overall. For example Quake had an auto aim detection that kicked legitedly skilled players back in the day.
As for stopping a bots from connecting to your websocket directly set up a seperate HTTP or HTTPS verification channel on your multiplayer game for added security. Use multiple Http/https/ws channels to validate a client as being "official", acting as some form of handshake. This will make connecting to the ws directly harder.
Example:
Think of a simple multiplayer game. A 2D room based racing game. Upto n users go on a flat 2D platformer map and race to get from A to B.
Let's say for arguments sake that you have a foolsafe system where there's a complex authetication going over a HTTPS channel so that users can not access your websocket channel directly and are forced to go through the browser. You might have a chrome extension that deals with the authentication and you force users to use that. This reduces the problem domain.
Your server is going to send all the visual data that the client needs to render the screen. You can not obscure this data away. No matter what you try a silled hacker can take your code and slow it down in the debugger editing it as he goes along until all he's left with is a primitive wrapper around your websocket. He let's you run the entire authentication but there is nothing you can do to stop him from stripping out any JavaScript you write from stopping him doing that. All you can achieve with that is limit the amount of hackers skilled enough of accessing your websocket.
So the hacker now has your websocket in a chrome sandbox. He sees the input. Of course your race course is dynamically and uniquely generated. If you had a set amount of them then the hacker could pre engineer the optimum race route. The data you send to visualise this map can be rendered faster then human interaction with your game and the optimum moves to win your racing game can be calculated and send to your server.
If you were to try and ban players who reacted too fast to your map data and call them bots then the hacker adjusts this and adds a delay. If you try and ban players who play too perfectly then the hacker adjusts this and plays less then perfect using random numbers. If you place traps in your map that only algorithmic bots fall into then they can be avoided by learning about them, through trial and error or a machine learning algorithm. There is nothing you can do to be absolutely secure.
You have only ONE option to absolutely avoid hackers. That is to build your own browser which cannot be hacked. Build the security mechanisms into the browser. Do not allow users to edit javascript at runtime in realtime.
At the server-side, there are 2 options:
1) Full server-side game
Each client sends their "actions" to the server. The server executes them and sends relevant data back. e.g. a ship wants to move north, the server calculates its new position and sends it back. The server also sends a list of visible ships (solving maphacks), etcetera.
2) Full client-side game
Each client still sends their actions to the server. But to reduce workload on the server, the server doesn't execute the actions but forwards them to all other clients. The clients then resolve all actions simultaneously. As a result, each client should end up with an identical game. Periodically, each client sends their absolute data (ship positions, etc.) to the server and the server checks if all client data is identical. Otherwise, the games are out of sync and someone must be hacking.
Disadvantage of the second method is that some hacks remain undetected: A maphack for example. A cheater could inject code so he sees everything, but still only sends the data he should normally be able to see to the server.
--
At the client-side, there is 1 option:
A javascript component that scans the game code to see if anything has been modified (e.g. code modified to render objects that aren't visible but send different validation data to the server).
Obviously, a hacker could easily disable this component. To fix that, you could force the client to periodically reload the component from the server (The server can check if the script file was requested by the user periodically). This introduces a new problem: the hacker simply periodically requests the component via AJAX but prevents it from running. To avoid that: have the component redownload itself, but a slightly modified version of itself.
For example: have the component be located at yoursite/cheatdetect.js?control=5.
The server will generate a slightly modified cheatdetect.js so that in the next iteration, cheatdetect.js?control=22 (for example) must be downloaded. If the control mechanism is sufficiently complicated, the hacker won't be able to predict which control number to request next, and cheatdetect.js must be executed in order to continue the game.
There's nothing you can really do to prevent anyone from modifying your JS or writing a GreaseMonkey script. However you can make it hard for them by minifying your script as well as making your code as cryptic as possible. Maybe even throwing in some fake methods or variables that do nothing but are used to throw an attacker off. But given enough time, none of these methods are completely foolproof, as once your code goes to the client, it is no longer yours.
The only way I can even think of implementing this is by modifying your Javascript to function as a client and then designing a central server mechanism to validate data sent from that client. This is probably a big change to implement and will most likely make your project more complex. However, as was said earlier, if the application runs entirely on the client, the client can pretty much do whatever they want with your script. The only way to secure it to use a trusted machine to handle validation.
They don't have to touch your client-side code -- they could just sniff and implement your Websocket protocol and write a tiny agent that pretends to be a human player.
Update: The problem has a few parts, and I don't have answers off the top of my head, but the various options could be evaluated with these questions in mind:
How far are you willing to go to prevent cheating? If you only care about casual cheating, how many barriers are enough to discourage the casual cheater? The intermediate Javascript programmer? A serious expert? Weighing this against the benefits of cheating, is there anything of real value at stake, like cash and prizes, or just reputation?
How do you get a high confidence that a human is providing inputs to your game? For example, with a good enough computer vision library I could model your game on a separate machine feed inputs to the computer pretending to be the mouse, but this has a high relative cost (not worth my time).
How can you create a chain of trust in your protocol such that knowledge of (2) can be passed to the server, and that your server is relatively confident your client code is sending the messages?
Sure many of the roadblocks you throw up can be side-stepped, but what is the cost to the player and you? See "Attrition warfare".
Some other methods that can be implemented:
Make the target elements difficult for a script to distinguish from other elements. Avoid divs with predictable class and id names if possible. Inject styling using JavaScript instead of using classes. Think like a hacker and make it hard on yourself.
Use decoys that a script will fire on. For instance, if the threat vector is a screen scraping algorithm using pixel colors, throw some common pixel colors in non-target elements. Hits on these non-targets could seem inconsequential to the cheater, but would be detectable. You don't want the cheater to know why you know.
Limit the minimum time between actions to slightly below the best human levels. The best players will hit that plateau, and it won't matter as much who's cheating, and immediately be able to detect anyone scripting faster than that by side-calling method calls.
Random number generators are typically uniform. Human nature is not. Likely a random number generator will have values within a set limit and even distribution. Natural distribution is a Gaussian curve. If you sampled the distribution and it looks like a square wave in the x and y axis, 100% it's a cheater. This will be fairly difficult for the cheater to detect the threshold for the algorithm because it's a derivative of the random, and not the random distribution itself. You're also using aggregate data and not individual plays to detect it, so reverse engineering the algorithm would be extremely difficult without knowing your detection algorithm.
Utilize entropy whenever possible. Avoid predictable game plays. Imagine a racing game on a set collection of race tracks. Each game play could have slightly differing levels of traction, horsepower, and momentum. The script would have to be extremely good to beat it. In a scrolling game, you can alter factors that are instinctual to humans, but difficult for computers, such as wind force, changes in gravity, etc. It would also make it more fun as a side benefit.
Server generated tokens can be used to validate UI elements were used and not calls to the code itself. Validation can be handled in one call at the end of the game comparing events to hashed codes of UI elements. The token should be a hash with a server private key and some value of the UI element.
Decoy the cheater with data they think you're using to detect cheats. Such as calls to a DetectCheat method with dummy calls to a fake backend. It's the old magician's trick. Wave your hand over here, while you slip a card into the deck with the other hand. Let them waste days on end in a maze that has no exit, with lot's of hair pulling.
I'd use a combination of minification and AJAX. If all of the functions and data aren't loaded into the page, it'd be more difficult to cheat.
On the other hand, modding turned out to be a very profitable tool for companies like Id Software. Perhaps allowing the system to be modded might make the game that much more enjoyable to the community at large.
Obfuscate your client exposed code as much as possible. Additionally, use some magic.
You can edit the javascript on the browser and make it work.
Some people suggest that make a call to check with the server. So after making a call to the server, it will be validated in the server. Once validated, it will come to client side and do actions. But I think even this is not foolproof.
For eg.,. for a Basic login action : in angular while making a call to server, the backend validates username & pwd and if validated, it will come back to the client and let the user login using angular.
When I say login using angular, it is going to store things in cookies, like user objects and other things. But still the user can remove the JS code which is making the call to backend, and return TRUE(wherever needed) and insert user object(dummy) to cookies and other objects(whatever needed) and login. It is a very difficult thing to do, but it is doable. In many scenarios, this is not desirable even if it takes hours to edit/hack the code.
This is possible in single page applications, where JS files dont get reloaded for each page. To mitigate the possibility of getting hacked we can use minified codes. And I guess if actions like this is done in backend(like login in Django) it is much safer.
Please correct me if I am wrong.

How safe is "the future of browser gaming"?

HTML5 will be widely adopted as a way to design games, is the prediction. But I have my questions about this: how can an online HTML5 game ever be secure?
Let me give you an example: imagine this platform game where you gain badges when you win, for example, an extremely hard level. When you have actually won this badge, a request is made to the server, in order to update your online profile. Isn't it extremely simple for a hacker to just send this request and gain the badge, without playing the actual game? Because:
The client-side source code is visible and impossible to hide
It is possible to execute Javascript from the command-line
I don't see a way to prevent this hacker from gaining his badge... Is there any way to make this game safe?
Yes, if you designed your game like that, it would be very easy to hack. But why is this specific to HTML5? You could do that with any type of game that was written like that. Even with a native desktop game you could still fake the request. The only difference is that faking HTTP requests is easier than reverse-engineering requests made by a desktop game.
The solution would be to add some kind of "validation" to the victory--the actual algorithm would vary from game to game. Maybe have the server track the game's progress while the user is playing. If it were a game of chess, for example, you could send every move to the server and have the moves validated to make sure they work out correctly. This gets more complicated with real-time games, though.
But whatever algorithm you decide to use, it will be defeated. Even the chess validation that I just mentioned could be bypassed: you could just "create" your own valid game of chess and just send the same moves to the server every time, ensuring that the game was valid. (This is assuming that the player is against a computer--having two humans play against each other would make things easier.)
It's no different from any Flash-based game or indeed a game with a downloadable client like World of Warcraft. Anything integral to the game's fairness has to be handled on the server.
One way that HTML5 can be more secure is that you can change it at any time. So let's say you have an AJAX call to provide a user with a reward. You could periodically change the signature of this call, so that 'cheats' would no longer work. Be sure to keep track of players that are still using the old API, and you can penalize the players using the cheats.
No, this won't solve all of your problems, and there are ways the most savvy players will be able to work around this (depending on how elaborate your changes are), but it does provide some way to deal with this, especially if your game requires significant investment. Players may not be willing to risk their progress if they feel like there is a chance they'll be caught. Just make sure you have a clear code of conduct that details punishments for cheating.

How to Check Authenticity of an AJAX Request

I am designing a web site in which users solve puzzles as quickly as they can. JavaScript is used to time each puzzle, and the number of milliseconds is sent to the server via AJAX when the puzzle is completed. How can I ensure that the time received by the server was not forged by the user?
I don't think a session-based authenticity token (the kind used for forms in Rails) is sufficient because I need to authenticate the source of a value, not just the legitimacy of the request.
Is there a way to cryptographically sign the request? I can't think of anything that couldn't be duplicated by a hacker. Is any JavaScript, by its exposed, client-side nature, subject to tampering? Am I going to have to use something that gets compiled, like Flash? (Yikes.) Or is there some way to hide a secret key? Or something else I haven't thought of?
Update: To clarify, I don't want to penalize people with slow network connections (and network speed should be considered inconsistent), so the timing needs to be 100% client-side (the timer starts only when we know the user can see the puzzle). Also, there is money involved so no amount of "trusting the user" is acceptable.
You can't guarantee the security of the timings cryptographically, because the client's browser can't do secure computation. Any means for encrypting to/from the server could be bypassed by adjusting the actual timings.
And timing on the server doesn't work, either - if you don't take account of latency in the round-trip-time, users with lower latency connections will have an advantage; if you do, users could thwart the compensation phase by adding extra latency there and then removing it later.
You can, of course make it difficult for the users to modify this, but security by obscurity is an unsustainable policy anyway.
So it comes down to either trusting your users somewhat (a reasonable assumption, most of the time) and designing the game so it's not trivial to circumvent the timings.
This approach obviously makes assumptions and is not invincible. All calculations are done on the client, and the server does some background checks to find out if the request could have been forged. Like any other client-based approach, this is not deterministic but makes it very hard for a lying client.
The main assumption is that long-lived HTTP connections are much faster for transmitting data, even negligible in some cases depending on the application context. It is used in most online trading systems as stock prices can change multiple times within a second, and this is the fastest way to transmit current price to users. You can read up more about HTTP Streaming or Comet here.
Start by creating a full-duplex ajax connection between the client and server. The server has a dedicated line to talk to the client, and the client can obviously talk to the server. The server sends the puzzle, and other messages to the client on this dedicated line. The client is supposed to confirm the receipt of each message to the server along with its local timestamp.
On the server generate random tokens (could be just distinct integers) after the puzzle has been sent, record the time when each token was generated, and pass it over to the client. The client sees the message, and is supposed to immediately relay this token back along with it's local time of receipt. To make it unpredictable for the client, generate these server tokens at random intervals, say between 1 and n ms.
There would be three types of messages that the client sends to the server:
PUZZLE_RECEIVED
TOKEN_RECEIVED
PUZZLE_COMPLETED
And two types of messages that the server sends to the client:
PUZZLE_SENT
TOKEN_SENT
There could be a lot of time variation in the messages send from the client to the server, but much lesser in the other direction (and that's a very fair assumption, hey - we have to start somewhere).
Now when the server receives a receipt to a message it sent, record the client time contained in that message. Since the token was also relayed back in this message, we can match it with the corresponding token on the server. At the end of the puzzle, the client sends a PUZZLE_COMPLETED message with local time to the server. The time to complete the puzzle would be:
PUZZLE_COMPLETED.time - PUZZLE_RECEIVED.time
Then double check by calculating the time difference in each message's sent vs received times.
PUZZLE_RECEIVED.time - PUZZLE_SENT.time
TOKEN_RECEIVED.time - TOKEN_SENT.time
A high variance in these times implies that the response could have been forged. Besides simple variance, there is lots of statistical analysis you can do on this data to look for odd patterns.
Even a compiled application could be forged. If the user changes their system clock halfway through timing, your application will report an incorrect time to the server. The only way to get an accurate upper-bound on the time it takes them is to start timing on the server when the puzzle is given to them, and to stop timing when they supply the answer.
As others have pointed out you can minimise the effect that slow connections have by making the load of the puzzle as small as possible. Load the entire page and "game engine" first, and then use an asynchronous request to load the puzzle itself (which should be a small amount of data) to level the playing field as much as possible.
Unfortunately you can't do latency compensation as this would be open to tampering. However, on a connection that's not being used for anything else, the latency for a request like this would be greatly overshadowed by the time it takes a human to solve a puzzle, I don't think it will be a big deal.
(Reasoning: 200ms is considered very bad lag, and that's the average human reaction time. The shortest possible "puzzle" for a human to complete would be a visual reaction speed test, in which case bad lag would have a 100% markup on their results. So as a timing solution this is 2-OPT. Any puzzle more complex will be impacted less by lag.)
I would also put a banner on the page saying to not use the internet connection for anything else while playing for the best possible speeds, possibly linking to a speed / latency tester.
It is impossible to start and stop the timer at the client-side without fear of manipulation...
Anything you perform at the client can be altered / stopped / bypassed..
encrypting/decrypting at the client is also not safe since they can alter the info before the encryption occurs..
Since it involves money, the users can not be trusted..
The timing has to start at the server, and it has to stop at the server..
Use ajax to start the timer at the server only if the puzzle contents return with the result of the ajax call. do not load the puzzle and then sent an ajax request as this could be hijacked and delayed while they review the puzzle...
..
Depending on the server side implementation you have, you could put the timing functionality on the server side. Record the time that the webpage request was made (you could put that into a database if you liked) and then when the answer is received get the current time and perform some arithmetic to get the duration of the answer. You could store the time in the session object if you liked instead of the database as well although I don't know too much about its integrity in there.
You have to use server-side time here. Here is how I would do it:
Make an AJAX request on document ready to ping the server. When server-side code receives the ping, store the server-side time as a session variable (making sure the variable does not already exist). When they finish the quiz, take the server-side time again and compare it with the session variable to determine their duration. Remove the session variable.
Why this works:
You do not start the timer before they see the quiz
The network delay is factored in, because the timer does not start until the AJAX request comes in (if they have a slow connection, the AJAX request will be slow)
Ping is not spoofable because you make sure the session variable does not exist before storing
EDIT: I wanted to add that you could continue to keep client-side time, and include it in the final post. Then you can compare it with your server-side calculated time. If they are reasonably close, then you can trust the client time.
You asked a bunch of questions in your original question, I'm only going to answer one of them:
Am I going to have to use something that gets compiled, like Flash? (Yikes.)
Yes. Given your criteria: 1) 100% accurate, and 2) No possibility of user interference, you have to use a compiled binary.
Doesn't have to be flash though - I'd suggest a java applet if the thought of Flash makes you say "Yikes".
-- Edit:
This solution is somewhat flawed, as pointed out by ZoFrex below.
-- Old:
Here is a way (but you'll need to do some profiling).
Send down a series of "problems" for the JavaScript to solve, while they are playing the puzzle. Previously, I've sufficiently-sized number N such that it is the result of: prime1 * prime2. This forces the client to factor the number (you can get code to do this in JavaScript) and this will take time (this is where profiling clients comes in, and sending down appropriately-sized primes [obviously, this opens you to degradation-attacks, but nevertheless]).
Then, you just send down say, 500, of these prime-problems (or another type), and let the JavaScript solve them in the background. It will generate a list of solutions, and when you send the completed value, you also send this list. From the total count of answers supplied, you can determine how long they spent on the puzzle.
Cons:
Requires profiling to determine capabilities of various clients (and hence difficulty of problems)
Can be downgrade-attacked
Slightly complicated
JavaScript computation may interrupt general puzzle-solving
Possible to write a bot to get solve problems faster than JS
Pros:
Calculations must be done in order to submit the form
If implemented correctly, will prevent all but non-trivial attacks
Clearly, it's attackable, (all proposed answers are), but I think it's reasonable. At least, it would be fun to work on :)
In the end, though, you need to actually install a client-side system with a bit more security. And do note that Flash certainly is not this; it's trivial to decompile. Infact, there was an IQ test here in Australia once, and it was controlled via a Flash app that was done LIVE on television. Of course, the winner was a computer programmer, I wonder why :P
-- Edit:
OP, Also, I linked it in a comment to this post, but just incase you miss it, you are kind of interested in the Hashcash, which is the aim to show that a client has completed some amount of 'Work'. Even if my implementation isn't suitable, you may find a review of that field fruitful.
It's a tricky problem because it's fundamentally unsolvable, so you need to work around the tradeoffs to do your best. There've been several good points made on the technical side including: (a) don't waste your time thinking compiling to Flash, Windows, Silverlight, JVM, or anything will actually help, (b) first transmit the encrypted real puzzle payload, then as the actual bottleneck transmit the key alone, (c) the latency even on 56k of sending a couple hundred bytes is negligible compared to human reaction time.
One thing I haven't seen mentioned is this:
Use after-the-fact auditing and tracking of users. This is how real casinos work. This is, I am told, a big part of how PayPal made their money. In both cases, rather than doing a lot of before-the-fact security, they keep very close tabs on everything about their players, use a lot of technology (statistics, pattern detection, etc) to flag suspicious players and they investigate. In both casinos and PayPal, you can't get your money right away. You have to cash in your chips or wait for the money to make it out of the PayPal system into your real bank. Your system should work the same way-- they can't actually get the money for at least a few days at minimum (longer if you are unable to set up a sufficiently speedy auditing system), giving you time to potentially impound their winnings. You have a lawyer, right? Also, casinos and PayPal know your real life identity (a must for dealing in money) so they can go after you legally-- or more importantly, deter would-be attackers since they could go after them legally.
Combined with the other tips, this may be sufficient to eliminate cheating entirely.
If you find it is not, make your goal not to totally eliminate cheating but to keep it to an acceptable level. Kind of like having 99.99% uptime. Yes, as one poster said, if even one person can compromise it everyone is screwed, but with a good auditing system the attacker won't be able to consistently cheat. If they can cheat 1 in 1000 times if they're lucky and they find they can't cheat more than once or twice before being caught, it won't be a problem since very few will cheat and any given honest user will have an extremely low chance of being affected by an extremely small amount of cheating. It'll be imperceptible. If you ever have a real cheating occurence that hurts an honest user, go out of your way to make the honest user feel satisfied with the outcome to a degree out of proportion to the value of that single customer. That way everyone will be confident in your security. They know they don't have to worry about anything.
People problems are not always solvable with technology solutions alone. You sometimes need to use people solutions. (The technology can help those people solutions work a lot better though.)
excuse me but why you can't use the time on the server? the time when you recieve the response will be the one which you use to calculate the score.
As several others have pointed out:
You must use server time, because client time is vulnerable to manipulation.
Checking the time on the server will potentially penalize people with slow network connections, or people that are far away.
The answer to the problem is to use a time synchronization protocol between the client and the server similar to the protocol that NTP uses. Working together, the client and the server determine the amount of delay caused by network latency. This is then factored into the times given to each user.
NTP's algorithms are complicated and have been developed over years. But a simple approach is below; I think that the protocol should work, but you may wish to test it.
Have the client measure the round-trip time with two successive HTTP XMLRPC pings. Each ping returns a different nonce. The second ping requires the nonce from the first ping, which assures that they are sequential. The puzzle time starts when the second HTTP ping is sent from the client. The server timestamps each request and assumes that the puzzle is displayed 1/2 way between the receipt of the first and the second request.
When the puzzle is finished the client pings twice again, following the same protocol as before. The server knows when it receives each request and it knows the time delta. Now take half the time delta and subtract that from when the first ping of the second set is received. That can be safely assumed to be the time that the puzzle was completed.
there is a very fast implementation of cryptography in js here
http://crypto.stanford.edu/sjcl/
it allows public / private key encryption all on the client and I think you can adapt it to encrypt the Ajax communication between your server and the client browser
here is a detailed explanation, which you can adapt to your needs
http://crypto.stanford.edu/sjcl/#usage
Just a quick thought: why don't you use an iFrame to include the game and it's javascripts and let them reside on the server you have your server side implementation running. Any ajax request should then be sent by the same IP as your server side IP is which would solve the problem of identifying the source. Of course you have to take further measures but already gained a lot of confidence in your "client" side requests. Remember the windowsLive services login and many more like it are based on javascript and the usage of iFrames and are considered secure enough.
I do not think there is a perfect solution. Here is an alternative that makes it harder for cheater but at the same time an unlucky honest solver may lose out.
Get many samples of roundtrip time measurements from each specific devices/location/other combination apriori for each user based on their other interaction with your site. You will also have these measurements for the entire population. You could also be very subtle get the timestamps for when a particular DNS lookup happened from their ISP's resolver (random hostname and you host the authoritative DNS server for that domain).
Once you have this, perform all measurements on the server side (puzzle returned to user, solution received) and subtract out the network time based on previous observations.
Note that even in other solutions you have server load, client load (slow processor, etc.), etc that affect timing.
Make sure you have XSRF protection on puzzle submission page :)
The way I would do this is that when the server sends the puzzle to the client, the current time is stored in a session. This ensures that the timing starts immediately after the puzzle has been sent. After the puzzle has been completed, and is sent to the server to check if the puzzle was done right, the server again checks the time and does a comparison.
Obviously slow Internet connections can make this time bigger, but there's nothing you can do about it.

Categories