views:

80

answers:

4

I have a login service to my current website and what I was wondering is - is there any particular method you could call the MOST Secure?

Allow me to explain my system a little better:

I currently have a PHP MySQL database with a users table. The username and password are both stored as VARCHAR (not the best for passwords I know).

On the sign up form side, I regulate the choice of passwords and usernames by only allowing a-Z 0-9 entry and limit the number of characters. On the login form side, I stop attacks by using mysql_real_escape_string and I use POST to an iFrame instead of AJAX.

I feel I am doing what I can to prevent attacks from the Form side, but not from the database side. I know you can change the type of password storage to encrypt upon entry to the database, but what I don't understand is how I would then query this encrypted string.

Given what I've described, what would you advise in terms of added security and why? What are your chosen methods to prevent hacking and attacks? Can you see any glaring security holes in what I've described? Perhaps most importantly of all, what could I do to correct these, given that I've not been in the web-development game long and don't have much experience?

(Bear in mind that I'm not creating a system to house confidential or inflammatory data)

+4  A: 

First of all, don't store plain text passwords in your database. So, when registering a new user insert their password as a hash. MD5 is most commonly used for this. I suggest using a salt with this. So for storing:

$password = md5($yoursalt . $_POST['password']);

Now when the user wants to login, you have their password again in your post. Now make the same hash as before and search for this hash in the database (with their username). This way you don't store their actual passwords.

Leon
+1 for "at least use a hash and a salt", -1 for "use MD5". It's 2010 and MD5 is, for password hashing, dead. Use at least one of the SHA-2 functions, please.
Piskvor
thank you, this has been a great help. My thinking process stopped after the user entering a password and getting an encrypted one from the database so I didn't really think of encrypting the entered password and comparing. Thanks
Daniel Hanly
Also, `$yoursalt` should be per-user, not per-site; this is not mentioned explicitly in your answer.
Piskvor
+3  A: 

Hashing the password to MD5 or SHA1 is an important part of web security. The way to then match the passwords is to first retrieve the hashed password from the DB using the supplied username, hash the user supplied password and then match the two hashes. Since MD5 and SHA1 are one way hashes is does mean that you cannot retrieve the current password if a user has lost it. A new password needs to be recreated. You can get around this by using the PHPs mcrypt() funtions.

You should also allow special characters in passwords. This just adds to complexity in brute force attacks.

You can also lock an account for a certain period after 3 incorrect tries and even go so far as to lock an IP address after 10 tries. Although the later falls under the category of 'tar pits'. Just makes things a little bit more difficult for hackers.

Meloth
thank you. I'm attempting to use some encryption now, as I said on the answer above, my thinking didn't extend to encrypting the entered password and comparing :( Thanks for being very clear with your answer, so many people would just throw a lot of jargon my way, and being inexperienced (I'm only 22) it wouldn't be the best way to learn
Daniel Hanly
mcrypting a password is extremely dangerous as it is reversible.. no password securing method should be reversible.
MRW
+1  A: 

I always use a user specific salt when generating passwords, so my 'users' table has two fields 'encrypted_salt' and 'password'

the top and bottom of it is that I sha1(encrypted_salt + 'password');

When generating the encrypted_salt I would use sha1(unqid(true)); which generates almost a 100% unique salt as it uses time to milliseconds with extra entropy (salt) of its own. The likelihood of getting a duplicated is virtually 0.

So:

$salt = sha1(unqid(true));
$password = sha1($_POST['password']);

store in the DB as:

$pw = sha1($salt.$password); or sha1($password.$salt);

It doesnt really matter.

The beauty of SHA1 is that it will always generate a 40 character string. The more you can salt the string the better, especially if you can generate a unique salt for each password.

MRW
I considered basing the salt on an encrypted version of the username + id of the user, would you also consider this viable?
Daniel Hanly
yes, as the id (pc) of the user SHOULD always be unique, as a best practice I always use some kind of timestamp in the hash so you can use microtime(true) or time() or unqid() as the likelihood that 2 users are added at exactly the same millisecond, especially since PHP doesnt handle multithreading. But username.id would be fine especially hashed.
MRW
With hashing, sha1 vs md5 is personal preference I think. I always use sha1() but md5 is just as good!
MRW
I cannot stress how important it is to NOT use a global salt. Always a user based salt.
MRW
that's a case of, if the hacker gets the salt, it gets the access, I'll be building a nice secure secure salt unique to every user :)
Daniel Hanly
+1  A: 

As far as your SQL goes, don't use a string-munging function like mysql_real_escape_string that can still allow injections attacks to occur under some circumstances. Use parameterised queries, thus ensuring that the database treats all user-supplied string as data, under ALL circumstances, and not possibly as SQL code fragments.

The MySQLi and PDO libraries in PHP both supports parameterised queries.

Cheekysoft
Thank you, how would I implement these libraries into my code? How would I execute a parameterised query?
Daniel Hanly
There's a giant amount of documentation and tutorials around on this. Here's one http://forum.codecall.net/php-tutorials/12442-php-5-mysqli-prepared-statements.html
Cheekysoft