Simple LoginServer
by Stefan Lundmark · 04/02/2004 (1:17 pm) · 19 comments
I posted a while ago helping two individuals with some loginserver information.
Today when I looked in my email, it turned out that a bunch of people wanted to have some examples on how it would look like.
I'm by no means a programmer, I'm merely trying to learn script and some C++ while I'm here doing some art for our project.
The following will be code snippits and comments. Recommendations and modifications are very welcome!
I also want to say thank you to John Vanderbeck, Peter Andersson, Melvyn May, Phil Carlisle, Ben Garney, Gerald Fishel and Matthew Fairfax for making this possible.
I consider this abit help I can give back to the community for so much you have helped me, at least I hope so.
This is my first resource and I really feel it's difficult for me to get everything simple, so that everyone else understands; but I'll try to be as clear as possible. Additionally, anyone can contact me or post here if they want help.
Puh, that's alot. Let's start.
____________________________________________
I want to point out that you need some basic knowledge of TorqueScript to pull this off, and be fairly oriented in mySQL.
If you haven't got mySQL in TGE yet, please consult this link.
To start with, you'll need a logindialog of some kind. Mine had two editboxes (username & password) and two buttons (proceed & cancel).
The two editboxes were tied to two strings in the client/prefs.cs script, so let's add them there.
Save the modifications to the file and proceed to your loginscript or dialog, and add these two to your editboxes.
For instance.
Now make a button or whatever you'd like to execute a simple command.
It sends the username & password fields to the server and tells it to "check" them.
The server does not know what to do with the command or what it means, so let's make it "understand".
In server/scripts/login.cs (which you will need to create).
The function will bind the two pref.cs strings to %AuthUser and %AuthPass on the server.
It will then validate and log you in to your mySQL server. Open up your database and Select from all rows where username and password is the ones supplied with the strings from the client.
It will only work if the username and password is in the same row and they are identical to the database's stored ones.
IF the database returns a row where it has a match, it will send you back a logincall.
IF the database does not return a value, it will send loginfailed to the client.
You will need to make a command on the client that responds to these calls, or place whatever code inbetween that you need.
The above can be done in one command using a variable instead, but I haven't done that in this version of the loginscript.
Also, you SHOULD log/call something on the server when the client get's authed, or whenever she types the correct information.
____________________________________________
I have done it the way that I'm logging the IP number and setting a flag to "true" which the gameserver checks each time the client logs in.
Also, to avoid misuse of the mySQL commands I've made scripts on the server and the client that both forbid certain words and spaces in the editbox fields.
I think this is very important.
The full code for that is a bit long and it would take too long to include here right now.
Something I did as well was to rip out the terrain, most of the GUI, audio and interior code to make it "impossible" to hack the server.. if you only want it to be a loginserver, that is ;)
Then keep the binary seperate from the normal gameservers.
If the user modifies the strings while the session is running on a gameserver, the server might want to disconnect the user and log the event somewhere.
That's all that I did right now.
Make sure the new server/scripts/login.cs script is executed on server startup.
____________________________________________
I really hope this says something and that it gives you a clue, if it does not.. make sure to point it out for me and I'll see what I can do :)
There are also a bunch of very helpful members out there that might have improvements and/or suggestions so keep checking back.
I'll edit this post with updates if/when there are any.
Sincerely
Stefan Lundmark
Today when I looked in my email, it turned out that a bunch of people wanted to have some examples on how it would look like.
I'm by no means a programmer, I'm merely trying to learn script and some C++ while I'm here doing some art for our project.
The following will be code snippits and comments. Recommendations and modifications are very welcome!
I also want to say thank you to John Vanderbeck, Peter Andersson, Melvyn May, Phil Carlisle, Ben Garney, Gerald Fishel and Matthew Fairfax for making this possible.
I consider this abit help I can give back to the community for so much you have helped me, at least I hope so.
This is my first resource and I really feel it's difficult for me to get everything simple, so that everyone else understands; but I'll try to be as clear as possible. Additionally, anyone can contact me or post here if they want help.
Puh, that's alot. Let's start.
____________________________________________
I want to point out that you need some basic knowledge of TorqueScript to pull this off, and be fairly oriented in mySQL.
If you haven't got mySQL in TGE yet, please consult this link.
To start with, you'll need a logindialog of some kind. Mine had two editboxes (username & password) and two buttons (proceed & cancel).
The two editboxes were tied to two strings in the client/prefs.cs script, so let's add them there.
$pref::Username = "Stefan"; $pref::Password = "Blaha";
Save the modifications to the file and proceed to your loginscript or dialog, and add these two to your editboxes.
For instance.
new GuiTextEditCtrl() {
profile = "GuiTextEditProfile";
horizSizing = "right";
vertSizing = "bottom";
position = "82 83";
extent = "130 18";
minExtent = "8 8";
visible = "1";
variable = "$pref::Password";
maxLength = "255";
historySize = "0";
password = "1";
tabComplete = "0";
sinkAllKeyEvents = "0";
helpTag = "0";
};Do the same with the username field, but change the variable.Now make a button or whatever you'd like to execute a simple command.
It sends the username & password fields to the server and tells it to "check" them.
new GuiBitmapButtonCtrl() {
profile = "GuiDefaultProfile";
horizSizing = "right";
vertSizing = "bottom";
position = "287 28";
extent = "80 27";
minExtent = "8 2";
visible = "1";
command = "commandToServer('LoginCheck', $pref::Password, $pref::Username);";
lockMouse = "0";
bitmap = "~/sprites/gui/probutton01.png";
HighlightBitmap = "~/sprites/gui/probutton01.png";
PressedBitmap = "~/sprites/gui/probutton02.png";
wrap = "0";
};You *should* store the strings each time, at least the username. I won't go into detail about that here though.The server does not know what to do with the command or what it means, so let's make it "understand".
In server/scripts/login.cs (which you will need to create).
function ServerCmdLoginCheck(%client, %AuthPass, %AuthUser)
{
%login= new MySQL();
%login.host= "localhost";
%login.port= 3306;
// user information
%login.user= "administrator";
%login.pwd= "whatever";
// connection flags
%login.flag_compress= false;
%login.flag_ssl= true;
// database to use
%login.db= "mygame";
// ----------------------------------------------------
// echo
%login.ValidateSettings();
%login.Connect();
%login.Query ("SELECT * FROM myusers WHERE Username=\"" @ %AuthUser @ "\" AND Password = \"" @%AuthPass @ "\"");
%result= %login.StoreResult();
if (%login.NumRows (%result) > 0)
{
echo("Access Granted");
commandToClient(%client, 'Login');
}
if (%login.NumRows (%result) < 1)
{
echo(" ");
echo("Access Denied");
echo(" ");
commandToClient(%client, 'LoginFailed');
}
%login.FreeResult(%result);
%login.Close();
}The function will bind the two pref.cs strings to %AuthUser and %AuthPass on the server.
It will then validate and log you in to your mySQL server. Open up your database and Select from all rows where username and password is the ones supplied with the strings from the client.
It will only work if the username and password is in the same row and they are identical to the database's stored ones.
IF the database returns a row where it has a match, it will send you back a logincall.
IF the database does not return a value, it will send loginfailed to the client.
You will need to make a command on the client that responds to these calls, or place whatever code inbetween that you need.
The above can be done in one command using a variable instead, but I haven't done that in this version of the loginscript.
Also, you SHOULD log/call something on the server when the client get's authed, or whenever she types the correct information.
____________________________________________
I have done it the way that I'm logging the IP number and setting a flag to "true" which the gameserver checks each time the client logs in.
Also, to avoid misuse of the mySQL commands I've made scripts on the server and the client that both forbid certain words and spaces in the editbox fields.
I think this is very important.
The full code for that is a bit long and it would take too long to include here right now.
Something I did as well was to rip out the terrain, most of the GUI, audio and interior code to make it "impossible" to hack the server.. if you only want it to be a loginserver, that is ;)
Then keep the binary seperate from the normal gameservers.
If the user modifies the strings while the session is running on a gameserver, the server might want to disconnect the user and log the event somewhere.
That's all that I did right now.
Make sure the new server/scripts/login.cs script is executed on server startup.
____________________________________________
I really hope this says something and that it gives you a clue, if it does not.. make sure to point it out for me and I'll see what I can do :)
There are also a bunch of very helpful members out there that might have improvements and/or suggestions so keep checking back.
I'll edit this post with updates if/when there are any.
Sincerely
Stefan Lundmark
About the author
#2
One thing. You should preformat those strings before using them in your query.
%AuthUser = "'" @ %AuthUser @ "'";
%AuthPass = "'" @ %AuthPass @ "'";
04/02/2004 (2:55 pm)
Nice one Stefan. This is a great resource.One thing. You should preformat those strings before using them in your query.
%AuthUser = "'" @ %AuthUser @ "'";
%AuthPass = "'" @ %AuthPass @ "'";
#3
because you never strip out the ' and " characters in the password or username, a user could simply bypass the check by giving a password like this:
---
User: Bleh
Pass: ..." OR 1=1 OR ""="
---
With the first ", it terminates the password field in the mysql query, then putting an OR 1=1 telling the mysql to succeed no matter what. The ""=" part is just for the last closing " after the password.
To fix this, you should look for a similar function to php's addslashes, or mysqls mysql_realescape or something.
There's more info on this on the mysql website.
Anyway, NEVER EVER just forward your data into a mysql query, let the program check it first!
---
PS Might be Torque already adds slashes, which i doubt. if so, just correct me :P
PPS By using this same technique you are also able to put in your own queries with a few semicolons >:]
04/02/2004 (3:55 pm)
In PHP i used MySQL, and it seems this script is VERY dangerous.because you never strip out the ' and " characters in the password or username, a user could simply bypass the check by giving a password like this:
---
User: Bleh
Pass: ..." OR 1=1 OR ""="
---
With the first ", it terminates the password field in the mysql query, then putting an OR 1=1 telling the mysql to succeed no matter what. The ""=" part is just for the last closing " after the password.
To fix this, you should look for a similar function to php's addslashes, or mysqls mysql_realescape or something.
There's more info on this on the mysql website.
Anyway, NEVER EVER just forward your data into a mysql query, let the program check it first!
---
PS Might be Torque already adds slashes, which i doubt. if so, just correct me :P
PPS By using this same technique you are also able to put in your own queries with a few semicolons >:]
#4
Read my reply before yours. Stefan already knows about the injection hole as I explained it to him a while back. Just need to preformat the strings like I showed above and you'll be fine. Note though that Stefan mentioned that he prechecks them and strpis out certain keywords. Its easier and safer to just preformat them as I indicated though.
04/02/2004 (5:21 pm)
@F.W.Read my reply before yours. Stefan already knows about the injection hole as I explained it to him a while back. Just need to preformat the strings like I showed above and you'll be fine. Note though that Stefan mentioned that he prechecks them and strpis out certain keywords. Its easier and safer to just preformat them as I indicated though.
#5
Hope this is useful for you.
04/02/2004 (6:22 pm)
As Ron stated though, linking mySQL isn't a very robust option. Not to mention that having the database access password stored INSIDE the game code is not very secure as .dso's are easily decompilable besides the fact that if you ever want to change your password you need to relaunch the game or a patch. The way I have done this in the past and has worked perfectly (even using md5 hash passwords) was to have a web script that had the database user and password, so the client accessed the web script and the script logged in and checked the info the client was passing through the url arguments. This is what Ron was saying with his ASP example btw, although I did it in PHP.Hope this is useful for you.
#6
04/02/2004 (8:48 pm)
I'm going to test this out, and i'll put some of the gameing communities best hackers on it (when my game is finished and in beta)
#7
I have already adressed this issue, as John said. ;)
Look in the resource, it says this;
[quote]Also, to avoid misuse of the mySQL commands I
04/03/2004 (12:34 am)
F.WI have already adressed this issue, as John said. ;)
Look in the resource, it says this;
[quote]Also, to avoid misuse of the mySQL commands I
#8
Also forbidding certain things is not the way to go, because it would limit usability.
If i where you, I'd try to export mysql_realescape to TorqueScript :)
04/03/2004 (2:29 am)
Preformatting the strings like Vanderbeck wont really help i think, because those can also be bypassed.Also forbidding certain things is not the way to go, because it would limit usability.
If i where you, I'd try to export mysql_realescape to TorqueScript :)
#9
It does not really limit usability, as it only forbids spaces (AND, OR - such too). You dont need much more in a username.
But hey, whats the mysql_realescape thing? Havent head of it before, please explain. Im very interested :]
04/03/2004 (3:03 am)
F.WIt does not really limit usability, as it only forbids spaces (AND, OR - such too). You dont need much more in a username.
But hey, whats the mysql_realescape thing? Havent head of it before, please explain. Im very interested :]
#10
You're right but only because I was half asleep when I wrote it. My apologies all. I goofed that when I wrote it. Don't know what I was thinking.
The correct way is to REPLACE any single quotes in the string with TWO single quotes.
You can see the post that I made in the original thread when Stefan was working on this. I explain it better in there.
Basically you can use the TorqueScript "strreplace()" function to replace single quotes with double quotes. Just do that before you pass it into the SQL query.
That will prevent pretty much any known SQL injection (Though NOTHING is 100% bulletproof).
04/03/2004 (7:12 am)
Quote: Preformatting the strings like Vanderbeck wont really help i think, because those can also be bypassed.
You're right but only because I was half asleep when I wrote it. My apologies all. I goofed that when I wrote it. Don't know what I was thinking.
The correct way is to REPLACE any single quotes in the string with TWO single quotes.
You can see the post that I made in the original thread when Stefan was working on this. I explain it better in there.
Basically you can use the TorqueScript "strreplace()" function to replace single quotes with double quotes. Just do that before you pass it into the SQL query.
That will prevent pretty much any known SQL injection (Though NOTHING is 100% bulletproof).
#11
While searching the net for some SQL syntaxes.. I found this.
Pretty funny how your posts are everywhere, they are great help. :)
John Vanderbeck
I don't even know how to call that function in TorqueScript and how to pass it on but.. seems like it should work better than hardcoding it into the engine.
04/03/2004 (8:11 am)
Ron YackettaWhile searching the net for some SQL syntaxes.. I found this.
Pretty funny how your posts are everywhere, they are great help. :)
John Vanderbeck
I don't even know how to call that function in TorqueScript and how to pass it on but.. seems like it should work better than hardcoding it into the engine.
#12
As someone mentioned, there are routines in place to properly escape variables. But do you really want to pass anything to the database? IS linking with the mySQL libs really is a good solution when they're under GPL? I was under the impression that if you linked against a non-static GPL library your software wouldn't have to be released under the GPL. Maybe that's LGPL?
04/03/2004 (8:19 am)
John, The correct way would be (IMO) to escape all special characters. When you want security you never look at the cases which aren't allowed, you identify the allowed cases and ban the rest. That way you can't overlook things only be incompetent in identifying allowed cases. Won't replacing every single quote with two single quotes (padding) give you improper behaviour as well? Ie "Peter's" would become "Peter''s" which most likely isn't what you want? Maybe I misunderstood.As someone mentioned, there are routines in place to properly escape variables. But do you really want to pass anything to the database? IS linking with the mySQL libs really is a good solution when they're under GPL? I was under the impression that if you linked against a non-static GPL library your software wouldn't have to be released under the GPL. Maybe that's LGPL?
#13
Correct me if Im wrong but it would not be a problem for an internal server anyway.
04/03/2004 (9:23 am)
Peter AnderssonCorrect me if Im wrong but it would not be a problem for an internal server anyway.
Quote:
As long as you never distribute (internally or externally) the MySQL Software in any way, you are free to use it for powering your application, irrespective of whether your application is under GPL license or not.
#14
my bad, it isnt mysql_realescape
but its:
mysql_real_escape_string
read about it here:
http://www.mysql.com/documentation/mysql/bychapter/manual_Clients.html#mysql_real_escape_string
04/03/2004 (11:31 am)
Oops :Pmy bad, it isnt mysql_realescape
but its:
mysql_real_escape_string
read about it here:
http://www.mysql.com/documentation/mysql/bychapter/manual_Clients.html#mysql_real_escape_string
#15
04/06/2004 (4:51 am)
Instead of stripping out characters from usernames and passwords, you could hash them with a function like this. I use this for storing server and player profiles into a file with thier name on it by hashing their names. You could run your user name and password through this hash to ensure that they dont use bypassing code to gain access to your server....function nameHash(%name)
{
%name = strreplace(%name, "\?", "A1");
%name = strreplace(%name, "\", "A2");
%name = strreplace(%name, "\/", "A3");
%name = strreplace(%name, "\!", "A4");
%name = strreplace(%name, "\@", "A5");
%name = strreplace(%name, "\#", "A6");
%name = strreplace(%name, "$", "A7");
%name = strreplace(%name, "\%", "A8");
%name = strreplace(%name, "\^", "A9");
%name = strreplace(%name, "\&", "A0");
%name = strreplace(%name, "\*", "B1");
%name = strreplace(%name, "\(", "B2");
%name = strreplace(%name, "\)", "B3");
%name = strreplace(%name, "\+", "B4");
%name = strreplace(%name, "\=", "B5");
%name = strreplace(%name, "\:", "B6");
%name = strreplace(%name, "\;", "B7");
%name = strreplace(%name, "\<", "B8");
%name = strreplace(%name, "\>", "B9");
%name = strreplace(%name, "\,", "B0");
%name = strreplace(%name, "\|", "C1");
%name = strreplace(%name, "\`", "C2");
%name = strreplace(%name, "\~", "C3");
return %name;
}
#16
04/06/2004 (8:44 am)
May you do me (a newbie) a huge favor and perhaps post a zip with the GUI and cd files? That would save a lot of time. Thanks!
#17
Sorry but its not possible. The code above is clean and it works. If I would post the .cs and GUI files, that would include alot of bitmaps and functions that your Torque does not know how to handle, since I modified that a bit.
The client calls "LoginCheck" upon you pressing the OK button, then the server runs LoginCheck which will do everything automatically and send back different commands depending on what happened.
OF COURSE this won't work right off the bat, as you need to change the password, username and IP of your mySQL database.
Then grant priviligies to whatever computer you have that is connecting to the database.
If some of this are done the wrong way or if it simply does not work, there will be a red "warning" text in the console about it. Pick that out and paste it here if you get any.
So if you want further help then you need to specify abit more what the problem is. It could be the code above, it could be the mysql implantation, it could be something I've done wrong and it could be that you haven't set up the MySQL database the correct way. It could be anything :)
More details mate, and I'll look into it. Any console errors and such would be greatly appreciated.
Gonzo
I'm afraid that doesnt make sense to me.
04/07/2004 (5:13 am)
Nick MerrillSorry but its not possible. The code above is clean and it works. If I would post the .cs and GUI files, that would include alot of bitmaps and functions that your Torque does not know how to handle, since I modified that a bit.
The client calls "LoginCheck" upon you pressing the OK button, then the server runs LoginCheck which will do everything automatically and send back different commands depending on what happened.
OF COURSE this won't work right off the bat, as you need to change the password, username and IP of your mySQL database.
Then grant priviligies to whatever computer you have that is connecting to the database.
If some of this are done the wrong way or if it simply does not work, there will be a red "warning" text in the console about it. Pick that out and paste it here if you get any.
So if you want further help then you need to specify abit more what the problem is. It could be the code above, it could be the mysql implantation, it could be something I've done wrong and it could be that you haven't set up the MySQL database the correct way. It could be anything :)
More details mate, and I'll look into it. Any console errors and such would be greatly appreciated.
Gonzo
I'm afraid that doesnt make sense to me.
#18
In order to make sure people don't use special characters to hack a login, and to make names file compatible I run a players name through the namehash before saving, loding, or sending data.
For example...
DeV| Gonzo when run through that function always returns as...
DeVC1C4Gonzo when loading or saving info related to that name. That way there are never any file or syntax issues when dealing with people's funky names.
07/22/2004 (9:33 am)
StefenIn order to make sure people don't use special characters to hack a login, and to make names file compatible I run a players name through the namehash before saving, loding, or sending data.
For example...
DeV| Gonzo when run through that function always returns as...
DeVC1C4Gonzo when loading or saving info related to that name. That way there are never any file or syntax issues when dealing with people's funky names.
#19
$pref::Username = "Stefan";
$pref::Password = "Blaha"; <----What is the purpose of this?
Wouldn't that be what the user enters in?
Does the login.cs support connecting to a server not on the network?
I am using mysql 5.0 and I have a php registering site. I need the user to register and be directed to the app download. When the user loads the game the mainmenugui will show a login button. The user will put in the username and password they used to register and tge will then callback to the remote server and authenticate. the result will be connect('ip.address'); of the master server.
Do you think this script will work with 1.5.2 TGE and 5.0 MySQL?
09/07/2007 (11:11 pm)
Call me stupid (I'm sure someone will), but I'm not grasping this resource. I know it's old but I might be able to use it. $pref::Username = "Stefan";
$pref::Password = "Blaha"; <----What is the purpose of this?
Wouldn't that be what the user enters in?
Does the login.cs support connecting to a server not on the network?
I am using mysql 5.0 and I have a php registering site. I need the user to register and be directed to the app download. When the user loads the game the mainmenugui will show a login button. The user will put in the username and password they used to register and tge will then callback to the remote server and authenticate. the result will be connect('ip.address'); of the master server.
Do you think this script will work with 1.5.2 TGE and 5.0 MySQL?

Associate Ron Yacketta
Nice resource, but it has been mentioned before that linking the mysql libs would force one to abide by the GPL license.
A more robust way (as Xavier has mentioned) woyuld be to use httpobject and send a request to a webserver running mysql.
I am currently working a resource (already done need input from Davis and possibly a review from Tim G) that connects to a ISS server using the TGE httpobject which kicks off a ASP.NET webservice and runs a MySQL stored proc for user authentication.
The password is AES encrypted in the DB as well as stored in a $pref var (so I can populate the password field for the user ;) ).
-Ron