﻿<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Travis Miller &#187; security</title>
	<atom:link href="http://www.electrumdigital.com/tag/security/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.electrumdigital.com</link>
	<description>Web Developer for Hire</description>
	<lastBuildDate>Thu, 22 Jul 2010 14:17:43 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Password Security for Web Applications 101</title>
		<link>http://www.electrumdigital.com/2009/10/password-security-for-web-applications-101/</link>
		<comments>http://www.electrumdigital.com/2009/10/password-security-for-web-applications-101/#comments</comments>
		<pubDate>Wed, 28 Oct 2009 22:34:56 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[security]]></category>

		<guid isPermaLink="false">http://www.electrumdigital.com/?p=223</guid>
		<description><![CDATA[User registration and login is a standard feature on interactive Web sites, and passwords are the standard way to protect those accounts. But a password is only effective as long as it's kept secret—and you might not be doing everything you can to protect yours.
Let's say you've finished building the HTML and the server-side validation [...]]]></description>
			<content:encoded><![CDATA[<p>User registration and login is a standard feature on interactive Web sites, and passwords are the standard way to protect those accounts. But a password is only effective as long as it's kept secret—and you might not be doing everything you can to protect yours.</p>
<p>Let's say you've finished building the <acronym title="HyperText Markup Language">HTML</acronym> and the server-side validation code for your registration form, and you're now ready to write the code which stores the user's information (probably in a database). How should you handle the password?</p>
<p><span id="more-223"></span></p>
<p>The most obvious approach is to store it as just another column in the user table, with no special consideration. Many novice developers do exactly this—after all, you need access to the database to view the contents of the user table, so the passwords are protected, right?</p>
<p>But what happens when an attacker <em>gains</em> access to your database—for example, by guessing or intercepting your phpMyAdmin password? They have instant access to all of your user's passwords without even trying.</p>
<p>(Perhaps your application is trivial, and your users' accounts don't provide access to anything sensitive—who <em>cares</em> if an attacker gets their passwords? Well, many people use the same password for <em>all</em> of their accounts—email, bank accounts, and so forth. Our hypothetical attacker might not be able to do much damage on <em>your</em> site—but if the email addresses and passwords he just obtained allow him to gain access to other, more sensitive accounts, then you have a problem.)</p>
<p>Encrypting the password before storing it in the database is the obvious solution to this problem. Simply run it through your favorite encryption algorithm, and save the encrypted version; when the user logs in, just decrypt it to check the entered password.</p>
<p>This is also the <em>wrong</em> solution to the problem. An attacker who has access to your database probably has access to your file system, as well—which means they can easily find your encryption code and any keys it may use. Your encryption is useless in this case.</p>
<p>(Whatever you do, don't write your own home-brew encryption function, or run the password through a series of different encryption algorithms and arbitrary transformations, thinking this will make it more secure. It won't. In fact, this approach may leave telltale mathematical traces in the ciphertext which will make it <em>easier</em> for a skilled attacker to compromise your system. Leave the design of encryption algorithms to the experts.)</p>
<p>A better method is to <a href="http://en.wikipedia.org/wiki/Cryptographic_hash_function">hash</a> the password, rather than encrypting it. Hashing is a form of one-way encryption: converting a password to a hash is easy, but reconstituting the password from the hash is mathematically impossible. Think of a trap door, or running a steak through a meat grinder—once something has gone through a hash function, it can't go back.</p>
<p>(Since the original string can't be reconstituted, hashing technically <em>isn't</em> encryption, no matter what anyone may tell you. I merely described it as such for illustrative purposes.)</p>
<p>But if we aren't storing the password in a way that can be decrypted, how can we check it when the user tries to log in?</p>
<p>Simple: hash the password entered on the login form, and compare that to the hashed password stored in the database. If the two hashes are the same, we know that the user entered the correct password.</p>
<p>(Incidentally, this is why many systems can't tell you your password when you forget it—they don't <em>know</em> your password. They only know its hash value. These systems typically handle forgotten passwords by asking you to choose a new one. Any system which <em>is</em> capable of providing your password on demand must be using some kind of reversible encryption—or, God forbid, storing it in plaintext—and should be considered less secure.)</p>
<p>PHP's <code class="php"><a href="http://php.net/md5">md5()</a></code> function is the standard hash function used for this purpose, but I prefer the more cryptographically robust <a href="http://php.net/sha1">sha1()</a>.</p>
<p>This is a lot better than our original system, and it's good enough for many applications. But our system still has a weakness.</p>
<p>Again, assume that an attacker has access to our database (and therefore our password hashes). Though he can't convert the hashes back into passwords, he knows that most people choose plain English words, or minor combinations and permutations thereof, for their passwords.</p>
<p>It's easy to generate a table of English words and their corresponding hashes (known as a <a href="http://en.wikipedia.org/wiki/Rainbow_table">rainbow table</a>). With this in hand, an attacker simply has to compare your password hashes to the rainbow table until he finds a match. There are even <a href="http://gdataonline.com/seekhash.php">pregenerated rainbow tables</a> online.</p>
<p>(This is why good systems encourage you—or even <em>force</em> you—to choose complex passwords which don't appear in dictionaries. Generating a hash table based on an English dictionary is easy; generating one for every possible password-length string of ASCII characters is effectively impossible.)</p>
<p>For kicks, I once ran about 15,000 real-world password hashes (from a system I administrated) against the above-linked rainbow table. I was able to crack about two-thirds of them. Clearly, this is a serious vulnerability for any system which needs high security.</p>
<p>Fortunately, there's a simple and elegant solution: <a href="http://en.wikipedia.org/wiki/Salt_%28cryptography%29">salt</a> your passwords before hashing them, by concatenating them with a randomly generated string.</p>
<p>For example, let's say the user has chosen "ravens" as their password. If we simply hash this, it will be vulnerable to even the most basic rainbow attack.</p>
<p>So, instead, we'll generate a random string, four to ten characters long. (This is arbitrary; a few characters is sufficient.) This is known as the salt. (For convenience, I like to restrict my salts to printable ASCII characters.) Let's say our random-salt-generating function returns this:</p>
<p><code>^p]K~7</code></p>
<p>We prepend the salt to the password, and get:</p>
<p><code>^p]K~7ravens</code></p>
<p>Finally, we hash that string, and store the hash <em>and</em> the salt in the database. To check login passwords, we simply repeat the process (retrieving the original salt from the database, rather than generating it anew), and compare the hashes as before.</p>
<p>We've effectively turned a vulnerable, low-strength password into a strong one. Yes, our attacker can see the salt, and he could generate a rainbow table based on English words prefixed with that salt. But since the salt is different for every user, he'd have to generate a separate rainbow table <em>for every user</em>. The costs in time and storage space are prohibitive.</p>
<p>All of this may seem complex at first, but you're really only dealing with two database fields (the hash and the salt) and a couple of functions: one to generate a random salt, and one which accepts a plaintext password and a salt and computes the hash. Here's some sample code.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">function</span> generate_salt<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$salt</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">''</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span> <span style="color: #000088;">$i</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span> <span style="color: #000088;">$i</span> <span style="color: #339933;">&lt;</span> <span style="color: #990000;">rand</span><span style="color: #009900;">&#40;</span> <span style="color: #cc66cc;">4</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">10</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000088;">$i</span><span style="color: #339933;">++</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$salt</span> <span style="color: #339933;">.=</span> <span style="color: #990000;">chr</span><span style="color: #009900;">&#40;</span> <span style="color: #990000;">rand</span><span style="color: #009900;">&#40;</span> <span style="color: #cc66cc;">33</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">126</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #000088;">$salt</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">function</span> hash_password<span style="color: #009900;">&#40;</span> <span style="color: #000088;">$password</span><span style="color: #339933;">,</span> <span style="color: #000088;">$salt</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #990000;">sha1</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$salt</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$password</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// for user registration, do something like this</span>
<span style="color: #000088;">$password</span> <span style="color: #339933;">=</span> getPasswordFromRegistrationForm<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$users_pw_salt</span> <span style="color: #339933;">=</span> generate_salt<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$users_pw_hash</span> <span style="color: #339933;">=</span> hash_password<span style="color: #009900;">&#40;</span> <span style="color: #000088;">$password</span><span style="color: #339933;">,</span> <span style="color: #000088;">$users_pw_salt</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// store $users_pw_salt and $users_pw_hash; forget $password</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// and for user login, do this</span>
<span style="color: #000088;">$users_pw_salt</span> <span style="color: #339933;">=</span> getUsersPasswordSaltFromDatabase<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$users_pw_hash</span> <span style="color: #339933;">=</span> getUsersPasswordHashFromDatabase<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$entered_password</span> <span style="color: #339933;">=</span> getPasswordFromLoginForm<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span> hash_password<span style="color: #009900;">&#40;</span> <span style="color: #000088;">$entered_password</span><span style="color: #339933;">,</span> <span style="color: #000088;">$users_pw_salt</span> <span style="color: #009900;">&#41;</span> <span style="color: #339933;">===</span> <span style="color: #000088;">$users_pw_hash</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #666666; font-style: italic;">// the correct password was entered</span>
<span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #666666; font-style: italic;">// the password was incorrect</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

]]></content:encoded>
			<wfw:commentRss>http://www.electrumdigital.com/2009/10/password-security-for-web-applications-101/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
