Distribution Save file security techniques?

C

CruelBus

Guest
My game will have 2 files stored locally: a settings file (not critical) and the offline stats file (VERY CRITICAL) that will be sent to Google as a cloud backup.

I'm comfortable with the data integrity in the stat file, but one user could simply give a copy of their "secure" file to another user, and that second user would now have everything the first user had, offline anyway.

I haven't implemented all things Google yet, but am wondering if there is a way to uniquely identify the install by a user, which I can then add to the save file, so that the file can not be shared.

I am asking about this now because I'm setting up the buffer that holds the information and need to know how large a space to reserve for such an ID or method.
_____________________________________________________________

SOLUTION: Use ds_map_secure_save combined with my current methods.
"This function will save the contents of the given DS map to a file that is linked to the device it was created on (meaning it can't be read if transferred to any other device). "
 
Last edited by a moderator:

Alice

Darts addict
Forum Staff
Moderator
In cases like this, it's worth asking:
- what is the harm of one player cheating by using save data of another
- how far are you willing to go to prevent that damage, and whether you can let cheating players off the hook sometimes

Note that while there are various security measures available that prevent save-sharing, they tend to be pretty intrusive and/or cumbersome. There are two broad categories I can think of:

1. Identifying the machine/system of the player - it can be intrusive a lot and, depending on specific solution used, can result in unstable saves or holey security. Examples would include:
- IP address (prone to change in some machines, so the saves are unstable a lot)
- MAC address (feels pretty intrusive to me, not sure if system security won't protest when trying to access it; GM probably can't retrieve one natively, you'd need to use an extension instead)
- Windows account name (it should be supported on all Windows machine; the save can work on same-named accounts on different machines, but changing an account name to cheat in a game is still a hassle; the save won't work between different Windows accounts)

2. Online verification - the player needs to login to the game server first in order to play the game for the first time, and that player information becomes the key to the save data. If you want to ensure the save won't be opened without proper verification, you need to make an online check every time you load the game. Still won't work if someone shares their account freely, unless you add separate server-side measures against using the same account across too many machines.

Another thing that should be noted - once someone has the game file itself, they can still reverse-engineer your saving system given enough effort, and there's nothing you can do to stop it for good.

My personal take

As long as the save data only affects the offline state of the game (as opposed to e.g. online achievements or something), I would employ extra measures preventing save-sharing. I imagine getting the proper save should be difficult enough that most players won't bother cheating that way, and those that do... well, it's up to them what they do offline. I'd still do some minimal save integrity check so that cheating will be too difficult to bother for most people. However, I wouldn't go out of my way to prevent save-sharing itself, because the effort and potential annoyance to the player outweighs the harm prevented. Then again - I don't see offline cheating as that great of a harm to my game.

When it comes to online games, I might be more cautious - but since the game uses online connections anyway, I might as well employ online verification measures. There's still a problem of the game itself containing all the online connection logic, which cheaters might employ. This can be mitigated sometimes - e.g. if you have a puzzle game like sudoku, then you can store puzzles and answers on server side, and the game doesn't have the data necessary to cheat on a specific puzzle. But in some cases all the data required to count as a "win" might need to be stored in the game itself anyway, and then cheaters might extract that data. But at the very least, if I know someone is obviously cheating, I can invalidate their result on my game server.

For me, in the end, it's about how much the game is harmed by cheating. Having people cheat offline mostly affects them, so it's not a major concern to me. An online-connected game might be harmed somewhat by cheating (especially if the cheaters occupy the top of the leaderboards), but you can prevent save-file sharing by using logged in user data, so that someone doesn't get bragging rights on their account from someone else's save.

Also, please keep in mind that there are various methods cheaters can use - some more elaborate than the others - and it's near impossible to prevent all the cheating with people owning a game copy. So it becomes less about "how to prevent cheating" and more of "how much of a hassle should the cheating be, so that most people won't bother".
 

Yal

šŸ§ *penguin noises*
GMC Elder
One of my favorite techniques is just XORing data with some random 32-bit number(s) (GM's random or based on something - e.g. the username environment variable if you don't want people to share files between accounts), it makes it human-unreadable and it's impossible to reverse-engineer from the file unless you know the original XOR number. (Though be careful, XORing the same data value with the same number a lot could reveal the number because of the repeats - 0 data is a big offender)
 

curato

Member
ds_map_secure_save isn't a bad way to do it as long as you don't want the save to be shared between computers. It is quick and easy and will keep casual hackers out with out haveing to write a custom save. Just put all the data in a ds_map and use the command. A determined hacker will get in no matter what. All you can do is keep the casuals out and maybe make it more trouble than it is worth.
 
C

CruelBus

Guest
With the exception of the leaderboards, there's really no reason any of my game's players would really need to be online... except for IAP. I plan on following the "free to play" model on Google Play, since that's what everyone expects these days. Originally it was just going to be a flat price.

If the only incentive to connect with Google Play is to send your latest scores for bragging rights, then people who don't really care about that can just copy their saves with everything unlocked and share them for free, and I will basically have a revenue stream of ZERO (not that I'm expecting really anything for my first game)

I could force the game to be online only, which I personally would HATE as a player. Also, with Google Play, you are REQUIRED to allow the user to deny connecting, and must save data locally.

https://developer.android.com/training/articles/user-data-ids <- This link has some great info, but honestly, I'm not running my own server, and have my hands full learning everything I need to get this game "out there."
 
Last edited by a moderator:
C

CruelBus

Guest
I am using the binary file read/write method and am comfortable with the data integrity in the file. If an individual wants to take the time to figure it all out in order to save 99 cents, then hey - GREAT. BUT, if that is just as simple as copy-pasting a file (on a rooted phone) then I feel like most people would do that (see what happened to Fallout Shelter by Bethesda) instead of paying the 99 cents, so a one dollar loss becomes thousands (if I were to be so fortunate that thousands would download and play)
 
Last edited by a moderator:
C

CruelBus

Guest
I read about ds_map_secure_save and that sounds like exactly what I need.

I have never used a ds_map before, so could I just store my entire buffer as a key in the map, then save the map?
 

curato

Member
I read about ds_map_secure_save and that sounds like exactly what I need.

I have never used a ds_map before, so could I just store my entire buffer as a key in the map, then save the map?
You literally could do that. Just add the buffer as a key and then save it.
 
Top