I feel like writing a technical post, so feel free to read below. I'm trying to make it as layman-oriented as possible. This post focuses on how to deal with security on websites without using any advanced methods (like secure HTTP connections).

One of the many problems about websites is the lack of security when a user inputs their password. Given the fact that many users tend to reuse passwords over and over again (my Tabulas password is nearly the same as my Bank of America online account, which is also very similar to some of my server passwords), websites must put in some basic methods of protecting these passwords.

When you submit a form from a website, whatever you submit gets sent over the Internet. Think of it like a phone call - you've called Tabulas and you're saying your username and password over the phone. Your sister could be on the phone as well, listening to what you're saying. The internet works in a similar way; anyone who is on your immediate network can watch what traffic leaves your computer. This means the passwords you submit are being sent in plain-text (not being converted!) ...

Obviously this is a horrible security measure.

The obviously solution is to use something called HTTPS, which is "secure" http. The server makes a direct connection to your computer and encrypts the data being sent back and forth so nobody can view it. But this is not feasible on many sites like Tabulas, because:

  1. Creating HTTPS connections from a server to each individual computer utilizes a lot of server resources. Obviously for sites like banking sites, you're willing to sacrifice speed for security. But for stuff like Tabulas, the cost in computing power is not worth the security (except for the facts that I mentioned above, but that's a human error issue)
  2. It costs money and is a bit more difficult to implement. It's not easy to "plug and play" these features from site to site, which is my ultimate goal.

So what does a developer like me do? We take advantage of something called a MD5 hash. A MD5 hash will convert a word(s) into a 32-length passcode. For example, the word 'hello,' when it is converted to a MD5 hash, looks like this: 5d41402abc4b2a76b9719d911017c592.

There's a lot of mathematics behind it, but the end result is that no two words will ever create the same MD5 hash, and MD5 hashes cannot be reversed. This means that if you are given '5d41402abc4b2a76b9719d911017c592', this means ONE word (which we know to be 'hello').

This is a one-way hash; we can convert something in one direction, but we can't "decode it."

So the first step any webdev should take in developing a site is to MD5 those passwords.

But the problem still occurs: people will iinput their passwords, it will be sent to the server, then it will be MD5 hashed. For someone listening in on the phone conversation, they'll still pick up on the password. Then they can just MD5 hash the password and send it to the server and pretend to be someone they are not.

So the obvious solution is to do something with Javascript ... some sort of awesome Javascript function that would create a MD5 hash of the password, delete the password being sent, and send the hash to the server instead. And such an awesome system already exists.

Great, so we hash the function! So when Roy sends his password of hello to the server, the server receives Username: Roy, Password 5d41402abc4b2a76b9719d911017c592. But wait. If the server is accepting MD5 hash, someone could *still* intercept the MD5 hash and just send the MD5 hash to the server! This hasn't done anything besides convert the plain-text to a simple hash.

So we add what is called a "salt." A salt is a randomly generated token (it could be a word or a number) that is added to the password. For example, let's say Roy wants to login ot the server. On the login page, the webpage automatically adds a random number (119834727) to the password, then MD5 hashes the whole string, THEN sends it to the server.

So the webpage submits this new MD5 hash of our password and salt combined into one word as well as the salt by itself. Our receiving server then receives the salt, takes the password (which we know), adds the salt and password words together, then MD5 the result. If they come out to be the same MD5 result, then we know the right password was put in!

The next step one should also take is to store all the sorts in memory; the salt simply adds another layer of complexity to the program ... but a hacker could take the salt, the md5 hash, and do a repeat attack. By storing the salt on the server, the server can reject any request that sends a salt that it's previously used. When creating salts, it's most useful to use a number you KNOW won't ever be reused - I use the number of seconds since the UNIX epoch (number of seconds since January 1, 1970).

I will be sorely dissappointed if anybody actually read this and commented. Get a life, you fools!

By the way, if you've ever been curious how something works on Tabulas or with websites, feel free to ask below. Maybe I'll write more technical articles... it's kind of fun.

Posted by roy on June 5, 2005 at 07:56 PM in Web Development | 8 Comments

Related Entries

Linked Entries

These are Tabulas entries which have linked to this particular entry.

Want to comment with Tabulas?. Please login.

Comment posted on June 6th, 2005 at 06:03 AM
You can't substitute a 'secure' connection, no matter how hard you try. It always turns out an ugly mess of complication (which won't stop diehard crackers).

Oh, and there are definitely an infinite number of strings which could MD5 to the same 128-bit hash. Base 16 with a limit of 32 characters, infinite input length… collisions can be generated within an hour or two ( <a href="http://en.wikipedia.org/wiki/MD5">http://en.wikipedia.org/wiki/MD5</a> ).

Your salt helps, but can you really trust a computer to have JavaScript enabled? Something like SSL might be more up the list than JS when someone goes about making a Web browser.

Dissappointed yet?

PS: Shouldn't you be using SHA-1? ( <a href="http://www.php.net/manual/en/function.sha1.php">http://www.php.net/manual/en/function.sha1.php</a> )
Comment posted on June 6th, 2005 at 08:54 AM
Given infinite number of strings, yes collisions do occur. But even *if* collisions do occur, that doesn't fundamentally change the value of MD5. The gain in difference between moving between SHA-1 and MD5 is not as much as moving from plaintext to MD5. And if I'm not mistaken, collisions in SHA-1 were found recently as well.

But you're correct in that nothing can ever replace HTTPS; what I'm outlining is a cost-effective absolute minimum of security any website that takes passwords should offer to its users.
Comment posted on June 6th, 2005 at 06:29 AM
I think roy's method hits the spot about right, although I wouldn't care that much about the users. Disabled js is easy to work around.

Also, does this guard against someone clicking the username box when your entering your password from the spare seat?
Comment posted on June 6th, 2005 at 04:06 AM
why stop at salts? why not peppers, and even sauces?

god ive reached new lows.
Comment posted on June 6th, 2005 at 08:58 AM
you got ONE guffaw out of me for that. ONE!!!
Comment posted on June 6th, 2005 at 12:38 AM
I read the entry. Now I am commenting on it. I wouldn't know what to do with a life if I got one anyways...
Comment posted on June 5th, 2005 at 08:21 PM
First you are saying that you'll be dissapointed if someone comments, but then you tell your readers to ask questions below. MAKE UP YOUR MIND!!! :)

Anyway, im actually curious as to how the database is setup. What tables, keys, relations, etc...?
Comment posted on June 5th, 2005 at 08:46 PM
Oh, the paradoxes. ;)

I'll write up a post on the stuff I've learned about databases too. Shortly.