Now that there are a couple of neat canvas demo's of both classic platform and even 3D fps games in HTML5, the next step might be to try developing a multiplayer HTML5 game. HTML5 socket support makes this relatively straight-forward, but with client-side source being viewable by anyone in the browser, what are some solutions for basic game security features for a HTML5-frontend multiuser game -- such as being able to prevent a faked high-score submit?
The simple answer is: You can't trust the data from client, which means that the high score submit can't come from the client.
Since the code client is available for anyone to inspect, there's no way of trusting the data that the client sends your server. Even if you encrypt the data with a per-user encryption key (which is possible), the user can simply alter your code within the browser and change the values it's sending to the server.
Since your game is multiplayer, this might be possible IF the server generates all the scoring events. If the server generates all the scoring events, the client never sends score data to the server which means that the high score data can't be faked.
You'll still have to deal with cheating, which is even more challenging, but that's another issue...
Adding on to what Larry said, you're definitely going to have to handle the scoring on the backend to really prevent cheating/fake score posting.
For an example of this in practice... The game Word Wars is a boggle-esque game where you find as many words as you can from a 4x4 grid of letters.
At the start of each game, a 4x4 board is generated server side. A list of possible words for that board is generated and a hashed version (md5'd with a random salt) of each word as well as the salt are passed to the client.
On the client side, when the letters are typed and the enter key is pressed, we md5 (with the salt from the server) the word that was entered and check that against the list of hashed words provided by the server. If it's a match, we update the client with the new score (there's a function based on letters used and their point values).
Once the game is over, the client sends the list of words they came up with to the server (NOT the score), and the server double-checks that those words existed in the board, and handles the scoring.
This is where Clay.io, the company I'm working in comes in. Clay.io offers an API for high level HTML5 game features like leaderboards, achievements, payment processing, etc... Needless to say, we needed a solution for games that have a backend to make certain things like high scores more secure.
The solution was to encrypt JavaScript objects on the backend (node.js, php, whatever) using JWT (JSON Web Token), and pass that encrypted object rather than the score itself. This lets us communicate both ways (game -> Clay.io and Clay.io -> game), and is pretty painless to do. The full docs on this are here: clay.io/docs/encryption (max links hit on this answer)
Back to Word Wars... from the server we generate that JWT with the user's score and pass that on to Clay.io to post the score. Voila :)
Of course, this will differ as the type of game you're developing differs, but the moral of the story is you have to get creative :)
I wrote a blog post that covers HTML5 game security in greater detail. Part 3 of a series on HTML5 Game Development Tips.
Related
The App could have a private key hard-coded into it and my server could have the public for it and the App could sign everything. But then a hack could identify the private key in the object code and write a malicious App that signs everything with that same key. Then that App could use my server.
The App could do a key exchange with my server but how does the server know the App is authentic when it does the key exchange?
In essence you cannot know.
Reason is simple: since anybody can get to the client and have everything the client is and knows by reverse engineering the client (to which they have all they need to perfrom that), there is nothing that can prevent them from answering any challenge you might set to what the real app would answer.
You can make it harder on fake apps though. But they could (if done right) give the answer anyway.
E.g. how to make it harder:
The server sends a challenge to the client app to calculate e.g. the CRC32 (or md5, sha-1, sha-256, ... doesn't matter as such) of the app itself from a given start to a given end. If you set those start and end points to be fully random for every challenge you send, you essentially force the fake app to have the real app's compiled code in full ... So you place the burden of having to have the real app (not forcing it to be actually running the (unmodified) code, just having the actual unmodified code).
Take care that you would need to support the server side with allowing for multiple versions of the client etc. or you can't upgrade the clients anymore.
Anybody distributing a fake app would hence be forced to violate your copyright on the real app (and your lawyers would have am easier case maybe).
Alternatives:
To pick an alternative, you need to figure out why it's (so) important to have your client ?
If the client contains secrets: remove them, make the client display only and have an 3 tier model where you only let the user run the display part and keep all secrets on your servers.
If you get your revenue from selling an app, give it away for free and sell accounts on your server. Use authentication to do that: you can authenticate users (login&password, real 2 factor authentication , ...) you can also disallow them to dramatically change their geo location in a short time, disallow simultaneous logins, ...
But the price is the hoops for the user to jump through. And they might use other clients nonetheless.
If you allow logic (like e.g. used in online games) to use the power of the user's CPU to do things, you can still keep oversight on a logic level on the server: e.g. if it takes 5 minutes at the very minimum to complete a task in the real client, and if the client reports back as "achieved" before those 5 minutes are done: you have a cheater ... Similarly, make sure all important assets are only given from the server, don't trust the clients ...
I develop a simple game with an online simple high score.
One way to attack it is spoofing.
I wanted to send out a Post Request containing username and points.
Right now we just looking at sending data, receive it and process it. (=> no anticheat within the game or SQL injection etc)
The Question is:
What possibilities do I have to protect this process client side?
How do baddies hijack a post request, so they can spoof it?
What would be a solution to protect the content of the the request?
greetings
You can't stop fake high scores from being submittable.
You can have the end client digitally sign the high score, but the client could be modified, so that achieves nothing.
The best you can do is have the high score accompanied by a complete play by play of the game. That way the play by play can be audited to look for suspicious/erroneous behaviour.
You can't guarantee 100% that your communication will be secure but you can make an attacker's job harder.
If you encrypt the score within the game and send the (encrypted) score to the server you defeat most script kiddies who just downloaded Wireshark and learned to change numbers.
However, a determined attacker can always reverse-engineer your game to determine the encryption key, or even attach a debugger to the game and modify their score right before it's sent.
There are ways to make this more difficult as well but at the end it's a balance of how secure you want your game to be and how much time and effort you're willing to put into it.
I have built a game in HTML5 and a web form posts data to a server.
The scores in the game are calculated using Javascript, and the form posts the data to the server.
Won't this architecture be vulnerable to an attack, where the client can be modified, such that it posts rogue values instead of the calculated scores?
How can I prevent this from happening?
To keep things short - you need to do all of your verification server-side. There no problem using client-side scripts to keep things looking good, but you cannot trust anything from the client.
Take Stackoverflow as an example. When you vote it is instantly calculated client-side (to keep things nice and quick) but it is properly validated by the server once submitted.
For example if I attempt to upvote my own answer the server rejects it with the following JSON:
{"Success":false,"Warning":false,"NewScore":0,"Message":"You can't vote for your own post.","Refresh":false}
even though the javascript happily submitted it.
Therefore you also need to calculate your game scores server-side.
Don't trust user inputs, especially trough a form they might perform SQL injection as you send data to your server. (see also How can I prevent SQL injection in PHP?)
Try to verify as much data as possible server side.
Seeing that you also use javascript watch out for javascript injection (http://www.testingsecurity.com/how-to-test/injection-vulnerabilities/Javascript-Injection) as they can inject changes into ur script (e.g. score value)
I want to create a portal website for log-in, news and user management. And another web site for a web app that the portal redirects to after login.
One of my goals is to be able to host the portal and web-app on different servers. The portal would transmit the user's id to the web-app, once the user had successfully logged in and been redirected to the web app. But I don't want people to be able to just bypass the login, or access other users accounts, by transmitting user ids straight to the web app.
My first thought is to transmit the user id encrypted as a post variable or query string value. Using some kind of public/private key scenario, and adding a DateTime stamp to key to make it vary everytime.
But I haven't done this kind of thing before, so I'm wondering if there aren't better ways to do this.
(I could potentially communicate via database, by having the portal store the user id with a key in a database and passing that key to the web app which uses it to get the user id from that database. But that seems crazy.)
Can anyone give a way to do this or advice? Or is this a bad idea all-together?
Thanks for your time.
Basically, you are asking for a single-sign-on solution. What you describe sounds a lot like SAML, although SAML is a bit more advanced ;-)
It depends on how secure you want this entire thing to be. Generating an encrypted token with embedded timestamp still leaves you open to spoofing - if somebody steals the token (i.e. through a network sniffing) he will be able to submit his own request with the stolen token. Depending on the time to live you will give your token this time can be limited, but a determined hacker will be able to do this. Besides you cannot make time to live to small - you will be rejecting valid requests.
Another approach is to generate "use once" tokens. This is 'bullet proof' in terms of spoofing, but it requires coordination among all the servers within the server farm servicing your app, so that if one of them processed the token the other ones would reject it.
To make it really secure for the failover scenarios, etc. it would require some additional steps, so it all boils down to how secure you need it to be and how much you want to invest in building it up
I suggest looking at SAML
PGP would work but it might get slow on a high-traffic site
One thing I've done in the past is used a shared secret method. Some token that only myself and the other website operator knows concatenated to something identifying the user (like their user name), then hash that with a checksum algorithm such as SHA256 (you can use MD5 or SHA1 which usually are more available but they are much easier to break)
The other end should do the same thing as above. Take the passed identifying information and checksum it. Compare that to the passed checksum, if they match the login is valid.
For added security you could also concat the date or some other rotating key. Helps to run SSL on both sides as well.
In general, the answer resides somewhere in SHA256 / MD5 / SHA1 plus shared secret based on human actually has to think. If there is money somewhere, we may assume there are no limits to what some persons will do - I ran with [ a person ] in High School for a few months to observe what those ilks will do in practice. After a few months, I learned not to be running with those kind. Tediously avoiding work, suddenly at 4 AM on Saturday Morning the level of effort and analytical functioning could only be described as "Expertise" ( note capitalization ) There has to be a solution else sites like Google and this one would not stand the chance of a dandelion in lightning bolt.
There is a study in the mathematical works of cryptography whereby an institution ( with reputable goals ) can issue information - digital cash - that can exist on the open wire but does not reveal any information. Who would break them? My experience with [ person ]
shows that it is a study in socialization, depends on who you want to run with. What's the defense against sniffers if the code is already available more easily just using a browser?
<form type="hidden" value="myreallysecretid">
vis a vis
<form type="hidden" value="weoi938389wiwdfu0789we394">
So which one is valuable against attack? Neither, if someone wants to snag some Snake Oil from you, maybe you get the 2:59 am phone call that begins: "I'm an investor, we sunk thousands into your website. I just got a call from our security pro ....." all you can do to prepare for that moment is use established, known tools like SHA - of which the 256 variety is the acknowledged "next thing" - and have trace controls such that the security pro can put in on insurance and bonding.
Let alone trying to find one who knows how those tools work, their first line of defense is not talking to you ... then they have their own literature - they will want you to use their tools.
Then you don't get to code anything.
Lets say that in a browser based game, completing some action (for simplicity lets say someone clicks on a link that increases their score by 100) clicking on this link which would have a url for example increase_score.pl?amount=100 what kind of prevention is there from someone simply sending requests to the web server to execute this command:
Over and over again without actually doing the task of clicking on the link and
Sending a false request to the server where amount is set to something rediculus like 100000.
I am aware of checking HTTP_REFERER however I know people can get around that (not sure how exactly) and other than some bounds checking for the 2nd option I'm kind of stumped. Anyone ever experience similar problems? Solutions?
Nothing can stop them from doing this if you implement your game how you propose.
You need to implement game logic on the server and assign points only once the server validates the action.
For example: on SO when someone votes your question up, this isn't sent as a command to increase your reputation. The web-app just says to the server user X voted question Y up. The server then validates the data and assigns the points if everything checks out. (Not to say SO is a game, but the logic required is similar.)
Short version: you can't. Every piece of data you get from the client (browser) can be manually spoofed by somebody who knows what they're doing.
You need to fundamentally re-think how the application is structured. You need to code the server side of the app in such a way that it treats every piece of data coming from the client as a pack of filthy filthy lies until it can prove to itself that the data is, in fact, plausible. You need to avoid giving the server a mindset of "If the client tells me to do this, clearly it was allowed to tell me to do this."
WRONG WAY:
Client: Player Steve says to give Player Steve one gazillion points.
Server: Okay!
RIGHT WAY:
Client: Player Steve says to give Player Steve one gazillion points.
Server: Well, let me first check to see if Player Steve is, at this moment in time, allowed to give himself one gazillion points ... ah. He isn't. Please display this "Go Fsck Yourself, Cheater" message to Player Steve.
As for telling who's logged-in, that's a simple matter of handing the client a cookie with a damn-near-impossible-to-guess value that you keep track of on the server -- but I'll assume you know how to deal with session management. :-) (And if you don't, Google awaits.)
The logic of the game (application) should be based on the rule to not trust anything that comes from the user.
HTTP_REFERER can be spoofed with any web client.
Token with cookie/session.
You could make the link dynamic and have a hash that changed at the end of it. Verify that the hash is correct given that period of time.
This would vary in complexity depending on how often you allowed clicks.
A few things to note here.
First, your server requests for something like this should be POST, not GET. Only GET requests should be idempotent, and not doing so is actually a violation of the HTTP specification.
Secondly, what you're looking at here is the classic Client Trust Problem. You have to trust the client to send scores or other game-interval information to the server, but you don't want the client to send illegitimate data. Preventing disallowed actions is easy - but preventing foul-play data in an allowed action is much more problematic.
Ben S makes a great point about how you design the communication protocols between a client and a server like this. Allowing point values to be sent as trusted data is generally going to be a bad idea. It's preferable to indicate that an action took place, and let the server figoure out how many points should be assigned, if at all. But sometimes you can't get around that. Consider the scenario of a racing game. The client has to send the user's time and it can't be abstracted away into some other call like "completedLevelFour". So what do you do now?
The token approach that Ahmet and Dean suggest is sound - but it's not perfect. Firstly, the token still has to be transmitted to the client, which means it's discoverable by the potential attacker and could be used maliciously. Also, what if your game API needs to be stateless? That means session-based token authentication is out. And now you get into the deep, dark bowels of the Client Trust Problem.
There's very little you can do make it 100% foolproof. But you can make it very inconvenient to cheat. Consider Facebook's security model (every API request is signed). This is pretty good and requires the attacker to actually dig into your client side code before they can figure out how to spoof a reqeust.
Another approach is server replay. Like for a racing game, instead of just having a "time" value sent to the server, have checkpoints that also record time and send them all. Establish realistic minimums for each interval and verify on the server that all this data is within the established bounds.
Good luck!
It sounds like one component of your game would need request throttling. Basically, you keep track of how fast a particular client is accessing your site and you start to slow down your responses to that client when their rate exceeds what you think is reasonable. There are various levels of that, starting at the low-level IP filters up to something you handle in the web server. For instance, Stackoverflow has a bit in the web application that catches what it thinks are too many edits too close together. It redirects you to a captcha that you need to respond to if you want to continue.
As for the other bits, you should validate all input not just for its form (e.g. it's a number) but also that the value is reasonable (e.g. less than 100, or whatever). If you catch a client doing something funny, remember that. If you catch the same client doing something funny often, you can ban that client.
Expanding on Ahmet's response, every time they load a page, generate a random key. Store the key in the user session. Add the random key to every link, so that the new link to get those 100 points is:
increase_score.pl?amount=100&token=AF32Z90
When every link is clicked, check to make sure the token matches the one in the session, and then make a new key and store it in the session. One new random key for every time they make a request.
If they give you the wrong key, they're trying to reload a page.
I would suggest making a URL specific to each action. Something along the lines of:
/score/link_88_clicked/
/score/link_69_clicked/
/score/link_42_clicked/
Each of these links can do two things:
Mark in the session that the link has been clicked so that it wont track that link again.
Add to their score.
If you want the game to only run on your server, you can also detect where the signal is sent from in your recieving trick, and ignore anything not coming from your domain. It will be a real pain to tamper with your codes, if you have to run from your dedicated domain to submit scores.
This also blocks out most of CheatEngine's tricks.