- Home /
I need a solution to SQL, saving and loading data and security/antipiracy
Alright well I've been building with unity and now I'm at a point where I would like to setup a sql database to manage my users who play the game. This sql server will maintain encrypted data about players their save states and any other important game information. The problem I'm reading about is that apparently unity games can be decompiled and all of my encryption code can be read, including login information for my sql database and any other private information I compile with unity. Is it true that I need to be concerened about people decompiling my unity game and logging into my sql database to destroy its functionality and possibly give out private information about users who play my games. I've literally invested hundreds of dollars/hours with the unity platform and now am I to understand that this is a very real threat to my games? Is there a solution to this seemingly massive security risk?
Answer by Ony · Jun 21, 2013 at 09:03 PM
The way I handle it is by having Unity call on a server-side php script (via www) that does all the database work, then it sends the info I asked for back to Unity. This way all of the database connectivity stuff gets handled server-side and is secure, and the only thing Unity gets is what that secure script gives it.
If you need more info or example of how to call on a script like that, let me know and I'll expand my answer.
Actually I could use some direction on how to setup the gateway that can connect securely to my SQL database and then send that data back to the game client. I actually just emailed my professor about this question too because I'm thinking I need to write a gateway server in php that just takes a set number of commands from the game client then in return talks to the database then sends the correct data back to the client. The concept is clear but the implementation part is a bit hairy for me. Any help you could give would be greatly appreciated! I have this all running on a home desktop just for my test purposes on the same desktop i have running my wiki for my $$anonymous$$ms development collaboration etc... But later I plan on migrating over to googles cloud sql service or perhaps something like smartfox but of course before I migrate I want to get the code running on virtual machines on my own desktop so I can work out all the kinks, again any help would be a huge help to this fledgling developer! :-)
Ok, what follows is some code that should get you started. It basically calls on a script on your server that then connects to a user database. It checks to see if the username and password the user entered into a form in Unity match up to what's in the database. If they match, it sends back the word "CORRECT!" to your game. Otherwise it sends back the word "WRONG". Obviously you will need a database set up and you'll need to enter the details for it in the top section of the php script.
The first code is for a Unity script, and the second is the php script.
I originally got some of this code from someone else, then edited it for my game, then for you I edited it further, so hopefully it all works now as intended. It works fine in my game but the changes I made here might throw up some errors as I haven't tested this particular incarnation. :)
This Answers thing only lets me put a certain number of characters into a reply so I have to split this all up into three comments.
First up, the Unity code (Javascript):
var hash : String = "myHash"; //must match php script $phpHash variable!
function Login() {
var form = new WWWForm(); //here you create a new form connection
form.AddField( "myform_hash", hash ); //adds your hash code to the field myform_hash
form.AddField( "myform_nick", formNick );
form.AddField( "myform_pass", formPassword );
// this now calls on your server-side script...
var w = WWW("http://www.YOURSIT$$anonymous$$CO$$anonymous$$/scripts/check_user.php", form); //here we create a var called 'w' and we sync with our URL and the form
yield w; //we wait for the form to check the PHP file, so our game doesn't just hang
if (w.error != null)
{
// there was an error getting the result...
Debug.Log("ERROR!");
}
else
{
formText = w.text.Trim(); //here we return the data our PHP told us
Debug.Log("RESULT: "+formText);
//if the script says "CORRECT" then we can log this user in...
if (formText == "CORRECT")
{
Debug.Log("username check : CORRECT");
// log the user in...
// (Your login code goes here, or call a function, or whatever.
// In other words, the user checks out, so do whatever you need to do now with that information. :)
}
w.Dispose(); //clear our form in game
}
formPassword = ""; // clear password field if not correct...
passwordWarning = "wrong username or password!";
}
function OnGUI() {
// this will need to be changed according to your GUI needs, of course...
GUI.skin = customSkin;
GUI.BeginGroup (Rect (((Screen.width / 2) - 512), ((Screen.height / 2) - 384), 1024, 768));
GUILayout.BeginArea (Rect (400, 180, 300, 120));
GUILayout.BeginHorizontal();
GUILayout.BeginVertical();
GUILayout.Label( "username:" );
GUILayout.Space (16);
GUILayout.Label( "password:" );
GUILayout.EndVertical();
GUILayout.BeginVertical();
formNick = GUILayout.TextField (formNick, 32, GUILayout.Width(180));
formPassword = PasswordField (formPassword, "*" );
GUILayout.Label( passwordWarning);
GUILayout.EndVertical();
GUILayout.EndHorizontal();
GUILayout.EndArea();
GUILayout.BeginArea (Rect (300, 310, 420, 110));
GUILayout.BeginHorizontal();
GUILayout.BeginVertical();
if (( GUILayout.Button ("Login", GUILayout.Width(90) ) ) && (loginButtonLive)){
Login();
}
GUILayout.EndVertical();
GUILayout.EndHorizontal();
GUILayout.EndArea();
GUI.EndGroup ();
}
Secondly, the php code, named check_user.php:
<?php
//error_reporting(E_ALL);
// CONNECTIONS =========================================================
$my_host = "localhost"; // Your mySQL server host address
$mydb = "yourSQLdatabase"; // The name of the database to use
$my_user = "yourSQLusername"; // Your mySQL username
$my_pass = "yourSQLpassword"; // Your mySQL password
$database = mysql_connect($my_host, $my_user, $my_pass) or die('Could not connect: ' . mysql_error());
mysql_select_db($mydb) or die('Could not select database');
// =============================================================================
// PROTECT AGAINST SQL INJECTION and CONVERT PASSWORD INTO $$anonymous$$D5 formats
function anti_injection_login_senha($sql, $formUse = true)
{
$sql = preg_replace("/(from |select |insert |delete |where |drop table|show tables|,|'|#|\*|--|\\\\)/i","",$sql);
$sql = trim($sql);
$sql = strip_tags($sql);
if(!$formUse || !get_magic_quotes_gpc())
$sql = addslashes($sql);
$sql = md5(trim($sql));
return $sql;
}
// THIS ONE IS JUST FOR THE NIC$$anonymous$$NA$$anonymous$$E PROTECTION AGAINST SQL INJECTION
function anti_injection_login($sql, $formUse = true)
{
$sql = preg_replace("/(from |select |insert |delete |where |drop table|show tables|,|'|#|\*|--|\\\\)/i","",$sql);
$sql = trim($sql);
$sql = strip_tags($sql);
if(!$formUse || !get_magic_quotes_gpc())
$sql = addslashes($sql);
return $sql;
}
// =============================================================================
$unityHash = anti_injection_login($_POST["myform_hash"]);
$phpHash = "myHash"; // same code in here as in your Unity game in the hash variable
$nick = anti_injection_login($_POST["myform_nick"]); // I use this function to protect against SQL injection
$pass = anti_injection_login_senha($_POST["myform_pass"]);
// defaults...
$userid = "";
$logins = "";
$registered = "";
$forceUpdate = "";
if ((!$nick || !$pass) || ($unityHash != $phpHash))
{
echo $nick;
echo "Sorry, you're not authorized to be here!";
}
else
{
// get userID
$query = "SELECT user_id, registered FRO$$anonymous$$ login_users WHERE username = '$nick' AND password = '$pass'";
$result = mysql_query($query) or die('Query failed: ' . mysql_error());
while ($row = mysql_fetch_array($result))
{
$userid = $row['user_id'];
$registered = $row['registered'];
}
// send info to the game...
if ($userid != "") && ($registered != "")
{
echo "CORRECT";
}
else
{
echo "WRONG";
}
}
// Close mySQL Connection
mysql_close();
?>
$$anonymous$$y professor responded with:
Yeah, if you have the decryption key on the client machine, then that can be exposed.
So, it sounds like you want to create an application layer to sit between the client and the database. That layer would basically be a collection of web service type stuff that the client would use to get/send data that would go back to the database.
The first line of defense against sql injection is to not use dynamic sql and only use stored procedures, it's far more challenging to inject through parameters. Second line is validation of data to be well formed, which you can do on the client machine as a first step, as well as at the web services as well.
You'll want to put security on the web services, so that the user is required to login to the game and once authenticated by the web server that security token would be sent to those web services that you feel require authenticated access. You wouldn't want the client to have any kind of database awareness, unless you have a local (client side) database that it keeps things in.
With any client-server system, you'll want to think about a caching system to reduce the amount of calls to the server as well as calls to the database. So, the client should remember things and the app server should remember things, the key thing there is you need to make them forget those things that are out of date.
Answer by AmoralAckbar · Jun 21, 2013 at 03:42 PM
You aren't going to be able to protect against people being able to decompile or use reflection to get into your code. However, there are a couple things you can do to reduce risk.
Don't put your SQL credentials in plain text anywhere in your code. If they aren't hardcoded, someone can't just read them if you decompile stuff. Instead, you want your code to read them in from an encrypted file. There are tons of good encryption libraries out there that you can use to encrypt a configuration file that includes connection information. This will keep your actual credentials safe on the local PC.
If you are overly freaked out about someone decompiling your stuff, you can look into code obfuscation, which just makes it a hell of a lot harder to read anything you have decompiled. Off hand, I am not sure if Unity supports any obfuscation or if you would have to hack it together. My opinion is that this is not needed.
Manage your SQL server correctly. Use credentials for your game that only have access and permissions to do stuff that you want them to do. If you are not well versed in SQL, now's the time.
If you really want a solid solution for using a local fat client to access a SQL server, your best bet is to build a web service that handles all the SQL server communication. You call into the web service from your game (ie "Get rank info") and then the web service has the credentials stored only on the server side. The web service logs into the SQL server, gets what you want and sends it back down to you.
Answer by Arive2 · Oct 14, 2016 at 05:54 AM
@Ony, you're amazing. Thank you!
Woo! Glad that helped, even from all the way back in 2013. I switched over to c# not long after originally posting this so if anyone needs it in c#, let me know. :)
I would love to see this in C# if possible. I'm just getting started, and this looks like it will be super useful in getting me a jump start on what I need to do.
I haven't used a login script like this in a while now and can't seem to find the c# version in my files. Not even sure now if I ever actually converted this particular script.
I recently made a game for a client and it needed a login system, so I ended up using the one here ( https://www.assetstore.unity3d.com/en/#!/content/16120 ) and modifying it slightly to add in additional injection protection on the server-side script.
It works great and has more options (forgot password, create account, etc.) than I had in my original script posted here. So, I'd recommend checking it out if you're in the market for a robust c# solution that's more up to date with current Unity versions. For the record, I don't have any personal connection with that particular asset, but it did work out really nicely so I'm happy to recommend it. :)
Answer by acriticalstrike · Jun 21, 2013 at 10:42 PM
Actually I could use some direction on how to setup the gateway that can connect securely to my SQL database and then send that data back to the game client. I actually just emailed my professor about this question too because I'm thinking I need to write a gateway server in php that just takes a set number of commands from the game client then in return talks to the database then sends the correct data back to the client. The concept is clear but the implementation part is a bit hairy for me. Any help you could give would be greatly appreciated! I have this all running on a home desktop just for my test purposes on the same desktop i have running my wiki for my teams development collaboration etc... But later I plan on migrating over to googles cloud sql service or perhaps something like smartfox but of course before I migrate I want to get the code running on virtual machines on my own desktop so I can work out all the kinks, again any help would be a huge help to this fledgling developer! :-)
Yes, that's exactly what I gave you in the scripts. The screen shot you show is the way the form in Unity will display the login form, yes. But you also have to set up the php script I gave you, and put it on your server.