Search Unity

WWW Class Wierdness

Discussion in 'Scripting' started by marty, Aug 17, 2007.

  1. marty

    marty

    Joined:
    Apr 27, 2005
    Posts:
    1,170
    I'm using (an adaptation of) the online highscores table example from the Unify Wiki in a project of mine.

    It worksf just ine when I run it in the Unity editor - saves the scores to the MySQL database and so on. The thing is, when I run the built Unity.webapp on the server, it doesn't write to the database anymore.

    Anyone have any idea what might cause that sort of wierdness to happen?
     
  2. andeeeee

    andeeeee

    Joined:
    Jul 19, 2005
    Posts:
    8,768
    From a little bit of testing I have just done, it seems that firstly, the web player can only communicate with a PHP script in the folder it is being served from (ie, the web player file and the PHP script must be in the same folder on the server) and secondly, the web player identifies itself as the browser, not as Unity Player.

    Check that your PHP script is in the same folder as your player and remove the "if" statement from the PHP that looks like this:-

    Code (csharp):
    1. if ($_SERVER['HTTP_USER_AGENT'] == "UnityPlayer/1.1 ([url]http://www.otee.dk[/url])")
    (I am assuming you are referring back to the example from your earlier post.)

    However, without this "if" statement, the script will accept updates from anywhere - it is there to stop people falsifying high scores. If you want this protection for the web player then you will need a second PHP script that responds to the web player separately. This script is similar but checks that the referring page is the one that houses your player rather than querying the user agent. You would replace the "if" statement above with something like:-

    Code (csharp):
    1. if ($_SERVER['HTTP_REFERER'] == "([url]http://www.marty.com/UniGame/unigameHolder.htm[/url])") {
    2.     ...
    3. }
    Note that both of these forms of protection are very weak - you would need something a bit more sophisticated if you really want to ensure the scores are valid.
     
  3. marty

    marty

    Joined:
    Apr 27, 2005
    Posts:
    1,170
    Okay, Andeeee. I'm getting close.

    I removed the IF statement altogether and everything works fine.

    Of course, as you inform me, I cannot deploy like that because it would open me up to DS attacks, spoofing and gingivitis.

    The thing is, I've tried several variations of the IF statement, all to no avail. If the IF is there, it does not work.

    Apparently, I am not writing the user agent stuff correctly.
     
  4. MatthewW

    MatthewW

    Joined:
    Nov 30, 2006
    Posts:
    1,356
  5. marty

    marty

    Joined:
    Apr 27, 2005
    Posts:
    1,170
    Good deal!

    I ripped out the referrer stuff altogether and went with a combination of (1) using and included db.inc.php file to secure my database login info, and (2) using MD5 encryption of the player/score data being passed from the game to the server.

    Now, everything appears to work perfectly as well as securely.

    There's event a hint of minty freshness in the air now!

    Thanks again, everyone!
     
  6. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    Maybe someone should update the script on the wiki to work correctly with the web player. The checksum method seems like the way to go.
     
  7. marty

    marty

    Joined:
    Apr 27, 2005
    Posts:
    1,170
    Actually, I intend do just that.

    I want to clean everything up and make it more presentable first though.

    Which means it will have to wait until after Top Dawg!
     
  8. freyr

    freyr

    Joined:
    Apr 7, 2005
    Posts:
    1,148
    I've just updated the wiki page so it uses a shared secret method of authenticating the client using an md5 checksum.
     
  9. marty

    marty

    Joined:
    Apr 27, 2005
    Posts:
    1,170
    Thank goodness freyr never sleeps! ;-)
     
  10. marty

    marty

    Joined:
    Apr 27, 2005
    Posts:
    1,170
    Freyr, I'm curious.

    Isn't all the information necessary (for a spoofer) to pass bogus high scores to the high scores table right there in the addScore.php file - namely, the secretkey and hash?
     
  11. freyr

    freyr

    Joined:
    Apr 7, 2005
    Posts:
    1,148
    Yup.

    That's why you have to modify the secret key to something different.

    The spoofer should not have access to the source of the add_score.php script.
     
  12. marty

    marty

    Joined:
    Apr 27, 2005
    Posts:
    1,170

    Maybe this is the big point I'm missing. Isn't the addScore.php script right there on the website where anyone can download and look at it?
     
  13. freyr

    freyr

    Joined:
    Apr 7, 2005
    Posts:
    1,148
    Only the output generated from it. PHP scripts are executed on the server, so the cllient should never see the actual code inside.
     
  14. marty

    marty

    Joined:
    Apr 27, 2005
    Posts:
    1,170
    But couldn't they just do a site rip and get the PHP script?
     
  15. andeeeee

    andeeeee

    Joined:
    Jul 19, 2005
    Posts:
    8,768
    The website is only as secure as its security. If someone is in a position to access the unprocessed PHP code then you can't do much about it. However, if you make full use of the web server's security then it should be difficult for an outsider to gain this kind of access. Also, another trick is to store the secret data in a file outside the web folder and load it into the PHP script at runtime (ie, the data isn't stored inside the script) - this is a nice little bit of "insurance" against security lapses and oversights.

    Basically, if you switch on all straightforward safety features then it generally won't be worth an attacker's while to try and break them. At least not unless you are offering a big cash prize for the highest score!
     
  16. marty

    marty

    Joined:
    Apr 27, 2005
    Posts:
    1,170
    The bastards.
     
  17. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    How are they going to do that without ftp access? PHP isn't like Javascript where you can just look at the page source and see the code. (Server-side vs. client-side.)

    --Eric
     
  18. marty

    marty

    Joined:
    Apr 27, 2005
    Posts:
    1,170
    They could use a site-ripper (i.e. WebDevil, DeepVacuum) to download the root and all sub- and remote- directories used by the game, with no more a-priori knowledge than the URL of the game itself.

    The stinking bastards.
     
  19. andeeeee

    andeeeee

    Joined:
    Jul 19, 2005
    Posts:
    8,768
    These tools will only download the *output* of the PHP scripts - they communicate with the web server via HTTP so it's only the same as making lots of separate page requests from the browser. It's much more difficult to fool the server into coughing out the unprocessed PHP code (usually the result of bad configuration and quite easy to spot during testing). Also, if you use the technique I mentioned (put any secret data in a file outside the web folder) then it won't do the attacker any good even if they *do* manage to view the PHP. There shouldn't be any way they can get at the secret unless they have SSH access or a key to the server room and the right password. If they do have these then you've likely got much worse things to worry about than false high scores.
     
  20. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    They can do no such thing. ;) "Site-rippers" can only access the site the same way as any other anonymous user can. They have no magical powers to somehow divine your login and password. They have no ability to read directories that have permissions set to 711 or do anything else that someone with no direct access to your site can't do.

    --Eric
     
  21. marty

    marty

    Joined:
    Apr 27, 2005
    Posts:
    1,170
    My lacking knowledge of web technology has bitten me soundly in the butt.

    I didn't realize that PHP was rendered server-side, thus leaving only fully hashed-out PHP for the rippers.

    Very cool indeed!

    Thanks, all!
     
  22. marty

    marty

    Joined:
    Apr 27, 2005
    Posts:
    1,170
    Okay, now I've got a new wrinkle in this ongoing dilema ...

    My MD5 hash values, as generated by the Unify Wiki Unity Javascript and PHP, are not matching.

    Here's my Unity calling code:

    Code (csharp):
    1.         //  do md5 security check
    2.         var hash = md5.Md5Sum(playerName + score + "secretkey");
    3.  
    4.         //  build WWW class call string, starting with server URL
    5.         var highscore_url ="http://something.com/addScore.php?";
    6.        
    7.         //  add passed info to stirng
    8.         highscore_url += "name=" + playerName + "&score=" + score + "&hash=" + hash;
    9.        
    10.         //  WWW call
    11.         hs_post = WWW(highscore_url);

    And here's my PHP calling code:

    Code (csharp):
    1. <?php
    2.    
    3.     $secretkey = "secretkey";
    4.     $name = $_GET['name'];
    5.     $score = $_GET['score'];
    6.     $hash = $_GET['hash'];
    7.  
    8.  
    9.     $real_hash = md5($name + $score + $secretkey);
    10.    
    11.     //  get login info
    12.     require_once("includes/db.inc.php");
    13.    
    14.    
    15.     if ($real_hash == $hash) {
    16.    
    17.         //  get database login info from secure file and connect to database
    18.         $query = "insert into scores values (NULL, '$name', '$score');";
    19.         $result = mysql_query($query) or die('Query failed: ' . mysql_error());
    20.    
    21.     } else {
    22.    
    23.     $name = $hash;
    24.     $query = "insert into scores values (NULL, '$name', '$score');";
    25.     $result = mysql_query($query) or die('Query failed: ' . mysql_error());
    26.    
    27.     $name = $real_hash;
    28.     $query = "insert into scores values (NULL, '$name', '$score');";
    29.     $result = mysql_query($query) or die('Query failed: ' . mysql_error());
    30.    
    31.     }
    32.        
    33. ?>

    Any ideas, suggestions or corrections to my inestimable stupidity would be greatly appreciated!

    ;-)
     
  23. andeeeee

    andeeeee

    Joined:
    Jul 19, 2005
    Posts:
    8,768
    The PHP script is attempting to use the plus operator for string concatenation. The concat operator is actually dot "." in PHP:-
    Code (csharp):
    1. $real_hash = md5($name + $score + $secretkey);
    It was actually doing (meaningless) arithmetic on the values. The wiki script was wrong, it wasn't anything you did.

    Actually, now I have looked at the wiki version of addscore.php, I have noticed it also contains a pretty serious SQL injection vulnerability. The wiki doesn't appear to be responding at the moment, but I'll post the fixed version of the script as soon as possible.
     
  24. marty

    marty

    Joined:
    Apr 27, 2005
    Posts:
    1,170
    Thanks, Andeeee!

    Feel free to post it here too, for anyone who might be following this thread.

    ;-)
     
  25. andeeeee

    andeeeee

    Joined:
    Jul 19, 2005
    Posts:
    8,768
    Yes, good idea:-
    Code (csharp):
    1. <?php
    2.         $db = mysql_connect('mysql_host', 'mysql_user', 'mysql_password') or die('Could not connect: ' . mysql_error());
    3.         mysql_select_db('my_database') or die('Could not select database');
    4.  
    5.         // Strings must be escaped to prevent SQL injection attack.
    6.         $name = mysql_real_escape_string($_GET['name'], $db);
    7.         $score = mysql_real_escape_string($_GET['score'], $db);
    8.         $hash = $_GET['hash'];
    9.  
    10.         $secret_key="mySecretKey"; # Change this value to match the value stored in the client javascript below
    11.  
    12.         $real_hash = md5($name . $score . $secretKey);
    13.         if($real_hash == $hash) {
    14.             // Send variables for the MySQL database class.
    15.             $query = "insert into scores values (NULL, '$name', '$score');";
    16.             $result = mysql_query($query) or die('Query failed: ' . mysql_error());
    17.         }
    18. ?>
    (Without the escapes, it might be possible for someone to do serious damage to the database, see information they shouldn't, etc... Ideally, the game should warn the user not to enter anything but letters, numbers and hyphens to avoid surprises.)

    The wiki page seems to go crazy when I try to replace the existing code with this, but I'll see if I can update it somehow.
     
  26. marty

    marty

    Joined:
    Apr 27, 2005
    Posts:
    1,170
    So, another way to avoid this potnetial problem would be to not allow the user to enter anything orther than alphanumeric characters (and maybe a few other safe characters) when they enter their name.

    Correct?
     
  27. Jonathan Czeck

    Jonathan Czeck

    Joined:
    Mar 17, 2005
    Posts:
    1,713
    No, because even if you secure things on the Unity side, someone could still attack from outside of your Unity game/app. Say, with a web browser or curl from the command line.

    Cheers,
    -Jon
     
  28. marty

    marty

    Joined:
    Apr 27, 2005
    Posts:
    1,170
    Dangit. Good point, JC.

    Well, I finally got it all to work - unlike merely appearing to work, as I had previously. :oops:

    Tons of thanks to all of you friendly reply-ers!