947740 Posted April 18, 2008 Share Posted April 18, 2008 I have a quick question about login security using PHP. I am working on a website where only administrators can login and only with a password. That makes it much simpler on the administrators, and it makes it easier on me. (There are only 4 administrators, so there is not a problem with the same passwords) I am concerned with the security of the login. When someone logs in, I use md5() to encrypt the password and compare it to the passwords in the database. If it matches, it logs the user in. It creates a session variable, $_SESSION['login'] = "true". Every single administration page checks for the $_SESSION['login'] variable. If it is not == "true", it sends you back to the home page with an error message. Does anyone see any security concerns with the way I have set it up? If you need to see the code, just ask. I will probably put it up later, but I do not have it on me. ~Thanks Quote Link to comment Share on other sites More sharing options...
mrdamien Posted April 18, 2008 Share Posted April 18, 2008 That's pretty much how everyone does it. So yeah, it should be safe. Quote Link to comment Share on other sites More sharing options...
discomatt Posted April 18, 2008 Share Posted April 18, 2008 Should be fine, the only issue here is if someone grabs your database, the plain-text password won't be hard to bruteforce (due to rainbow tables). Assuming your SQL code is injection-safe, an attacker will have a hard time getting access Quote Link to comment Share on other sites More sharing options...
947740 Posted April 18, 2008 Author Share Posted April 18, 2008 The password in the database is encrypted using PHP's md5(), and then I just attempt to match it. Are there any specific things to stop injection? Thanks for your opinions on that! Quote Link to comment Share on other sites More sharing options...
hitman6003 Posted April 18, 2008 Share Posted April 18, 2008 the plain-text password won't be hard to bruteforce (due to rainbow tables) It's not plain text, and good luck trying to find a collision in md5. As you stated, the real threat is sql injection. The password in the database is encrypted using PHP's md5(), md5 is not an encryption. It's a hash algorithm. Are there any specific things to stop injection? Use input verification (i.e. make sure a text input only contians text) and use mysql_real_escape_string or PDO and prepared statements. Quote Link to comment Share on other sites More sharing options...
dptr1988 Posted April 18, 2008 Share Posted April 18, 2008 You can use mysql_real_escape_string() on each variable that the user inputs before using that variable in an SQL statement. In this case you would want to run mysql_real_escape_string() on the username and password vars. http://us3.php.net/mysql_real_escape_string Quote Link to comment Share on other sites More sharing options...
discomatt Posted April 18, 2008 Share Posted April 18, 2008 It's not plain text, and good luck trying to find a collision in md5. As you stated, the real threat is sql injection. It's not a collision... it uses what a called 'rainbow tables' -> huge tables of prehashed values with their corresponding plain text strings. Allows you to brute force without the overhead of actually performing the hash. It's very fast, and well-known. Why do you think salting hashes has become such common practice? If it wasn't an issue, dumping the user table with an injection wouldn't be so risky assuming passwords were hashed. Quote Link to comment Share on other sites More sharing options...
947740 Posted April 18, 2008 Author Share Posted April 18, 2008 Okay, it is not encryption, but it is not plain text either. It would be rather hard to work backwards and figure out what the actual value is-at least I think so. Thanks to all of you for your insight. Quote Link to comment Share on other sites More sharing options...
hitman6003 Posted April 19, 2008 Share Posted April 19, 2008 Since md5 is so easily challenged, what strings generated these hashes? 1f9788313e0a9e5180a2705dda8e27e2 cd8dd7ce5892f48289825ee3db970c49 Quote Link to comment Share on other sites More sharing options...
discomatt Posted April 19, 2008 Share Posted April 19, 2008 I know of a couple private-access md5 hash tables that are in the terabyte ranges. They cover all ascii chars up to ~20 characters long. If you had something I wanted and I was less moral, then I could probably get access to them. The thing that worries me is insecure passwords. Dictionary-based tables are publicly available Quote Link to comment Share on other sites More sharing options...
947740 Posted April 19, 2008 Author Share Posted April 19, 2008 Assuming, as you said, that someone could easily hack the passwords, how would you suggest encrypting them? Are there any safe ways? Quote Link to comment Share on other sites More sharing options...
hitman6003 Posted April 19, 2008 Share Posted April 19, 2008 The thing that worries me is insecure passwords. Dictionary-based tables are publicly available Exactly...it doesn't matter (for the most part) the hash or encryption if the password is weak to begin with. On a side note, md5 is a 128 bit hash, which means there is 2^128 number of values. According to the calculator on my Fedora 8 laptop, that comes to ~ 3.4*10^38 combinations. MySQL's largest integer data type is BIGINT, which according to their documentation, and unsigned BIGINT has a max value of 18446744073709551615. If you divide the first number (2^128) by the second, you get 18446744073709551617. This means it would take 18,446,744,073,709,551,617 mysql tables, all with a BIGINT primary key, to find every hash possible. Terabytes is still a very small percentage. Quote Link to comment Share on other sites More sharing options...
947740 Posted April 19, 2008 Author Share Posted April 19, 2008 The math you provided really put it into perspective. Quote Link to comment Share on other sites More sharing options...
discomatt Posted April 19, 2008 Share Posted April 19, 2008 The easiest method is a salt of a predetermined length appended to the hash... This is described here http://phpsec.org/articles/2005/password-hashing.html But here's the basic idea: <?php // Multiples of 16 best here to obscure better define('SALT_LENGTH', 32); define('SALT_OFFSET', 12); function salted_md5 ($input, $salt = FALSE) { // Make sure constants are defined if ( !defined('SALT_LENGTH') || !defined('SALT_OFFSET') ) return FALSE; // If no salt is defined, generate one if ($salt === FALSE) $salt = md5( uniqid('', TRUE) ); // Make sure legth and offset make sense if ( SALT_LENGTH > strlen($salt) || SALT_OFFSET > strlen($salt) ) return FALSE; // Now that we've made sure the length checks out, truncate salt if needed $salt = substr( $salt, mt_rand(0, strlen($salt) - SALT_LENGTH), SALT_LENGTH ); // Hash input $hash = md5($input); // Use offset to mix up salt and hash together return substr( $salt, 0, SALT_OFFSET ) . $hash . substr( $salt, SALT_OFFSET ); } function get_salt ($hash) { // Make sure constants are defined if ( !defined('SALT_LENGTH') || !defined('SALT_OFFSET') ) return FALSE; // Extract salt return substr( $hash, 0, SALT_OFFSET ) . substr( $hash, strlen($hash) - SALT_LENGTH + SALT_OFFSET ); } // Does it work? $hash = salted_md5('test'); $salt = get_salt($hash); $compare = salted_md5('test', $salt); if ($hash == $compare) echo 'Match found!'; else echo 'No match'; // Example usage $q = 'SELECT `password` FROM `users` WHERE `username` = \'' . mysql_real_escape_string($_POST['username']) . '\' LIMIT 1'; $r = mysql_query($q); if (mysql_num_rows($r) !== 1) exit('User not found'); $pass = mysql_result($r, 0); $salt = get_salt($pass); if ( salted_md5($_POST['password'], $salt) != $pass ) exit ('Invalid password'); // When adding a new user, just call salted_md5 without second argument to have the salt made for you ?> That's a basic example. Use the hash() function rather than md5 to mix up the length of your hashes and it is theoretically impossible to reverse, even by brute forcing Exactly...it doesn't matter (for the most part) the hash or encryption if the password is weak to begin with. The above function protects against weak passwords. As the holder of someone's passwords, you are responsible for their secrecy. In this way, even if your user table gets dumped (heaven forbid), they will not be able to figure out passwords, no matter how weak the password. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.