Page 1 of 2

Game Anti-Cheat Devices.

Posted: Sat Apr 22, 2006 6:35 pm
by R4000
I'm trying to build up a list of anti-cheating methods to include in my game engine.
I've come up with the following at the moment.

base64_encode all URLs (and all forms use POST)
Basicly, this involves having a main index controller scripts (easy for me, because i use a template engine that includes other pages) that has the following code (or something along these lines) in it:

Code: Select all

$_url = base64_decode($_SERVER['QUERY_STRING']);
switch ($_url){
 case "home":
   include("pages/home.php");
   break;
 case "bank":
   include("pages/bank.php");
   break;
 default:
   include("pages/badnav.php");
}
Step by step navigation checks.
Only really usefull on RPG style games, but basicly you have an array of links for a location/page then call a 'register_links' function that stores the links in a database (basic caching would be a bonus).

Code: Select all

$links = array("bank","healers-hut","cafe");
register_links($links);
Then on the top of each page (or in your index page if you use above method) you select the links from the database that corrispond with the users location:

Code: Select all

$links = getLinks($userLocation);
$_url = base64_decode($_SERVER['QUERY_STRING']); // See Above
if(!in_array($_url[0], $links)){
 include("pages/badnav.php");
}
Secure all pages well
I know this sounds stupid, but if you have a page like 'heal.php' (and are ignoring above...) but then have no protection on that page.
A user would basicly add the link to heal.php in his favorites, go out to battle. Then when low on health (still in battle..) click his bookmark, heal. Then switch back to the battle and continue.
All it really takes is a simple set of 'if's like:

Code: Select all

$buildingsInUsersLocation = array("tavern","bank");
if(!in_array("healers-hut",$buildingsInUsersLocation)){
  include("pages/badnav.php");
  exit;
}
// Heal code goes here.
Watch your signup bonuses or freebies
I know we all like to be nice and give freebies, or to tempt new users we stick a decent amount of 'goodies' for signing up.
As most of you know, once you do this... You get multiple accounts so people get rich quick.
Although you might protect your signup with an image verifaction script MAKE IT DIFFICULT, because alot can be read using OCR techniques.
Your mail verifaction script will be easy to get around too with so called 'catch-all' email addresses, or free email accounts (GMail, Yahoo, ThemWhoMustNotBeNamedButAreOwnedByM$).
What you should really do is make the signup bonuses 'non-transferable' or something like that.
And if you give free 'gold' or something as a signup bonus. Make sure that during the first 48 hours or something that the gold cannot be 'donated' or anything.
Also make sure that you protect EVERY script that deals with transfering of goods between users, because if you leave one hole (maybe something like: signup, buy a pair of shiny boot, trade to another user, user sells them, user is rich) can be automated... and if you release to the public with holes like this, even though it seems small. Your chances of getting big are made alot smaller if a few people cheat there way to the top.

Trade limits
If you have a game with a 'trade' feature, i'd recommend limiting it so a user can only RECEIVE a certain amount of items or gold or anything within an hour. This should stop people getting rich REALLY fast (they still will, but not as fast) from 'scamming' other people or signing up for multiple accounts.



Thats basicly all i came up with, do any of you guys have any to add (or anything to say about mine)?

Posted: Sat Apr 22, 2006 7:04 pm
by John Cartwright
Why are you bothering to base64_encode your url's? This is what we call security by obscurity, which isn't true security at all -- although it may stop a script kiddie or two. If you want to continue this path of obscurity, don't use an out of the box function, instead make your own.

But whats the point in the end? There isn't much of one..

Posted: Sun Apr 23, 2006 5:57 am
by R4000
Well, i know base64 isn't really a end to all your problems, but as you said... it will stop alot of the "OOooo, if i change that to index.php?heal ill get free heal" people...

And i normaly use md5 there, its just complicated to explian how i find out what page the user wanted..

Posted: Sun Apr 23, 2006 10:31 am
by John Cartwright
That's baaaad! You need to come up with a some sort of permission system --- you should never trust the user with anything!

Posted: Sun Apr 23, 2006 11:04 am
by d3ad1ysp0rk
Yeah, encoding your crap is just a workaround for improper planning.

Your code should be determining whether they get health or not. Not what is passed as a query string.

Posted: Sun Apr 23, 2006 11:40 am
by R4000
I know that... Just these methods make the little glitches that you might/if/possibly/maybe get with coding, and instead of leaving them open for your users to find and make you look bad. Just whack a system over the top of your code like this. Then for you user to get around it, they would need to know how you get infomation out of the string.

Infact im just polishing up my own encryption method, CBE (char. based encryption) that should be totaly secure (to the extent of what i need).

Posted: Sun Apr 23, 2006 11:51 am
by John Cartwright
once the users realize that http://domain.com/d9g9h089f08as90d8wq0989g8x gets them a free heal, whats the stop them from visiting that page.

Why don't you stop using security through obscurity and do it right the first time? Seems like much less effort, aswell as keeping things much simpler.

heal.php

Code: Select all

$result = mysql_query(
   'SELECT `userGold` and `userHealth` 
    FROM `usersStats` 
    WHERE `uid` = \''.$_SESSION['uid'].'\' 
    LIMIT 1'
);

if (mysql_num_rows($result) > 0) 
{
   $row = mysql_fetch_assoc($result);

   if ($row['userGold'] >= 30 && $row['userHealth'] != 100) 
   {
      $row['userGold'] -= 30;
      $row['userHealth'] = 100;

      mysql_query(
         'UPDATE `user_stats` 
          SET `userGold` = '.$row['userGold'].', `userHealth` = '.$row['userHealth'] .'
          WHERE `uid` = \''. $_SESSION['uid'].'\''
      );
   }
}
Notice how simple it is to authenticate a user from a heal? Now I have no idea how your game works, but something like this should be effective enough.

Posted: Sun Apr 23, 2006 12:07 pm
by R4000
I see your point but...

I allready have code along the lines of that, and what will stop them bookmarking that page?
As I think I said in the first post, I am not using the exact same method as above, i have more than just the page in my encrypted string.

My actual string is more like:

Code: Select all

base64_encode(md5(pagename)."|".time()."|".session_id())
So when they have decoded the base64 all they get is:

Code: Select all

1f3870be274f6c49b3e31a0c6728957f|1145811482|36881f12433993be9c075119c04db24c
To anybody that makes no sense, cause it could be: MD5|time|MD5, SESS|time|MD5, SESS|rand number|MD5
and all you check for is if the time is less than 3600 seconds from current time(), so links are only valid for an hour.

But as i remember saying in my first post, this method on its own does absolutly nothing to protect your pages...

Posted: Sun Apr 23, 2006 12:27 pm
by John Cartwright
Let me just end this off by saying you are application as it stands it NOT secure. For the last time, this is security through obscurity. I'm no security guru, but I know I would be able to get through this system with little effort, reguardless if you change your "format". Perhaps if you screw with it enough ways it may not be worth it for the user to be able to cheat.

Why not just guarantee they won't be able to by doing it right. Why do you insist on ugly, unsafe urls?

Posted: Sun Apr 23, 2006 2:06 pm
by R4000
Why do you persist in not reading the parts of my posts that say this isn't the only method im implimenting....

Posted: Sun Apr 23, 2006 3:57 pm
by Charles256
because your idea won't work. that simple. :-D gotta do state checks :-D see what they're doing and what they should be allowed to do. things along those lines. I know it sucks,but that's the way it has gotto be.

Posted: Sun Apr 23, 2006 4:10 pm
by R4000
I'm trying not to lose my temper here but if you keep ignoring me then i might just do that, I have been saying all along that I am using them methods too... THIS IS JUST A METHOD OF DETERING EXPOITORS, If the see that i've even gone to the trouble of masking the URL, then 90% of the idiots that might randomly just accidentaly come across a glitch that allows them to do wierd stuff just by modding a url will be kept out!

I notice you have all focused on the first option in my main post, any comments on the others?

Posted: Sun Apr 23, 2006 4:23 pm
by John Cartwright
R4000 wrote:I'm trying not to lose my temper here but if you keep ignoring me then i might just do that, I have been saying all along that I am using them methods too... THIS IS JUST A METHOD OF DETERING EXPOITORS, If the see that i've even gone to the trouble of masking the URL, then 90% of the idiots that might randomly just accidentaly come across a glitch that allows them to do wierd stuff just by modding a url will be kept out!

I notice you have all focused on the first option in my main post, any comments on the others?
Calm down, anything done was not intentional, and if you want to continue this way then you are welcome to find someone else to help you -- I know I'm not anymore. Good luck.

Edit | I just want to point out, you do not have to do any of this garbage if you simply followed my suggestion. Please do not tell me I'm not listening -- you are not listening.

Posted: Sun Apr 23, 2006 4:24 pm
by Charles256
delete first one.if properly secured it's pointless and extra coding for you. the rest seem all right to me :-D

Posted: Sun Apr 23, 2006 5:29 pm
by R4000
You all seem pretty quick to judge this method, but i know for a fact that two projects i have seen, that proberly dont even know each other exist... and certainly dont share devs... use this method.

Allthough i totaly agree with the fact it is not needed, and does not really have and real protective value.
These projects are using it to stop the simple things like i said before... what if you code with register_globals off? (as i do), but then some IDIOT with it on, installs your project. yes you could code around that.

You might not see the point in it, but it is proving to be highly usefull in my dev server.