[How To] Password Hashing

08/26/2010 16:41 abrasive#1
I wrote this during breakfast on my way to work so there isn't a ton of documentation along with it.

A quick answer to why storing passwords (in plain text) in a database is bad: [Only registered and activated users can see links. Click Here To Register...]



Here is what my [PS_User_Data].[dbo].[Users_Master] looked like after I implemented password hashing:
[Only registered and activated users can see links. Click Here To Register...]
As you can see I changed the data types on a few columns, changed the primary key, and removed a/some column(s). Also the UserUID column is set to auto increment now.

Here is what my [dbo].[usp_Try_GameLogin_Taiwan] stored procedure looked like after I implemented password hashing:

To add a new user, you would need to run a stored procedure something like this (passing in the appropriate values to the stored procedure obviously):

Basically what is happening when you create a user is:
1. A new user gives you the user name and password they would like to use by filling out a registration form.
2. From the registration script, you pass the user name and password as arguments to a stored procedure meant to create a new user.
3. The stored procedure receives the arguments.
4. The stored procedure generates a unique salt for that user (in this case I use a random number passed into SHA1() to create the unique salt), and stores it in the @salt variable.
5. The stored procedure concatenates the user's plain text password to the salt, and passes the concatenated string into a one-way hashing algorithm (such as SHA1 or MD5), which is then stored in the @hash variable.
6. The stored procedure inserts the data into the [PS_userdata].[dbo].[Users_Master] table.
7. Now you have the password stored in a format that is unreadable and irreversible to humans, but you can still compare against it when users want to log in!

That other table in OMGGame_Web or whatever, we don't care about it anymore. It was redundant data and is now useless.
08/26/2010 16:44 Danco1990#2
Can we implement this on a running server without overlaps or conflict? Thank you alot.
08/26/2010 17:18 abrasive#3
Quote:
Originally Posted by Danco1990 View Post
Can we implement this on a running server without overlaps or conflict? Thank you alot.
It's definitely possible as there's no need to restart the game server or web server for it to take effect.

You should do it on your test server first to understand how it works and iron out any problems you run into there. It would be helpful to copy your live user data to the test server to test implementing it with real data as well.

Make sure you back up your live server's data before making any changes obviously.

When changing the table definition on a server that has user accounts already you won't be able to set the "Allow Nulls" constraint to new columns as they won't contain any data yet, but you can add the constraint later once the data is filled in.

You'll have to generate unique salts for every user, you can either do this manually for each account or write a query to do them all at once and test it on your test server to verify it is giving you the expected results. The same goes for concatenating the salt to their current password and generating the password hash.
08/28/2010 18:06 ProfNerwosol#4
Am I getting it right? You removed RowID and set UserUID as primary key with a clustered index so the results are sorted by it? But, isn't RowID useful here?

I am trying to make UserUID a PK and set it to Auto Increment. Just the dam MSSQL needs a column to be set to identity to allow auto increment and you can set only one identity per table >.<

EDIT:

I don't have Crypt_Gen_Random function. Is there any other way to generate random set of values?
08/29/2010 07:23 abrasive#5
Quote:
Originally Posted by ProfNerwosol View Post
Am I getting it right? You removed RowID and set UserUID as primary key with a clustered index so the results are sorted by it? But, isn't RowID useful here?

I am trying to make UserUID a PK and set it to Auto Increment. Just the dam MSSQL needs a column to be set to identity to allow auto increment and you can set only one identity per table >.<

EDIT:

I don't have Crypt_Gen_Random function. Is there any other way to generate random set of values?
I set UserUID to be the primary key as a clustered index, as well as the identity column. RowID didn't seem to serve any purpose after that, but I could be wrong. What are you suggesting RowID's benefit is in this case?

Instead of CRYPT_GEN_RANDOM() you can use something like:
Code:
CAST(RAND() * 1000000000 AS INT)
I was just generating a sufficiently large random integer to pass into SHA1() to get a random hash for the salt.
08/29/2010 09:58 ProfNerwosol#6
Honestly, I'm not sure. In PS_GameDefs.dbo.Items it allows to add new entries and have them all sorted. Here ... I think it had no purpose. I'm still learning and thought that someone smarter put it there and it's best to leave it :/

Btw, is there a way to change a column to Identity without having to recreate table? In SQL Books I downloaded from Microsoft website it says that you cannot make a column as Identity by ALTER.
08/29/2010 19:32 abrasive#7
It's hard to say what all was altered by others and for what reason. I have no idea how many people tinkered with this database in the past before it landed here.

Some things seem like bad design decisions, such as duplicating the login info in that other table. Also it appears someone removed password hashing at some point based on some of the stored procedure being commented out.

I've just been changing things based on what I've learned in the past about database best practices, performance tuning, normalization, etc.

When I changed the identity column I was able to do so by right-clicking the table and clicking on design. I'm not sure if SQL Server Management Studio was just running an ALTER statement in the background in that case or not.
08/29/2010 21:55 ProfNerwosol#8
I'm glad you joined our little Shaiya community. Someone with good knowledge of databases and willing to share was definitely needed :)
09/05/2010 21:22 abrasive#9
Thanks, I hope people find this useful :)
09/05/2010 21:24 .SweeT#10
Thanks :)
07/03/2011 06:52 [Admin]Snuggle#11
-Bump-
More people should look into doing this.
I prefer not to let my passwords for Shaiya be known because of an unsecured server.
(Even though I change my pass on every server but a lot of people don't)
07/03/2011 08:16 Bаne#12
Quote:
Originally Posted by abrasive View Post
I wrote this during breakfast on my way to work so there isn't a ton of documentation along with it.
Off topic, please tell me you take the subway...and don't drive to work..
07/03/2011 14:22 RebeccaBlack#13
Just fully applied this to my live server (Nightmare), took me about 2-3 hours to understand it all, convert my entire Users_Master table with a unique SALT for each, and recreate 2 new PHP scripts (I love PHP <3) for Registration, and Pass Changing. This is an awesome tutorial and should be easy for anyone.

I love you in the dearest of ways. *bro hug*
07/03/2011 20:54 [Admin]Snuggle#14
Quote:
Originally Posted by tnelis View Post
I love you in the dearest of ways. *bro hug*
I believe you should watch this Tyler o.o
Love you! XD
Now then back on topic
I agree that more people should start doing this.
If your passwords aren't hashed then it can all easily be stolen if someone somehow gets into your database. Meaning that ALL those players account info is out in the open. D: