5

I am developing an offline web app (game) for android using cordova (phonegap). The leaderboard of the same is maintained online in my server.

Currently this is how the leaderboard is updated

Step 1) The user's score is stored in the offline app's local storage.

Step 2) The user presses the "update my score" button connecting to the internet.

Step 3) The button basically sends an ajax request to https://mywebsite.com/scoreupdate.php?userid=user_id&score=obtained_score

Step 4) Based on this the database is updated in my server by scoreupdate.php file and returns success.

These are the problems I am facing

1) Anyone can easily visit https://mywebsite.com/scoreupdate.php?userid=user_id&score=obtained_score if they know the user id (It can be easily obtained from the app's localstorage data) and he/she can update his/her score in the leaderboard simply by replacing obtained_score value with some high value to get a better position in leaderboard.

2) Any secret value stored in the app or localstorage can be obtained easily as the whole thing is built in javascript. Reverse engineering of the app is also possible so I couldn't find a way to efficiently authenticate that it is the real app which is sending the request to the server and not a person.

My requirements

1) The app must be able to authenticate the scoreupdate.php file that it is the real app and not a person. So that only the app will be able to update the leaderboard.

2) The logic of the authentication shall not be cracked by the user just by reading the source code of the app. (eg: multiplying the user id with some numbers and doing the reverse process in server won't work)

Is there some way to accomplish this?

Javascript scrambling is not effective as it can be de-scrambled easily

EDIT

I am not worried if someone steals the user credentials via a MITM or any bruteforce like attacks. Even the real user who owns the profile should not be able to update his/her own score.

  • 1
    No. You'll have to settle for much less. – Neil Smithline Dec 31 '15 at 18:11
  • 1
    @NeilSmithline Isn't this possible? – Sandeep Thedarkprince C Dec 31 '15 at 18:12
  • @NeilSmithline I know that this is not a best practice. Can you advice me some better way to accomplish the same? I need to update the leaderboard. And no one should be able to cheat. – Sandeep Thedarkprince C Dec 31 '15 at 18:22
  • 2
    It's just not possible. You could add authentication so users could only update *their* score instead of anyone's, but as far as preventing them from cheating it isn't possible as you don't control the device they're running the game on. – André Borie Dec 31 '15 at 18:27
  • @NeilSmithline - I think this question is different enough than the possible dup you suggested, mainly because this question has 2 strikes against it- the client here is offline and virtually open source too. But what a fantastic answer you gave for that question. Everyone should go read it. – TTT Dec 31 '15 at 20:04
  • Maybe @TTT. It is more like the answer is the same rather than the question. And thanks! – Neil Smithline Dec 31 '15 at 20:06
  • @Neil- yeah, agreed! – TTT Dec 31 '15 at 20:08
  • 2
    Google offers some high score functionality on Android platforms. Have you looked at what they have? They may be able to do better as, in unrooted phones, they own the OS. They'll be no hope for rooted phones. But using them may be good enough. Let them worry about forgeries and such. – Neil Smithline Dec 31 '15 at 20:16
  • @NeilSmithline Thanks for that fantastic answer. But my problem is a little different. In my case not even the actual user who owns the profile should be able to update his score illegally. For example if I have a profile in my game named sandeep then my app should be able to update my score but myself should not be able change my score. I don't care about bruteforce and MITM. I think this question is dump. Since the source is open anyone can make a duplicate of my app and manually change the score stored in the local storage and pretend like it was scored by him/her – Sandeep Thedarkprince C Jan 01 '16 at 06:30
  • @NeilSmithline So is there any way to prevent the cheating? I am ready to change the architecture too. – Sandeep Thedarkprince C Jan 01 '16 at 06:31
  • 2
    No. You can't prevent cheating, though you can discourage it by obfuscation, signing data, and etc... It always comes down to there being no security without physical security. You don't have physical control of the mobile device so you're out of luck. – Neil Smithline Jan 01 '16 at 06:35

5 Answers5

7

I disagree that it is impossible.

Depending on the form of your game it might be possible to apply the following scheme:

  1. During the game, record the starting state, including seeds to RNGs and all inputs from the user.
  2. When submitting the game, submit this "replay" of the session to the server together with the claimed score.
  3. On the server, run through the game logic with the provided input and see if it results in the same score. If it does, the replay is valid and you update the score.

This way, you have effectively transformed the problem of cheating to the problem of writing a bot or a solver for your game which is the best you can ever get in a situation like this.

Basically this is a very good solution for any games that can be viewed as an NP-complete problem where verifying a solution is computationally easy while finding it is computationally hard. One such example is Sokoban.

Zeta Two
  • 446
  • 3
  • 7
  • 1
    You really not preventing cheating, just making it more difficult. So your first sentence is wrong. – Neil Smithline Jan 01 '16 at 06:38
  • 1
    That is a nice way. But sending the whole log to the server is tedious. I appreciate the answer and will use this method if I couldn't find any better solution. Thanks a lot. – Sandeep Thedarkprince C Jan 01 '16 at 06:54
  • Anyway there will be a pattern for the log and I am afraid that someone could reproduce it by using a loop or something like that. But I am sure that this will add security to my app. – Sandeep Thedarkprince C Jan 01 '16 at 06:58
  • You fooled all the upvoters. Neil is correct. This doesn't work. How do we even know the game has moves that the server can verify? I'm pretty sure it doesn't, because it's written in JavaScript which means you could just look at the code to see what moves it's expecting for the win. – TTT Jan 01 '16 at 16:40
  • @TTT That is why I wrote "Depending on the form of your game". Which language it is written is does not matter at all. For example: if I implemented Sokoban in Javascript, it is trivial to verify whether a certain sets of moves solves the level or not but it is still a computationally difficult problem to find that set of moves. – Zeta Two Jan 02 '16 at 00:34
  • 1
    @ZetaTwo - ok. That makes sense. I did actually miss the "depending on the form of your game". I agree that if the game is of that type, then this would work. I wouldn't assume that some random game happens to fit that criteria. Perhaps OP can let us know what the game actually is... – TTT Jan 02 '16 at 02:09
  • 1
    As a side note, I undid my DV, and I'm tempted to remove my comment about "fooling everyone", but I'm going to leave it for continuity of the comments. – TTT Jan 02 '16 at 02:25
  • 1
    I think this is a valid solution that would largely prevent cheating. True, a very determined and skilled cheater could come up with convincing statistics / video to cheat with, but this would probably deter almost all cheaters. It would be tremendously harder to make a non-obviously cheated replay than to simply falsely report a high score alone. Oftentimes security cannot eliminate risk, but it can greatly reduce it, and I think this does that. I also thought about the game replay along with the high score (I have seen it done before), and was going to post it here. Good idea @Zeta Two. – Jonathan Jan 05 '16 at 17:05
6

No, this is impossible.

You are relying on the client to provide accurate data. But you can not do that, because the client is outside of your control. It runs on the users hardware, which means that the user can change it in any way they want and there is nothing you can do about that. Any attempt to authenticate that the client wasn't modified must also run on the client machine, which means it isn't protected against manipulation either.

The only way to prevent players from cheating is by running all game mechanics on your own server.

Philipp
  • 48,867
  • 8
  • 127
  • 157
3

With an offline application this can't be achieved because it forces you to trust the application (which can be altered) to store and update the score. There is no way around this for an offline application.

Even with fully homomorphic encryption the offline application would be able to tamper with data even if it can't see the original data.

If the client application is responsible for score-keeping you can only hope for honesty and frustrate cheating attempts via obfuscation; you can't actually prevent them.

A possible incomplete solution that can address a high proportion of cheating is using tuned bayesian nets to perform fraud detection. You evaluate changes in game play activity and score changes into low, medium, and high buckets and then use a bayesian net to fuse the results into a single risk score. That is pretty sophisticated and far from foolproof, but may be an option if the app must be offline.

If you can make it an online application instead you can move rule management and score-keeping to the server which is in your control where you can prevent cheating. Even then it is still a tricky process if the client is able to send anything more than user input events.

Alain O'Dea
  • 1,615
  • 9
  • 13
  • 1
    You lost me with the bayesian net. What would stop the fraudster from just continually sending slightly better scores that fit within the bounds of the net? – TTT Dec 31 '15 at 20:07
  • 1
    @TTT that's where the net would have to be extremely sophisticated. It would also be hard not to cause false positives where genuinely expert or eclectic gamers would be caught by accident. You need a lot of typical gamer data to generate worthwhile nets for this. I just wasn't comfortable saying outright no here since it prevents you from deploying you app offline. – Alain O'Dea Dec 31 '15 at 20:31
  • 2
    So in other words, it wouldn't work well enough to bother... You just wanted to let the OP down easy? You're too nice. :D – TTT Jan 01 '16 at 00:03
  • 1
    @TTT it can work. It does work extremely well for us at work, but it takes years of tuning ;) – Alain O'Dea Jan 01 '16 at 00:26
  • 1
    My definition of "working" is 100% accuracy (for this scenario of preventing cheating). If you need to tune your fraud detection algorithm over time (and perhaps continuously beyond that), I don't think it is a viable solution for *this* particular problem. – TTT Jan 01 '16 at 16:17
  • @TTT good point. I'll make that caveat clear. – Alain O'Dea Jan 01 '16 at 17:09
  • 1
    That's a good edit. Perhaps the net would be "better than nothing" in this case. – TTT Jan 01 '16 at 17:49
1

Sorry, no can do.

In general, if your requirements are:

  1. Have an offline client.
  2. Make the client code open source or easily decompilable.
  3. Prevent the client from cheating.

Then, Choose any 2 of those.

Note: even if you decide to change #2 and go with compiled code that isn't easily decompilable, you are still at the mercy of security by obscurity. You can hard code encryption keys and hope that no one ever figures it out, and if your game is just for fun that may be good enough, but if money is involved it may not be.

The best option of the 3 to change is to not have an offline client.

Caveat: above I said "in general" because there are specific types of games where you can accomplish all 3 requirements, for example games that are intrinsically hard to solve (e.g. imagine a Rubik's Cube type game where the solution isn't widely known yet). See Zeta Two's answer for more information about these types of questions.

TTT
  • 9,122
  • 4
  • 19
  • 31
0

The only real way to solve this is with custom hardware where the cryptographic keys and the source code are embedded in a device in a way that is very difficult for normal users to extract or modify.

For example, you could have a video game system where it reads games off of encrypted DVDs. The video game system (running secret source code existing in read-only memory on the system) can decrypt the video game (using a secret key embedded on the device) and verify it came from a legitimate source and wasn't modified. Inside the video game source code (that your system verified wasn't modified and can't be leaked), you can include a private key that is used to digitally sign combinations of username and high scores when submitting scores to the online leaderboard.

However, once you allow users to view and modify the source code, you've lost (as the user can just modify the source to change the high score to any value right before the time the score is normally submitted), unless there is a way for the user to also submit their moves and have the server verify those moves correspond with the score.

For example, if the game involves solving puzzles in X moves or less, and you want to submit that you solved the N-th puzzle, you could have your game submit the series of moves you made, and then your server can check that those moves consist of a solution that solves the N-th puzzle in X moves or less and that it was submitted at the time given by the server's clock.

dr jimbob
  • 38,768
  • 8
  • 92
  • 161
  • Sorry for the DV but I believe most of your answer is incorrect: The OP states the client is written in JavaScript, so as it stands you can't hide the code.as you suggest. Then you say "the *only real way* to solve this" is by re-writing the code with something that can hide the keys. But the *other way* to solve this (and likely the better way) is to not have an offline client. Also, your last paragraph suggests using the server's clock as some sort of validation, but with an offline client where answers are submitted later, those times can be manipulated to anything. – TTT Dec 31 '15 at 23:28
  • I think your answer may be salvageable though as your middle two paragraphs seem to be an interesting idea if you want to attempt to "secure the source code". (See the note in my answer.) – TTT Dec 31 '15 at 23:38
  • @TTT - First, about server time vs client time, reread what I wrote -- we are in agreement. I never said anything about trusting a client submitted time. I said you only trust the time that it was submitted as given by the **server's** clock and then validated server-side to work to produce a given score. I never said anything about looking at a client's time or the client submitting a time. E.g., a puzzle was released at noon and your leaderboard consists of the first people who submitted valid solutions with the times received by the server. – dr jimbob Jan 01 '16 at 01:05
  • Second, I agree this won't work for a mobile game with completely open source code that you can run on untrusted hardware. But I think it's worthwhile to say that while difficult this problem can be solved on trusted hardware that only runs trusted unmodified software (and this is how online high scores work for video games running on xbox, playstation, etc). And nothing in the question prevents this -- someone could design hardware devices that run a modified android that only runs signed javascript applications and digitally signs submitted scores. – dr jimbob Jan 01 '16 at 01:08
  • Regarding your first comment - your idea assumes that the client communicates with the server to get a puzzle when the user beings the game. Maybe that's how it could work, but then I wouldn't call that "offline". I was assuming that the client is always offline, except to submit a high score. – TTT Jan 01 '16 at 16:06
  • I'm almost with you on the second comment. But that would require scores to only be accepted from digitally signed unmodifable devices. How would the server differentiate from digitally signed scores from those special devices vs digitally signed from a hacked device? Maybe the hardware manufacturer would need to provide a verification system that the server could query? – TTT Jan 01 '16 at 16:13
  • In regards to (1), plenty of games played offline require you to download new levels prior to play. Offline in this context means no internet required while playing. In regards to (2) no, it doesn't require scores to be accepted from unmodified devices. It just requires your trusted server receiving submitted solutions to check the score produced by those moves. For example, say you wrote a Pacman clone that had no randomization (ghost actions only depend on your movements) and a discrete timer of moves (e.g., moves are only registered every tenth of second of the video game clock). – dr jimbob Jan 01 '16 at 17:44
  • If a player submits a series of moves to your server that would produce a high score, your server checks that those moves give the player an appropriate high score even when the game was entirely played offline. Granted this doesn't validate that a human actually found those moves to play on an actual device (versus wrote an AI program to play the game well), but you'll never be able to verify it was done by humans without actually having trustworthy judges watch the human play the game. (And you can add in randomization by treating the seed to your RNG as part of the solution). – dr jimbob Jan 01 '16 at 17:45
  • Copying from my comment to someone else's answer who extrapolated on your idea: "How do we even know the game has moves that the server can verify? I'm pretty sure it doesn't, because it's written in JavaScript which means you could just look at the code to see what moves it's expecting for the win." As for human vs AI: I think we can discount the AI playing the game, because that would thwart any high scores system (including server based games). – TTT Jan 01 '16 at 18:01
  • Zeta Two has shown an example of an NP-Complete game where your idea would work. I would like to undo my downvote but I cannot until you edit your question. Perhaps clarifying the types of questions you idea applies to would help. – TTT Jan 02 '16 at 02:23