Page 1 of 1

Newbie Needs Help - Password Hashing

Posted: Sun Jul 25, 2010 10:03 pm
by Jesse B
Hey all,

I've been programming/scripting casually for a few years now, but have recently just delved into php. I've used quite a variety of languages, such as HTML, CSS, Javascript, Python, VB, C, C++.... the list goes on, so I won't bore you all :p Anyways, I'm by no means an expert in any of these, but I'm somewhat familiar with the syntax.

Anyways, I'm in the process of building a server, so I figured I'd set up a virtual machine while I'm waiting for some parts to come in and whatnot. I'm working out of town, so I'm running Ubuntu 10.04 in VirtualBox, installed Apache2, PHP5, mySQL, all the stuff needed for a web server. I've been working on writing some code to log into the server, and access the pages/files/whatever. It's mostly going to be so I can access files from computers other than those on my network.

I've got the basic scripts all written, and I am able to log in just fine. However, now that I've got the core of the program working, I want to start adding some features. First things first is security, as that's a fairly vital thing. I've decided I'm just going to do a simple MD5 + const_salt, as there's only going to be 3 or 4 people with any access to said server, so it should be plenty adequate. I may add a user_salt if I feel the need to, but that's for later.

Anyways, I've read numerous guides on how to go about doing something like this, but I can't seem to get it to work. I've tried every piece of example code inserted into mine, but it's just not working. So I'm gonna need some help from you guys, if you wouldn't mind.

The way I've got things working right now is VERY messy and just kinda thrown together, but I do plan on cleaning things up once I get this password issue, plus one or two other things worked out. As it stands, the "map" is something like this:

main_login.php -> checklogin.php -> login_sucess/failure.php -> redirecting.html -> INDEX

As I said, very messy, but I'm gonna fix that later :p

Anyways, I really just have no clue where to go from here. checklogin.php has the majority of the code, and all the information that's relevant, so I'll just post that. An explanation of how to hash the password, or even just copy/pasting and then inserting it yourself would be much appreciated! Hopefully I'm not asking too much of you guys. Remember, it's still in the early stages, and I'm very new to this, so take it easy on me :D I'm entirely open to any suggestions as well.

Code: Select all

<html>
<body>
<CENTER>

<br><br><br><br>

<?php
ob_start();

$host = "localhost"; // Host name
$username = "USERNAME"; // Mysql username
$password = "PASSWORD"; // Mysql password
$db_name = "login"; // Database name
$tbl_name = "members"; // Table name

// Connect to server and select database
mysql_connect("$host", "$username", "$password") or die ("Could not connect: " . mysql_error());
mysql_select_db("$db_name") or die ("Could not select DB: " . mysql_error());

// Define $myusername and $mypassword
$myusername = $_POST['myusername'];
$mypassword = $_POST['mypassword'];

// Protect from MySQL injection
$myusername = stripslashes($myusername);
$mypassword = stripslashes($mypassword);
$myusername = mysql_real_escape_string($myusername);
$mypassword = mysql_real_escape_string($mypassword);

$sql = "SELECT * FROM $tbl_name WHERE username='$myusername' and password='$mypassword'";
$result = mysql_query($sql);

// Mysql_num_row is counting table row
$count = mysql_num_rows($result);

// If result matched $myusername and $mypassword, table row must be 1 row
// Register $myusername, $mypassword and redirect to file "login_success.php"
if ($count==1)
{
    $_SESSION['username'] = $username;
    $_SESSION['password'] = $password;
    header("Location: login_success.php");
}
else
{
    echo "Wrong Username and/or Password.<br />";
    echo "Please hit 'Back' and try again.";
}

ob_end_flush();
?>

</CENTER>
</body>
</html> 
Thanks,


- Jesse

Re: Newbie Needs Help - Password Hashing

Posted: Mon Jul 26, 2010 5:41 am
by Mordred
1. Article
2. Every time you give a $password to mysql (i.e. when registering and when checking the password), instead of the user password, pass the MD5(hash . salt) (or whatever scheme you use)

Re: Newbie Needs Help - Password Hashing

Posted: Mon Jul 26, 2010 7:05 pm
by Jesse B
Thanks for the help! I managed to get it working using another guide, but that article you posted is helping me add even further security. I've currently just got the password md5'd, but I'm gonna try to add a salt now. Thanks again :)

Re: Newbie Needs Help - Password Hashing

Posted: Tue Aug 10, 2010 8:33 am
by Fabian
it's better to use the sha1 command over the old md5. for security reason ^^

Re: Newbie Needs Help - Password Hashing

Posted: Thu Aug 12, 2010 2:07 pm
by Sephern
Fabian wrote:it's better to use the sha1 command over the old md5. for security reason ^^
Providing you use a salt, it should be fine. The only real risk to hashing passwords with MD5 is rainbow tables, and thats an omnipresent risk for all hashing algorithms (and one thats averted by using salts).

Its probably worth noting that if someone really wants to get into your server, its more secure to use a user-based salt than a global one. The reason for this is simple, if you use one then only one encryption scheme needs to be broken. For example, if you use md5("mySalt".$password); then someone with access to your database could quite easily do something like

Code: Select all

$password = md5("mySaltPassword");
SELECT * FROM users WHERE password = '$password';
Obviously, this is psuedo code because I haven't used mysql_ in a while (and thats probably what you're used to), and in reality you'd probably use a faster language with a pre-set array of common passwords in order to query the database, but that should give you an idea. If you have an individual salt for each user, it means you'd have to generate a database of hash to password combinations for every single user, which is just computationally infeasible.

The salting method I use at the moment is

Code: Select all

md5(md5($salt).md5($pass));
Where each user has an individually generated 5 character salt of alphanumerics, mixed casing and symbols.

Re: Newbie Needs Help - Password Hashing

Posted: Fri Aug 13, 2010 2:07 am
by Mordred
@Sephern: The argument is not between using a global salt or a per-user salt. The argument is between using only a per-user salt or both. The pepper (global salt) appears only in the source. An attacker with DB access needs to be able to read the source to do the thing you warn against. My arguments are in the article linked above.

I would also advise you to increase the size of your salt, it's free. Brute-forcing 64^5 (estimate) MD5-s takes a couple of minutes, still not enough to deter atacks against the most popular passwords.

Re: Newbie Needs Help - Password Hashing

Posted: Mon Aug 16, 2010 8:17 am
by Sephern
Mordred wrote:@Sephern: The argument is not between using a global salt or a per-user salt. The argument is between using only a per-user salt or both. The pepper (global salt) appears only in the source. An attacker with DB access needs to be able to read the source to do the thing you warn against. My arguments are in the article linked above.

I would also advise you to increase the size of your salt, it's free. Brute-forcing 64^5 (estimate) MD5-s takes a couple of minutes, still not enough to deter atacks against the most popular passwords.
Ah, my bad. I must have misinterpreted.

I'm aware that increasing the size of my salt wouldn't increase the computing time at all, but it wouldn't actually make any difference. I hash the salt before I hash it with the password, so either way it's going to end up as 32 characters.

MD5's are base 16, so that means that there's 16^32 possible combinations (340,282,366,900,000,000,000,000,000,000,000,000,000). Even if an attacker managed to compromise the database, they'd first have to pretty much guess how the passwords were hashed (as its not the most common md5($salt.$Pass) method), which is unlikely if they don't have file based access. Even then, they could work out what the plaintext salt was since it's stored in the db, but they'd still need to crack the hash which is relatively unlikely.

Increasing the size of a salt won't make too much difference anyway. All if does is stop your passwords from being susceptible to rainbow attacks. Ideally, every user in your system should have a unique salt, so estimate the amount of users that you're going to have and then generate a length of salt as appropriate. My salts can contain any 5 character combination of 36 different characters (5^36, or 10^25). Thats a hell of a lot of users. Its relatively safe to assume that its unlikely for any 2 users to get the same salt, and even more unlikely for more than 2 users to get the same salt. So in order to crack any password an attacker would have to generate a completely unique rainbow table. If they're willing to do that, then it's a very, very important password, and there's probably not a great deal that can be done to deter them.

As for the most common passwords, no matter what hashing scheme you use, if the attacker can find that and the hashes, it's not going to take them a great deal of time to write a quick program or script to go through and check for common things like "Password" and people's first names (if they have a full db dump), possibly with combinations of numbers and stuff. There's nothing much you can do about that than stop people from having common passwords (like password, their firstname or username, etc) and preaching the requirement to have a good password.

Out of interest, where did 64^5 come from?

Re: Newbie Needs Help - Password Hashing

Posted: Mon Aug 16, 2010 9:03 am
by Mordred
The danger is of course somewhat theoretical (mostly because the associated cost is larger than online bruteforcing), but it is as real as I describe it, your math is mostly wrong:
Sephern wrote:I'm aware that increasing the size of my salt wouldn't increase the computing time at all, but it wouldn't actually make any difference. I hash the salt before I hash it with the password, so either way it's going to end up as 32 characters.

MD5's are base 16, so that means that there's 16^32 possible combinations (340,282,366,900,000,000,000,000,000,000,000,000,000). Even if an attacker managed to compromise the database, they'd first have to pretty much guess how the passwords were hashed (as its not the most common md5($salt.$Pass) method), which is unlikely if they don't have file based access. Even then, they could work out what the plaintext salt was since it's stored in the db, but they'd still need to crack the hash which is relatively unlikely.
The entropy of the hashed salt is still the entropy of the plaintext salt. Having a different representation of it does not increase its randomness.
If I am an attacker with a read-only access to your database, I can register an account and then look at the login data to figure out the hashing scheme. Moreover, you should not base the security of your system in the hope that the attacker can't figure out something, that's "security through obscurity", generally not a good thing.
Sephern wrote:Increasing the size of a salt won't make too much difference anyway. All if does is stop your passwords from being susceptible to rainbow attacks.
Rainbow tables are an optimization of Helman's time-memory tradeoff, which is an optimization of the bruteforce attack. What I am describing is a different optimization of the bruteforce attack - one with a small dictionary and exhausing the salt-space. With a targeted dictionary of 5-10 entries one can recover 2-4% of the accounts.
Sephern wrote:Out of interest, where did 64^5 come from?
From the assumption that your salts used an alphabet of ~64 characters (you said uppercase, lowercase, numbers and symbols, meaning 26+26+10+X, which I estimated as 64)
64^5 is the correct size of the keyspace in that assumption, or if you use 36 characters, it's 36^5 (not 5^36). This puts the cost of a single attempt in the 10-20 seconds range, which makes it on par with online bruteforcing.
Sephern wrote:There's nothing much you can do about that than stop people from having common passwords...
Using a pepper can quite effective, although of course forbidding common passwords will help immensely as well.

In short, although the threat is really not that big, your math is wrong, the numbers are close enough. Increase your salts.

Re: Newbie Needs Help - Password Hashing

Posted: Mon Aug 16, 2010 3:24 pm
by Sephern
Based on the assumption the attacker has gained access to the database and the encryption scheme, and is only attempting to crack 2-4% of the accounts then surely the difference of a few characters in the salt (which would be stored in plaintext in the database anyway wouldn't make much difference? And given this, then after having cracked 3 (or more) passwords, they're likely to discover any global salt relatively easily...

Obviously, the chances of this occurring are pretty low, especially if you're not creating a web application that's going to get any real security exposure. Indeed, I know of sites in the top 20,000 visited on the web, who use a very similar scheme to that and have not had any problems (and they're in a field where one would expect them to get attempted attacks regularly).

Re: Newbie Needs Help - Password Hashing

Posted: Tue Aug 17, 2010 4:40 am
by Mordred
Sephern wrote:Obviously, the chances of this occurring are pretty low,
This I agree with, it requires some very specific circumstances to work.
Sephern wrote:Based on the assumption the attacker has gained access to the database and the encryption scheme, and is only attempting to crack 2-4% of the accounts then surely the difference of a few characters in the salt (which would be stored in plaintext in the database anyway wouldn't make much difference?
Yes, it would make a difference. The fact that the salt is kept in plain is irrelevant. The fact that it's short is important - it's the difference between having the passwords of these 2% and 0% (which equals thousands of users for high-profile sites.)
Sephern wrote:And given this, then after having cracked 3 (or more) passwords, they're likely to discover any global salt relatively easily...

This can only be done for small salts. If the global salt is sufficiently long, no plausible brute force attack can be made against it.
Sephern wrote:I know of sites in the top 20,000 visited on the web, who use a very similar scheme to that and have not had any problems
Hearsay is not science, it proves nothing, sorry. The numbers, on the other hand, do not lie, 36^5 is too low. I can quote exact numbers for compromised sites with faulty salting schemes if I can find my notes. (Lost them on my primary HDD, but I have them on backup somewhere).

Again: make your salts longer, it costs nothing and it has real effect on things.

Re: Newbie Needs Help - Password Hashing

Posted: Wed Aug 18, 2010 9:55 am
by timWebUK
Mordred wrote: Yes, it would make a difference. The fact that the salt is kept in plain is irrelevant. The fact that it's short is important - it's the difference between having the passwords of these 2% and 0% (which equals thousands of users for high-profile sites.)
In the case of Facebook, 1% would be 5,000,000 users.