how big an issue is hacking/cheating

Hi There,

I’m looking for any comments and insight on cheating/hacking in-app purchases.  Is it something we really need to watch out for?  Something that would happen once in a blue moon and not worth worrying about?  (I’m talking about when my game goes viral :))

Any suggestions as to how to prevent it and get around it?  Let’s say someone purchases 10 coins for a game that they can use at any time.  Obviously you need to make that persistent.  You’ll probably also want to encrypt it and/or obfuscate it to make it hard to hack.  But can’t someone just make a copy of whatever data files there are for the app, and if they want their 10 coins back again and again, just keep replacing the data files again and again.  What alternatives are there to get round simple file copy then replace?

thanks for any comments!

Hi,

I’m disappointed not to get any comments on this post.

I’ve done a bit of reading, and from what I can find:

* There are people that have websites dedicated to providing hacks for games

* It is quite simple to just overwrite data files with new ones.  So let’s say you buy an in app-purchase once, you could keep reusing that purchase simply by making a copy of the data files after purchase, and repeatedly replacing the data files whenever you want to reuse the purchase.

From what I could find on the 'net, the general consensus on how to get around this is to provide some sort of purchase verification using your own servers.  But I really don’t like this solution, because it means that an internet connection is required to use an in-app purchase.  I do distinguish between using and buying, because it’s possible to buy something and use it later on.

So I’m after some comments on an idea that I’ve come up with.

What I think is a feasible solution is to put a timestamp and a checksum in the data file that carries information about in-app purchases.  The checksum would be based on a combination of the timestamp and what in-app purchases are available to use.  One simple idea would be to add combinations of the digits of the timestamp together, and create letters out of it.  eg if the timestamp was

12345678

then you could add 123 to get 6->F, 4,5,6 to get 15->0, 6,7,8 to get 21-U then 234 to get 9-> I

and the checksum is

FOUI

I think any set of weird combination should be hard enough to work out shouldn’t it?  Is there any way a hacker can get access to the code to work out how to do the checksum, by reverse engineering the app?  Even if there was, I think this simple ‘checksum’ step would be a big detterrent to a lot of simple hacks.

The other requirement of this solution is that the in-app purchases expire after a certain amount of time.  Does anyone know if we’re allowed to trash purchases after a certain amount of time?  I’m thinking something like 2 or 3 days is reasonable.  I guess it depends on the app and what the purchase is.

If the app is setup to look at the timestamp and the checksum, and not grant purchases that are too old, then that means hackers are restricted to resetting their purchases to whatever the expiry time is.  eg if it’s 2 days, then the hacker could buy once, and reset the purchases as often as they wanted to for the next 2 days, but after that they’d have to buy them again.

Would love some thoughts on my idea please!!!  What I’d also like some thoughts on is, am I thinking too much about this?  Is it such a small problem that you just let the hackers have their little bit of fun and not worry about them?

thanks

Daniel

If you have a successful game and thousands of people are cheating and more importantly ruining the experience for other players, then sure, people should invest their time in fixing this problem. If not, I think most will tell you its a waste of time.

That being said I spent some time implementing anti cheating methods on my game that I have no idea if more than friends and family will try :slight_smile:

To create a reversible key for your in app purchases you can use openSSL http://docs.coronalabs.com/daily/plugin/openssl/index.html.

Example:

[lua]local openssl   = require(“plugin.openssl”) – Include the plugin in build settings

local cipher    = openssl.get_cipher ( “aes-256-cbc” )

local mime      = require(“mime”)

local secretWord = “daniel”

local function enCrypt(str)

    return mime.b64(cipher:encrypt(str, secretWord))

end

local function deCrypt(str)

    return cipher:decrypt(mime.unb64(str), secretWord)

end

local testString = “this is a secret”

local encrypted = enCrypt(testString)

print(encrypted)

local deCrypted = deCrypt(encrypted)

print(deCrypted)[/lua]

Hi Jon,

How exactly does the reversible key work?

I can’t see how any form of encryption will solve the problem of “buy now, consume later” purchases.  These need to be written to disk, and it doesn’t matter how you encrypt the data file, all someone has to do is make a copy of it and overwrite it to reset the purchases right?

thx

I was just thinking it as a replacement for the way you where creating a checksum above. I don’t really have experience with in app purchases yet though, hopefully someone will comment.

I see from this tutorial:

http://coronalabs.com/blog/2012/05/08/luafilesystem-lfs-tutorial/

That we can get access to the o/s lastmodified timestamp of files.I

It seems to me that one way of validating that data files haven’t been hacked/overwritten would be to compare the o/s lastmodified with the timestamp that I put in the file myself.  In conjunction with the checksum, that could be used to determine if the data file has been hacked/overwritten or not.  No need for expiring purchases!

Any thoughts/comments!?!?!

I’m encrypting against system.getInfo( “deviceID” ), so if someone moves it to a different device or resets their Advertising Identifier (which shouldn’t happen often), the data cannot be decrypted and results in a new table being made.

\_G.encryptedSaveData = true -- set to false when debugging \_G.iOSappID = "1234567890" -- your App Store app ID \_G.saveFilename = "save\_game\_data.txt" -- name of your save game data file -- set up encryption local openssl = require "plugin.openssl" local cipher = openssl.get\_cipher ( "aes-256-cbc" ) local mime = require ( "mime" ) local deviceID = system.getInfo( "deviceID" ) or ( \_G.iOSappID ) -- save json table to data file local function saveFile( filename, table ) local path = system.pathForFile( filename, system.DocumentsDirectory ) local file = io.open( path, "w" ) if ( file ) then local contents = json.encode( table ) local encryptedData = mime.b64 ( cipher:encrypt ( contents, deviceID ) ) if \_G.encryptedSaveData then file:write( encryptedData ) else file:write( contents ) end io.close( file ) return true else -- print( "Error: could not read " .. filename ) return false end end -- load json table from data file local function loadFile( filename ) local path = system.pathForFile( filename, system.DocumentsDirectory ) local contents = "" local file = io.open( path, "r" ) if ( file ) then -- read all contents of file into a string local contents = file:read( "\*a" ) local decryptedData = cipher:decrypt ( mime.unb64 ( contents ), deviceID ) local table if \_G.encryptedSaveData then table = json.decode( decryptedData ); else table = json.decode( contents ); end io.close( file ) return table else -- print( "Error: could not read from " .. filename ) end return nil end -- load/create save game data local saved = {} saved = loadFile( \_G.saveFilename ) if saved == nil then -- print( "No previous or valid save data. Creating new table." ) saved = {} end -- establish any missing variables and data in table if not saved.musicVolume then saved.musicVolume = 0.5 end if not saved.soundVolume then saved.soundVolume = 1 end if not saved.highScore then saved.highScore = 0 end if saved.gameUnlocked == nil then saved.gameUnlocked = false end -- new or updated table ready to be saved saveFile( \_G.saveFilename, saved ) 

Also, my above method is easily expandable to add new save variables while not disrupting the already saved data.

I am with @jonjonsson.  It does not make sense to wast time thinking about hacking unless you have a very successful game.

Said that, to avoid hacking you would have to think about 2 issues:

  1. Ensure that the purchase process is not hacked

  2. Ensure that your local files are not modified

To take care of (1), you can use a kind of double verification, by checking the receipt validity with Apple/Google server.

About (2), it is what was already said, just encrypt your local files. Just be careful that using encryption may require you to request a authorization from the US Government to sell your app there.

Thanks for the replies.

I still don’t understand how encrypting the files are going to ensure that they’re not modified.  Can’t someone just :

  1. make a copy of a valid encrypted file that has any new purchases in it

  2. When they want to restore new purchases, overwrite the file with the copy they’ve got.

If I’m right with that, is this a possible solution?

  1. Add a current timestamp to the data file based on the OS time, every time you change the file

  2. When loading the file, compare the timestamp with the OS last modified timestamp to make sure they’re about the same.  If they’re not the file has been overwritten.

thx

Encrypting files ensure that a person doesn’t understand what is there so he/she cannot modify it.

But, yes they can do what you said in (1) and (2), but it is not that easy. They would have to know what files do what to do what to change/replace them correctly (or go in a trial-and-error approach and this takes time…)

Your suggestion of using timestamp doesn’t work, because you would have to store your “OS last modified timestamp” somewhere, so he could change that either.

To avoid a person copying a file from other to device, you can simply add some kind of unique device identifier inside the file and check it with the actual value from the device when you app loads. This does not solve the problem (2), but if he keeps restoring the file, you can simply store in the same file the user progression, so every time that he restores the file, he loses his progression and in the end it will be of no use for him.

But my point stands, I think it is a waste of time in thinking new ways to protect you app from hacking besides what is already there (encryption and IAP validation).

The solution to the timestamp problem is quite easy, and that’s to also include a ‘checksum’ in the file.  The checksum is something derived from in the file - for instance you could add up 20 different combinations of the individual digits in the timestamp (plus other data in the file, like the in app purchase information), convert those 20 different sums to letters (eg 1 or 27 or 53 becomes a), and you have a checksum.  Then your app checks that what’s in the file also matches the checksum.  I think it would be next to impossible for someone to crack a checksum as random as that wouldn’t it?

Please correct me if I’m wrong, but I thought you can’t use unique device identifiers in this, because apps are allowed to be used on multiple devices owned by the same person, plus you can also restore in-app purchases to new devices.

I’ve seen websites dedicated to ‘crack files’ for individual apps - just overwrite this file and away you go.  They even give you a program to download to easily overwrite the file. So I don’t think it’s a waste of time.  But yeah I guess your app needs to be popular enough first!

regards

Hi,

I’m disappointed not to get any comments on this post.

I’ve done a bit of reading, and from what I can find:

* There are people that have websites dedicated to providing hacks for games

* It is quite simple to just overwrite data files with new ones.  So let’s say you buy an in app-purchase once, you could keep reusing that purchase simply by making a copy of the data files after purchase, and repeatedly replacing the data files whenever you want to reuse the purchase.

From what I could find on the 'net, the general consensus on how to get around this is to provide some sort of purchase verification using your own servers.  But I really don’t like this solution, because it means that an internet connection is required to use an in-app purchase.  I do distinguish between using and buying, because it’s possible to buy something and use it later on.

So I’m after some comments on an idea that I’ve come up with.

What I think is a feasible solution is to put a timestamp and a checksum in the data file that carries information about in-app purchases.  The checksum would be based on a combination of the timestamp and what in-app purchases are available to use.  One simple idea would be to add combinations of the digits of the timestamp together, and create letters out of it.  eg if the timestamp was

12345678

then you could add 123 to get 6->F, 4,5,6 to get 15->0, 6,7,8 to get 21-U then 234 to get 9-> I

and the checksum is

FOUI

I think any set of weird combination should be hard enough to work out shouldn’t it?  Is there any way a hacker can get access to the code to work out how to do the checksum, by reverse engineering the app?  Even if there was, I think this simple ‘checksum’ step would be a big detterrent to a lot of simple hacks.

The other requirement of this solution is that the in-app purchases expire after a certain amount of time.  Does anyone know if we’re allowed to trash purchases after a certain amount of time?  I’m thinking something like 2 or 3 days is reasonable.  I guess it depends on the app and what the purchase is.

If the app is setup to look at the timestamp and the checksum, and not grant purchases that are too old, then that means hackers are restricted to resetting their purchases to whatever the expiry time is.  eg if it’s 2 days, then the hacker could buy once, and reset the purchases as often as they wanted to for the next 2 days, but after that they’d have to buy them again.

Would love some thoughts on my idea please!!!  What I’d also like some thoughts on is, am I thinking too much about this?  Is it such a small problem that you just let the hackers have their little bit of fun and not worry about them?

thanks

Daniel

If you have a successful game and thousands of people are cheating and more importantly ruining the experience for other players, then sure, people should invest their time in fixing this problem. If not, I think most will tell you its a waste of time.

That being said I spent some time implementing anti cheating methods on my game that I have no idea if more than friends and family will try :slight_smile:

To create a reversible key for your in app purchases you can use openSSL http://docs.coronalabs.com/daily/plugin/openssl/index.html.

Example:

[lua]local openssl   = require(“plugin.openssl”) – Include the plugin in build settings

local cipher    = openssl.get_cipher ( “aes-256-cbc” )

local mime      = require(“mime”)

local secretWord = “daniel”

local function enCrypt(str)

    return mime.b64(cipher:encrypt(str, secretWord))

end

local function deCrypt(str)

    return cipher:decrypt(mime.unb64(str), secretWord)

end

local testString = “this is a secret”

local encrypted = enCrypt(testString)

print(encrypted)

local deCrypted = deCrypt(encrypted)

print(deCrypted)[/lua]

Hi Jon,

How exactly does the reversible key work?

I can’t see how any form of encryption will solve the problem of “buy now, consume later” purchases.  These need to be written to disk, and it doesn’t matter how you encrypt the data file, all someone has to do is make a copy of it and overwrite it to reset the purchases right?

thx

I was just thinking it as a replacement for the way you where creating a checksum above. I don’t really have experience with in app purchases yet though, hopefully someone will comment.

I see from this tutorial:

http://coronalabs.com/blog/2012/05/08/luafilesystem-lfs-tutorial/

That we can get access to the o/s lastmodified timestamp of files.I

It seems to me that one way of validating that data files haven’t been hacked/overwritten would be to compare the o/s lastmodified with the timestamp that I put in the file myself.  In conjunction with the checksum, that could be used to determine if the data file has been hacked/overwritten or not.  No need for expiring purchases!

Any thoughts/comments!?!?!

I’m encrypting against system.getInfo( “deviceID” ), so if someone moves it to a different device or resets their Advertising Identifier (which shouldn’t happen often), the data cannot be decrypted and results in a new table being made.

\_G.encryptedSaveData = true -- set to false when debugging \_G.iOSappID = "1234567890" -- your App Store app ID \_G.saveFilename = "save\_game\_data.txt" -- name of your save game data file -- set up encryption local openssl = require "plugin.openssl" local cipher = openssl.get\_cipher ( "aes-256-cbc" ) local mime = require ( "mime" ) local deviceID = system.getInfo( "deviceID" ) or ( \_G.iOSappID ) -- save json table to data file local function saveFile( filename, table ) local path = system.pathForFile( filename, system.DocumentsDirectory ) local file = io.open( path, "w" ) if ( file ) then local contents = json.encode( table ) local encryptedData = mime.b64 ( cipher:encrypt ( contents, deviceID ) ) if \_G.encryptedSaveData then file:write( encryptedData ) else file:write( contents ) end io.close( file ) return true else -- print( "Error: could not read " .. filename ) return false end end -- load json table from data file local function loadFile( filename ) local path = system.pathForFile( filename, system.DocumentsDirectory ) local contents = "" local file = io.open( path, "r" ) if ( file ) then -- read all contents of file into a string local contents = file:read( "\*a" ) local decryptedData = cipher:decrypt ( mime.unb64 ( contents ), deviceID ) local table if \_G.encryptedSaveData then table = json.decode( decryptedData ); else table = json.decode( contents ); end io.close( file ) return table else -- print( "Error: could not read from " .. filename ) end return nil end -- load/create save game data local saved = {} saved = loadFile( \_G.saveFilename ) if saved == nil then -- print( "No previous or valid save data. Creating new table." ) saved = {} end -- establish any missing variables and data in table if not saved.musicVolume then saved.musicVolume = 0.5 end if not saved.soundVolume then saved.soundVolume = 1 end if not saved.highScore then saved.highScore = 0 end if saved.gameUnlocked == nil then saved.gameUnlocked = false end -- new or updated table ready to be saved saveFile( \_G.saveFilename, saved ) 

Also, my above method is easily expandable to add new save variables while not disrupting the already saved data.

I am with @jonjonsson.  It does not make sense to wast time thinking about hacking unless you have a very successful game.

Said that, to avoid hacking you would have to think about 2 issues:

  1. Ensure that the purchase process is not hacked

  2. Ensure that your local files are not modified

To take care of (1), you can use a kind of double verification, by checking the receipt validity with Apple/Google server.

About (2), it is what was already said, just encrypt your local files. Just be careful that using encryption may require you to request a authorization from the US Government to sell your app there.

Thanks for the replies.

I still don’t understand how encrypting the files are going to ensure that they’re not modified.  Can’t someone just :

  1. make a copy of a valid encrypted file that has any new purchases in it

  2. When they want to restore new purchases, overwrite the file with the copy they’ve got.

If I’m right with that, is this a possible solution?

  1. Add a current timestamp to the data file based on the OS time, every time you change the file

  2. When loading the file, compare the timestamp with the OS last modified timestamp to make sure they’re about the same.  If they’re not the file has been overwritten.

thx

Encrypting files ensure that a person doesn’t understand what is there so he/she cannot modify it.

But, yes they can do what you said in (1) and (2), but it is not that easy. They would have to know what files do what to do what to change/replace them correctly (or go in a trial-and-error approach and this takes time…)

Your suggestion of using timestamp doesn’t work, because you would have to store your “OS last modified timestamp” somewhere, so he could change that either.

To avoid a person copying a file from other to device, you can simply add some kind of unique device identifier inside the file and check it with the actual value from the device when you app loads. This does not solve the problem (2), but if he keeps restoring the file, you can simply store in the same file the user progression, so every time that he restores the file, he loses his progression and in the end it will be of no use for him.

But my point stands, I think it is a waste of time in thinking new ways to protect you app from hacking besides what is already there (encryption and IAP validation).