views:

50

answers:

2

I am writing a web service in PHP for the first time and had ran into some security problems.

1) I am planning to hash passwords using md5() before I write them to the database (or to authenticate the user) but I realize that to do that, I would have to transmit the password in plaintext to the server and hash it there.
Because of this I thought of md5()ing it with javascript client side and then rehashing on the server but then if javascript is disabled, then the user can't login, right?

2) I have heard that anything that when the action is readonly, you should use GET but if it modifies the database, you should use POST. Isn't post just as transparent as GET, just not in the address bar?

+1  A: 

1) I am planning to hash passwords using md5() before I write them to the database (or to authenticate the user) but I realize that to do that, I would have to transmit the password in plaintext to the server and hash it there.

Because of this I thought of md5()ing it with javascript client side and then rehashing on the server but then if javascript is disabled, then the user can't login, right?

The point of hashing passwords is to reduce the consequences of your database being exposed. If you hash them client side, you just change one string that the client has to send for a different string. It is pointless.

2) I have heard that anything that when the action is readonly, you should use GET but if it modifies the database, you should use POST. Isn't post just as transparent as GET, just not in the address bar?

Crawlers (including search engine indexers) won't make POST requests. Browsers will generally warn users about resubmitting POST data.

Using POST and GET for the right things is not a matter of security.

David Dorward
Prefetching browsers (FasterFox) will also GET, but will not POST. For further reading see http://thedailywtf.com/articles/the_spider_of_doom.aspx and RFC 2616 http://www.w3.org/Protocols/rfc2616/rfc2616.html . GET is supposed to be idempotent and not have side effects. Crawlers and prefetchers count on that being true.
Frank Farmer
As you mention, client hashing does not help much in trying to avoid the sniffing of a password (You only have to sniff the hash and send it, like a string). It's better if you use an encrypted protocol, like HTTPS.
jpabluz
+4  A: 

It's usually not recommended to implement your own hashing layer. I'm sure md5 will be fine if you're just doing a really tiny site for learning purposes, but if you're storing important information for a larger site you should use a library, such as PHPass:

Thank you to Jacco for this PHPass code snippet:

require('PasswordHash.php');

$pwdHasher = new PasswordHash(8, FALSE);

// $hash is what you would store in your database
$hash = $pwdHasher->HashPassword( $password );

// $hash would be the $hashed stored in your database for this user
$checked = $pwdHasher->CheckPassword($password, $hash);
if ($checked) {
    echo 'password correct';
} else {
    echo 'wrong credentials';
}

If you insist on doing it yourself, you should salt the passwords. See http://phpsec.org/articles/2005/password-hashing.html.

define('SALT_LENGTH', 9);

function generateHash($plainText, $salt = null)
{
    if ($salt === null)
    {
        $salt = substr(md5(uniqid(rand(), true)), 0, SALT_LENGTH);
    }
    else
    {
        $salt = substr($salt, 0, SALT_LENGTH);
    }

    return $salt . sha1($salt . $plainText);
}

The reason for the difference between GET and POST is the way the browsers interpret the requests. As mentioned above, web crawlers won't execute POST requests. But imagine that you went to a page on your site http://example.com/deleteuser.php?userid=25 to delete a nasty spammer. Then you close your browser. The next time you come back firefox reopens that page and you've unfortunately deleted the user who just registered!

Another reason for GET vs. POST is the partial prevention against cross-site request forgeries. If you had a page that logged out the user in a GET request, someone could embed an image tag into a comment or forum post like <img src="http://example.com/logout.php" /> and the browser would be forced to execute the logout operation. So any user who viewed that page would be logged out, even if they were an admin.

Edit: As an aside, you should probably use sha-256 or bcrypt instead of md5, which has been cracked (?).

Lotus Notes
+1. Salting alone isn't really the be all and end all of security, either. "Adaptive hashing" is the state of the art: http://www.securityfocus.com/blogs/262
Frank Farmer