<?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>Joseph Keeler</title>
	<atom:link href="http://josephkeeler.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://josephkeeler.com</link>
	<description>PHP/LAMP Development and Software Process Improvement</description>
	<lastBuildDate>Thu, 05 Nov 2009 15:11:04 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>The Right Tool for the Job</title>
		<link>http://josephkeeler.com/2009/11/the-right-tool-for-the-job/</link>
		<comments>http://josephkeeler.com/2009/11/the-right-tool-for-the-job/#comments</comments>
		<pubDate>Wed, 04 Nov 2009 20:48:11 +0000</pubDate>
		<dc:creator>Joseph</dc:creator>
				<category><![CDATA[Software Development]]></category>

		<guid isPermaLink="false">http://josephkeeler.com/?p=102</guid>
		<description><![CDATA[&#8220;I need to nail this board down.  Got a hammer?&#8221; asked Jim, the lowly construction worker.
John, the foreman replied, &#8220;We have a pneumatic nail driver we&#8217;ve been using.  You&#8217;ll have to wait for that one.&#8221;
&#8220;But it&#8217;s just for a temporary brace while I put this wall up,&#8221; said Jim.
&#8220;We only do nailing with [...]]]></description>
			<content:encoded><![CDATA[<blockquote><p>&#8220;I need to nail this board down.  Got a hammer?&#8221; asked Jim, the lowly construction worker.</p>
<p>John, the foreman replied, &#8220;We have a pneumatic nail driver we&#8217;ve been using.  You&#8217;ll have to wait for that one.&#8221;</p>
<p>&#8220;But it&#8217;s just for a temporary brace while I put this wall up,&#8221; said Jim.</p>
<p>&#8220;We only do nailing with a pneumatic nail driver on this project.&#8221;</p>
<p>&#8220;It&#8217;s in too tight of a space to even fit the nair with this wall here.  I can just reach a hammer in and nail it down,&#8221; said Jim.</p>
<p>John said definitively &#8220;No, we have to use the pneumatic nail driver.  Everyone knows that hammers aren&#8217;t as good.  You&#8217;ll need to cut a hole in that wall so it will fit in there.&#8221;</p></blockquote>
<p>Any seasoned developer or any CS graduate can give you a laundry list of best practices when developing software.  Things like &#8220;Don&#8217;t use globals,&#8221; &#8220;Have explicit garbage collection instead of depending on built in cleanup,&#8221; or &#8220;The use of GOTO will cause searing pain.&#8221;  Good developers, however, will know that there are times when deviations to these rules is acceptable, and will at times produce software that doesn&#8217;t follow every best practice.<br />
<span id="more-102"></span></p>
<p>There are a couple of barriers to always following every best practice 100% of the time &#8211; developers who work for money are usually required to produce something functional on a fairly regular basis, and sometimes breaking a &#8220;best practice&#8221; provides a performance gain that cannot be easily translated following a &#8220;best practice.&#8221;</p>
<p>Now, this certainly isn&#8217;t to say that going cowboy/rogue and throwing out coding standards is ideal.  Breaking these rules should by far be an exception, but there are times when it can be beneficial.  If bending or breaking a rule gets you significant gain without impacting performance, security, maintainability, or portability of any likely foreseeable use of the code, I say go ahead and break it.</p>
<p>PHP has always been a &#8220;get it done&#8221; language.  Rasmus created the language as a tool to allow him to get things done faster.  The language certainly has changed since its original inception, but the &#8220;get it done&#8221; spirit of the language has always been fostered.  Sure, there are pieces of the language that don&#8217;t make a lot of sense, like  underscores or no underscores between words in standard functions, needle haystack precedence, etc.  Yet it is still arguably the most commonly used language to develop websites.  And that&#8217;s because with all of its quirks and peculiarities, it gets the job done.</p>
<p><a href="http://www.joelonsoftware.com/items/2009/09/23.html">Joel Spolsky</a> refers to people who do this as &#8220;duct tape&#8221; programmers.  They may not have every aspect of the software done with every layer of abstraction that your CS book says you need.  But they deliver software that is maintainable, done close to on schedule, and most importantly, works.</p>
<p>So follow the best practices wherever you can.  But when it makes sense to deviate from your CS Best Practices book, remember you&#8217;re coding to deliver a working product, not to get a grade on your source code.</p>
]]></content:encoded>
			<wfw:commentRss>http://josephkeeler.com/2009/11/the-right-tool-for-the-job/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP Security &#8211; Weak salt vulnerabilities</title>
		<link>http://josephkeeler.com/2009/07/php-security-weak-salt-vulnerabilities/</link>
		<comments>http://josephkeeler.com/2009/07/php-security-weak-salt-vulnerabilities/#comments</comments>
		<pubDate>Fri, 17 Jul 2009 08:00:27 +0000</pubDate>
		<dc:creator>Joseph</dc:creator>
				<category><![CDATA[PHP Security]]></category>

		<guid isPermaLink="false">http://josephkeeler.com/?p=79</guid>
		<description><![CDATA[Salt is good; but if the salt becomes unsalty, with what will you make it salty again?
- Jesus
Salting your hashes is a good thing.  It adds another level of protection to your hash, and prevents the effectiveness of rainbow tables should your hash get out.  It&#8217;s been standard practice to use a salt when storing [...]]]></description>
			<content:encoded><![CDATA[<blockquote><p>Salt is good; but if the salt becomes unsalty, with what will you make it salty again?</p></blockquote>
<p>- Jesus</p>
<p><a href="http://en.wikipedia.org/wiki/Salt_(cryptography)">Salting your hashes</a> is a good thing.  It adds another level of protection to your hash, and prevents the effectiveness of rainbow tables should your hash get out.  It&#8217;s been standard practice to use a salt when storing passwords and similar information for almost 30 years now.  Using a weak salt can significantly reduce the protection it will give you.  Also, use of a salt should just be an additional level of protection to your hashes &#8211; not your only protection.  However, the use of a salt doesn&#8217;t suddenly mean that sharing your hashes with the world is a good thing.</p>
<p><span id="more-79"></span></p>
<p>Not too long ago, I was reviewing the code on a smaller open source CMS.  I came across this block of code<br />
<code><br />
function setUserForeverCookie() {<br />
$hashVal = md5(PASSWORD_SALT . $this-&gt;getUserID());<br />
setcookie("ccmUserHash", $this-&gt;getUserID() . ':' . $hashVal, time() + 1209600, DIR_REL . '/');<br />
}</code></p>
<p>What function does is create a forever login cookie value out of an md5 hash of the combination of your user id and a static PASSWORD_SALT value.  The PASSWORD_SALT value is a number between 100,000 and 999,999, created upon the installation of the CMS.  The user id is a publicly availble id used to identify the user throughout the site, such as in the URL to the user&#8217;s profile page.  For the default super admin, the user id is always 1.</p>
<p>By creating an account and getting your own forever login value, you could easily discover this weak salt.<br />
<code>for ($i = 100000; $myForeverLogin != $guess; $i++) {<br />
  $guess = md5($i.$myUserId);<br />
}</p>
<p>echo "Salt is $i\n"<br />
echo "Admin cookie is ".md5($i.1);<br />
</code></p>
<p>In seconds those few lines of code will give you the server salt and the admin&#8217;s forever login cookie, giving you full control of the site.</p>
<p>While the use of something like a forever login cookie inherently poses some security risk and is prohibited from use in such regulated industries as financial or healthcare (you always need to login when you visit your bank, for example), there are times that it&#8217;ll come up as a requirement and it might make sense to do with your web app.</p>
<p>A better implementation of a forever login would combine a stronger salt with a number used once, or nonce, which would be stored in the database with a user record.  A stronger salt would be something like a 32 character key of random letters &#038; numbers.  The hash algorithm probably wouldn&#8217;t be md5 either, and instead use a stronger encryption algorithm.  By using both a strong salt stored outside of the database and a nonce in the database, a breach of either the code or the database alone would not allow a user to create a forever login.</p>
]]></content:encoded>
			<wfw:commentRss>http://josephkeeler.com/2009/07/php-security-weak-salt-vulnerabilities/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>What are you sharing? &#8211; Browser History Scraping</title>
		<link>http://josephkeeler.com/2009/06/browser-history-scraping/</link>
		<comments>http://josephkeeler.com/2009/06/browser-history-scraping/#comments</comments>
		<pubDate>Mon, 22 Jun 2009 03:13:09 +0000</pubDate>
		<dc:creator>Joseph</dc:creator>
				<category><![CDATA[General Web Security]]></category>

		<guid isPermaLink="false">http://josephkeeler.com/?p=81</guid>
		<description><![CDATA[The Internet offers the potential for safe, convenient       new ways to shop for financial services and conduct banking business, any           day, any time.
-FDIC, Safe Internet Banking
Anytime you visit a website, you&#8217;re providing the oppurtunity for that website to discover [...]]]></description>
			<content:encoded><![CDATA[<blockquote><p><span style="font-family: Arial, Arial;"><span style="font-family: Arial, Helvetica, sans-serif;">The Internet offers the potential for safe, convenient       new ways to shop for financial services and conduct banking business, any           day, any time.</span></span></p></blockquote>
<p><span style="font-family: Arial, Arial;"><span style="font-family: Arial, Helvetica, sans-serif;">-FDIC, Safe Internet Banking</span></span></p>
<p>Anytime you visit a website, you&#8217;re providing the oppurtunity for that website to discover a lot of information about yourself.  Cross-site scripting (XSS) vulnerabilities in websites could allow a malicious 3rd party site to gain access to your email, your Facebook account, your bank account, credit cards, etc.  Security vulnerabilities in browsers, link handlers, embedded media players, and other software could be used to compromise your local machine and monitor everything you do in the background.<span id="more-81"></span></p>
<p>Even if all the security vulnerabilites across the Internet were somehow fixed, the conveniences browsers offer you by design still create the potential for misues and abuse.  All of the main browsers save some sort of browsing history.  They also will provide the ability for a website you visit to change the color of visited links.  By creating a page that has a list of links, and then iterating through them to see what color they are, you can find out what sites that computer visits.</p>
<p>Your browsing history is likely to show whether you use MySpace or Facebook, Google or Yahoo, which bank you use, what sites you shop at, what YouTube videos you&#8217;ve watched, etc.  This information could be used for your benefit, like linking an address to your preferred mapping website.  It could also be used for marketing research, or to get enough information to make a good social engineering request to get even more information.</p>
<p>This isn&#8217;t considered a security vulnerability, it&#8217;s part of the design of the Internet.  As such, the use of anti-spyware and anti-virus software will do nothing to protect you.  There are no files you have to install, no popus you have to allow or deny.  You unknowingly provide all of this information by simply viewing a web page.</p>
<p>To protect yourself from this, one of the best options is to eiter turn off or clear your browser history regularly.  With the many browser security vulnerabilities that exist, even better practice is to use a separate browser than what you normally use to visit sites that contain sensitive information, like your bank.</p>
<p>For a quick demonstration of this concept in action, visit <a href="http://www.whoismybank.com">http://www.whoismybank.com</a>.  This site does not store any of your information.</p>
<p>References:</p>
<p>http://jeremiahgrossman.blogspot.com/2006/08/i-know-where-youve-been.html</p>
<p>http://www.cs.indiana.edu/~sstamm/projects/recon/</p>
]]></content:encoded>
			<wfw:commentRss>http://josephkeeler.com/2009/06/browser-history-scraping/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP Performance &#8211; Optimize, Eliminate or Scale</title>
		<link>http://josephkeeler.com/2009/05/php-performance-optimize-eliminate-or-scale/</link>
		<comments>http://josephkeeler.com/2009/05/php-performance-optimize-eliminate-or-scale/#comments</comments>
		<pubDate>Thu, 14 May 2009 22:07:07 +0000</pubDate>
		<dc:creator>Joseph</dc:creator>
				<category><![CDATA[PHP Performance]]></category>

		<guid isPermaLink="false">http://josephkeeler.com/?p=59</guid>
		<description><![CDATA[Get several more uses from your toothpaste by placing the tube in boiling water for several minutes to loosen up the toothpaste inside, then pulling the tube down across the edge of the bathroom counter to scrape all of the toothpaste from the bottom of the tube to the top.
Once this technique no longer yields more toothpaste from the tube, use [...]]]></description>
			<content:encoded><![CDATA[<blockquote><p>Get several more uses from your toothpaste by placing the tube in boiling water for several minutes to loosen up the toothpaste inside, then pulling the tube down across the edge of the bathroom counter to scrape all of the toothpaste from the bottom of the tube to the top.</p>
<p>Once this technique no longer yields more toothpaste from the tube, use a pair of scissors to cut the tube open about an inch or two from the top. Open the top part and use your toothbrush to scrape the toothpaste out of the inside of the tube.</p></blockquote>
<p>-Associated Content</p>
<p>When it comes to improving performance in a PHP system, there are a few different approaches you can take.  First, find out where your system performance can best be improved &#8211; see <a href="http://josephkeeler.com/2009/05/php-optimization-where-to-start/" target="_self">PHP Optimization &#8211; Where to Start</a>.  Once you know where your biggest bottlenecks are, you can try to optimize through them, but at some point, you&#8217;ll reach the limits of what optimization can do for you &#8211;  run out of toothpaste, so to speak.  There are two widely used performance techniques beyond optimization &#8211; eliminate it, or scale it out.</p>
<p><span id="more-59"></span></p>
<p> </p>
<h2>Optimize</h2>
<p>Generally speaking, optimizing is getting the system to do the same thing, only faster. Optimization techniques include things like tuning the server configuration for optimal performance, refactoring the code to get better performance from PHP, Opcode caching or adding indexes to the database tables for faster reads. Optimizing is usually one of the first tools you&#8217;ll be pulling out of your bag to deal with performance issues.  But there are limits as to how far optimization will take you.</p>
<p>With optimization, there is the law of diminishing returns.  Your first pass at optimization may yield a 600%-800% performance improvement.  Maybe your next one will give you a 200% improvement.  The next one may still give you a 100% improvement.  With each pass, finding ways to get those big performance gains will become increasingly difficult.  At some point, you&#8217;ll be struggling to get a 5% performance boost.  Or maybe you&#8217;ll find a way to increase performance, but it will also mean the code will become unmaintainable (Even if your one supergenius coder on the team can work with it, if it&#8217;s so confusing no other programmer can, it&#8217;s unmaintainable.  More on that later).</p>
<p>At some point, it&#8217;s not going to be worth trying to continue down this route as your performance needs increase.  I don&#8217;t boil my toothpaste and split it open to get every last drop, I go buy a new tube of toothpaste.  Similarly, at some point, even if I know that there are still probably some performance improvements somewhere still be in the system, I&#8217;ll start looking for something other than optimization to improve system performance.  This is where elimination and scaling come into play.</p>
<p> </p>
<h2>Eliminate</h2>
<p>Elimination is getting rid of your bottlenecks by finding a way to not have to execute them.  There are several different ways to do this.  Caching and using background process are commonly used ones.  Caching is probably the most common elimination technique &#8211; if there is data that does not need to be updated with every run, saving and reusing the processed information will save you from having to process it each time.  </p>
<p>Another common elimination technique is to take the heavy lifting off of the PHP loader and put it into separate running background process.  If there is a &#8220;heavy&#8221; process that doesn&#8217;t need to be real time, just close to real time, maybe it would make sense to have a cron job do the processing of this information.  The web user would then just look at this pre-processed information instead of processing every time.  This works two ways too &#8211; If a user uploads data, instead of waiting for it to be processed in real-time, maybe you could just hold it in a queue and tell them that it will be processed later.</p>
<p> </p>
<h2>Scale</h2>
<p>Even with using optimization and elimination, or if you need to deal with real-time processes where elimination isn&#8217;t an option, you&#8217;ll reach some limits and need to be able to scale your PHP system to get better performance.  There&#8217;s &#8220;vertical scaling,&#8221; which means doing something like buying a 48-core server with a terrabyte of RAM; kind of an expensive route.  And then there&#8217;s horizontal scaling, which is setting up your system so that it can be split across multiple pieces of hardware to distribute the load.  This same technique can also be used to give you highly available redundant systems.</p>
<p>Designing a system to horizontally scale typically requires the most work and has the most complexity of any of these three routes. And for many PHP systems, it&#8217;s a necessary route to take somewhere in the system.  Deciding what needs to be able to horizontally scale is extremely situationally dependent.  And with the added complexity to the development and the extra development time and costs that comes with this, designing to scale in situations that don&#8217;t need it is a very poor use of resources.</p>
<p> </p>
<h2>Summing it up</h2>
<p>When it comes to improving PHP performance, there are many approaches that you can take, with no blanket solutions that will solve your problems in every situation.  With each option, there are pros and cons to consider that will be impacted by many factors, anything from the deployment to the makeup of team that&#8217;s working on it.  Having a big bag of tools to approach performance issues is necessary, especially for those times you can&#8217;t rely on being able to boil out a little more toothpaste.</p>
]]></content:encoded>
			<wfw:commentRss>http://josephkeeler.com/2009/05/php-performance-optimize-eliminate-or-scale/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP Security &#8211; Escape proof SQL injection in ORDER BY clause</title>
		<link>http://josephkeeler.com/2009/05/php-security-sql-injection-in-order-by/</link>
		<comments>http://josephkeeler.com/2009/05/php-security-sql-injection-in-order-by/#comments</comments>
		<pubDate>Wed, 13 May 2009 16:24:48 +0000</pubDate>
		<dc:creator>Joseph</dc:creator>
				<category><![CDATA[PHP Security]]></category>

		<guid isPermaLink="false">http://josephkeeler.com/?p=46</guid>
		<description><![CDATA[It&#8217;s a well known, well documented, and well abused fact that SQL injection attacks can take place in the WHERE clause of a SQL statement. The commonly applied practice among professionals is to run user input through mysql(i)_real_escape_string(). However, this only protects against user variables within quoted values, and does not protect against SQL injection [...]]]></description>
			<content:encoded><![CDATA[<div class="wp-caption alignnone" style="width: 560px"><img class="      " title="XKCD - Little Bobby Tables" src="http://imgs.xkcd.com/comics/exploits_of_a_mom.png" alt="http://xkcd.com/327/" width="550" height="169" /><p class="wp-caption-text">http://xkcd.com/327/</p></div>
<p>It&#8217;s a well known, well documented, and well abused fact that SQL injection attacks can take place in the WHERE clause of a SQL statement. The commonly applied practice among professionals is to run user input through mysql(i)_real_escape_string(). However, this only protects against user variables within quoted values, and does not protect against SQL injection attacks elsewhere in the query.</p>
<p>One place that is commonly vulnerable is in the ORDER BY clause. Many developers either do not understand that mysql(i)_real_escape_string does not protect them from these types of attacks, or do not think that meaningful SQL injection can be done at this point in the query on a single statement engine like MySQL. As a result, this vulnerability can be found and exploited in many applications and websites, both commercial and open source, personal and corporate.<span id="more-46"></span></p>
<p>Vulnerable code and SQL queries is basically:</p>
<p><code>&lt;php<br />
 <br />
$sortColumn = mysqli_real_escape_string($_GET['sort_column']);<br />
$query ="SELECT * from some_table WHERE active = true ORDER BY $sortColumn DESC";<br />
 <br />
?&gt;</code></p>
<p>This is vulnerable to a SQL injection attack that will allow a hacker to get information from any table in the database, whether it&#8217;s usernames, passwords, credit card account numbers, etc.<br />
 </p>
<h2>How this can be exploited<br />
 </h2>
<p>The core theory behind the exploit is that this vulnerable query allow you to test a tiny piece of information from anywhere in the database in a boolean query that doesn&#8217;t rely on any unescaped characters, then use the value of that boolean to visibly change the output of the query.</p>
<p>Assume that the vulnerable site is a news site and lets you sort the article listings by the date or title column.  When you click on the column header you want to sort by, it sends a &#8217;sort_column&#8217; parameter to the above script of either &#8216;date&#8217; or &#8216;title&#8217;.  </p>
<p>If instead of sending &#8216;date&#8217; or &#8216;title&#8217;, you sent something like the following string, you would be able to start reading information from anywhere in the database.  In this particular case, we&#8217;ll try the users table.</p>
<p>(CASE WHEN (SELECT ASCII(SUBSTRING(password, 1, 1)) FROM users where username = 0&#215;61646D696E) = 65 THEN date ELSE title END)</p>
<p>Assuming that this is the correct table and column names, this injection will allow you to tell whether or not the first character of the admin user&#8217;s password is &#8216;A&#8217;. If it is, the article list will be returned sorted by date.  If not, it will be returned sorted by title.</p>
<p>If it isn&#8217;t a match, then the 65 in the query just needs to be incremented/decremented until the match is made to try other various letters/symbols. Once the match is made and the first character is discovered, the substring offset just needs to be incremented to get the second character, but this time starting with null to see if the end of the string has already been reached. If not, start back at 65, and repeat the process until null matches.</p>
<p>This does require some knowledge about the database schema, which can be guessed, looked up on open source applications, or can be learned by first querying against a known table like the information schema.</p>
<p>A script can be written to do automate this process very quickly, as an 8 character password with upper and lowercase letters and numbers can be discovered with a maximum of 500 queries. MD5 encoded passwords will have the hashes revealed in less than 512 queries, which can then be brute force decoded (at over 500 million attempts/second, thanks to <a href="http://bvernoux.free.fr/md5/index.php" target="_blank">GPU computing</a>), or directly looked up if the password is a common word or phrase.<br />
 </p>
<h2>Why This Works</h2>
<p>Because each of these queries puts user input in a place in the query that is not enclosed with &#8216;, there is no need to use any of the characters that would be escaped by mysql(i)_real_escape_string(). Instead, SQL can be directly passed directly into the query. In places that strings are normally used when making a query, Hex notation, ASCII or other character conversion can be used to convert strings to or from their numeric values. As demonstrated in these examples, anywhere that SQL can be injected into a query is a major security vulnerability.<br />
 </p>
<h2>How to Secure</h2>
<p>Securing this type of query is a rather simple process.  If a column name is expected, the user input should be validated against a whitelist array. </p>
<p>Applying this on the example query:</p>
<p><code>&lt;php<br />
$columns = array(<br />
'title',<br />
'date'<br />
);<br />
if (in_array($_GET['sort_column'], $columns)) {<br />
$sortColumn = $_GET['sort_column'];<br />
} else {<br />
$sortColumn = 'title';<br />
}</code></p>
<p><code> </code></p>
<p><code>?&gt;</code></p>
<p>As you can see, the above code will ensure that only expected/allowed values make it through to the database. So remember, trust no one, and sanitize everything, regardless of how harmless you may think invalid input will be.</p>
]]></content:encoded>
			<wfw:commentRss>http://josephkeeler.com/2009/05/php-security-sql-injection-in-order-by/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>PHP Optimization &#8211; Where to start</title>
		<link>http://josephkeeler.com/2009/05/php-optimization-where-to-start/</link>
		<comments>http://josephkeeler.com/2009/05/php-optimization-where-to-start/#comments</comments>
		<pubDate>Tue, 12 May 2009 01:19:37 +0000</pubDate>
		<dc:creator>Joseph</dc:creator>
				<category><![CDATA[PHP Performance]]></category>

		<guid isPermaLink="false">http://josephkeeler.com/?p=20</guid>
		<description><![CDATA[“Our web app is slow,” complained the boss.
“Well, I hear that using commas instead of periods with echo() makes PHP faster,” replied the code monkey.
“Well, let’s try optimizing that,” said the boss.
$100k later.
“Well, it’s still slow after that change.  I guess we’ve reached the limits of PHP.  Time to switch to Java.”
If you [...]]]></description>
			<content:encoded><![CDATA[<blockquote><p>“Our web app is slow,” complained the boss.<br />
“Well, I hear that using commas instead of periods with echo() makes PHP faster,” replied the code monkey.<br />
“Well, let’s try optimizing that,” said the boss.</p>
<p>$100k later.<br />
“Well, it’s still slow after that change.  I guess we’ve reached the limits of PHP.  Time to switch to Java.”</p></blockquote>
<p>If you run a website that becomes successful, at some point, you’re going to run into performance issues.  Heck, you may only need a single visitor with some scripts to bring it to a crawl.  There are a few different approaches often used for optimizing PHP, but really only one right one.  First there’s the old school way, dump in a bunch of var_dumps of script execution time and hope to find a slow spot.  Not very efficient.</p>
<p>Then there’s what I like to call the cluster-bomb optimizing approach.  These are those lists of 40 things to do to optimize PHP and the like.  I call this the cluster-bomb approach because you’re just throwing a bunch of tiny optimizations all over the place hoping that you hit one that’s causing your performance issues.  A lot of these recommendations will leave you with a trashed collection of unmaintainable code.  A cluster-f*** of code so to speak.</p>
<p>Very rarely will the majority of these recommendations actually make an impact to a real-world performance issue.  I know this because I regularly fix real-world performance issues, and I rarely follow most of the optimization “tips” in those lists.</p>
<p>And then there’s the profiling method.  This I think is the only right way to begin any sort of optimization process, in PHP or any other language.  For the uninitiated, a profiler is a process that will sit with your script handler and generate a detailed log of exactly what happened during a script run, how long a subprocess took, etc.  You can then take this log and get a visual representation of your scripts performance.  From there, it’s really easy to see where the performance bottlenecks are in the system, and give you a good idea of where the best effort could be put in optimization.</p>
<p><span id="more-20"></span></p>
<p>For PHP optimization and profiling, the tools that I like to use are <a href="http://www.xdebug.org/" target="_blank">Xdebug</a> and <a href="http://kcachegrind.sourceforge.net/html/Home.html" target="_blank">KCacheGrind</a>.  Xdebug is the profiler, and KCacheGrind is the graphical reader of the profiler.  First, install Xdebug on your PHP server.  You’ll need to be able to generate a profiler log.  You can do this by either enabling it in your core php.ini file, activating it from within your script, or, my preference, turning on the xdebug.profiler_enable_trigger setting in your php.ini so you just have to add XDEBUG_PROFILE=1 as a parameter in your URL or POST parameters, and you can generate the profiler files easily on demand.</p>
<p>Once you’ve generated the profiler log, open it up in KCacheGrind.  This is a very powerful tool that I won’t be covering very in depth, but it does make finding problem spots in the code very simple.  Using the Callee Map tab on the right side of the screen, you will see a visual representation of how long the calls in your script were for each run.  The larger the box, the more time relative to the other process was spent in that process.  By clicking on a box, you can see a stack trace of where that specific box is.</p>
<p>The visual profile of a complex OO script may look something like this</p>
<div id="attachment_21" class="wp-caption alignnone" style="width: 510px"><img class="size-full wp-image-21" title="KCacheGrind Dump" src="http://www.josephkeeler.com/wp-content/uploads/2009/05/better_profile.jpg" alt="KCacheGrind Dump" width="500" height="334" /><p class="wp-caption-text">KCacheGrind Dump</p></div>
<p>The largest block there represents 17% of the run time of that script.  If I wanted to improve performance of this script, I may want to look there.  Or maybe this tells me that I need to optimize system performance by looking at something other than script internals. Or maybe I need to look at ways to reduce the number of calls in the script run.  Each situation has its own unique requirements, and there is often more than one good approach to solving the problem.</p>
<p>If you have a slow performing script with a bottleneck, you may see something more like this.</p>
<div id="attachment_22" class="wp-caption alignnone" style="width: 510px"><img class="size-full wp-image-22" title="KCachegrind dump of bottlenecked PHP script" src="http://www.josephkeeler.com/wp-content/uploads/2009/05/bottleneck_profile.jpg" alt="KCachegrind dump of bottlenecked PHP script" width="500" height="309" /><p class="wp-caption-text">KCachegrind dump of bottlenecked PHP script</p></div>
<p>The two largest boxes there represent 80% of the total script run time.  This is definitely where the script bottleneck is, and performance efforts would be best directed. Directing any effort anywhere else wouldn&#8217;t have any significant impact as it represents &lt;20% of the script run.  In this particular case, the two boxes were a couple of sloppy SQL queries (something, btw, which isn’t even on the 40 ways to optimize PHP list).  But by cleaning those up, I was able to easily do a 70% performance improvement to the script run time.</p>
<p>Now, a code bottleneck is certainly not going to be the cause of every problem, but it will be found with the majority of performance issue you’ll come across.  And each bottleneck needs to be treated differently, more to come on that later. But by using the right tools and taking the few minutes to analyze your script, you&#8217;ll quickly gain excellent insight into how to best direct your optimization efforts.</p>
<p>Using these tools to find where to optimize, I was able to reduce script run time by 70% in about 20 minutes.  Let’s see you do that by swapping out your double quotes for single quotes (#28).</p>
]]></content:encoded>
			<wfw:commentRss>http://josephkeeler.com/2009/05/php-optimization-where-to-start/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>PHP Upload Security &amp; The 1&#215;1 jpeg Hack</title>
		<link>http://josephkeeler.com/2009/04/php-upload-security-the-1x1-jpeg-hack/</link>
		<comments>http://josephkeeler.com/2009/04/php-upload-security-the-1x1-jpeg-hack/#comments</comments>
		<pubDate>Sat, 04 Apr 2009 00:35:15 +0000</pubDate>
		<dc:creator>Joseph</dc:creator>
				<category><![CDATA[PHP Security]]></category>

		<guid isPermaLink="false">http://josephkeeler.com/?p=3</guid>
		<description><![CDATA[

Far too often, I&#8217;ve seen example PHP code, or live PHP code, where file upload checks exclusively using
$_FILES['userfile']['type'] == &#8216;image/jpeg&#8217;
or
getimagesize($filename)
or
strpos(&#8216;.jpg&#8217;, $_FILES['userfile']['name'] or strstr(&#8216;jpg&#8217;, $_FILES['userfile']['name']
followed by something like
move_uploaded_file($_FILES['userfile']['tmpname'], PUBLIC_WEB_UPLOAD_DIR.$_FILES['userfile']['name']);
All of these methods leave the server completely vulnerable to remote script uploading and execution with the 1&#215;1 jpeg hack.
 

How this can be exploited

To execute the 1&#215;1 jpeg [...]]]></description>
			<content:encoded><![CDATA[<div class="post-body entry-content">
<div>
<div>Far too often, I&#8217;ve seen example PHP code, or live PHP code, where file upload checks exclusively using</div>
<div>$_FILES['userfile']['type'] == &#8216;image/jpeg&#8217;</div>
<div>or</div>
<div>getimagesize($filename)</div>
<div>or</div>
<div>strpos(&#8216;.jpg&#8217;, $_FILES['userfile']['name'] or strstr(&#8216;jpg&#8217;, $_FILES['userfile']['name']</div>
<div>followed by something like</div>
<div>move_uploaded_file($_FILES['userfile']['tmpname'], PUBLIC_WEB_UPLOAD_DIR.$_FILES['userfile']['name']);</div>
<div>All of these methods leave the server completely vulnerable to remote script uploading and execution with the 1&#215;1 jpeg hack.<br />
 </div>
<div><strong><br />
How this can be exploited<br />
</strong></div>
<div>To execute the 1&#215;1 jpeg hack on a PHP server:</div>
<div>Create a 1&#215;1 jpeg</div>
<div>Put the PHP code you want executed on the server in the embedded jpeg header, surrounded by tags</div>
<div>Name your file some_random_name.jpg.php</div>
<div>Tell your browser/os that a .php file is of type image/jpeg.</div>
<div>Upload the file</div>
<div>When that file is uploaded your file against a server that uses the above method(s) as a &#8220;security&#8221; check to prevent remote file upload &amp; execution it will pass all checks, and will be executed whenever that file is requested by a client browser, whether it&#8217;s a direct request in the browser address or an embedded request in a &lt;img&gt; tag.</div>
<div><strong><span id="more-3"></span><br />
Why this works<br />
</strong></div>
<div>$_FILES['userfile']['type'] comes from the client browser. There is no server-side check to see what type of file it is, there&#8217;s no comparison of that file&#8217;s extension with the server extension list. It&#8217;s simply part of the HTTP header from the browser. By changing the file type association on a client machine that .php files are of type image/jpeg, the browser will upload files with a .php extension with a header type of image/jpeg, passing the first check.</div>
<div>The getimagesize() function will tell you if the uploaded file is a valid image or not. A 1&#215;1 jpeg is a valid image, and could be displayed just fine in a browser. The problem here is what happens when the page is requested by the user. When Apache recieves a request and serves a file, Apache simply looks at the final extension of the file, and decides how to process that file based on that. In all of these cases, $_FILES['userfile']['name'] will be used, and ends with a .php extension. So Apache will process this file as a php file, and run it through the PHP interpreter prior to serving the file, executing the PHP code that was embedded in the jpeg header.</div>
<div><strong><br />
How to secure<br />
</strong></div>
<div>The simple fix that works on 99.9% of the servers out there is to manually change the file extension to .jpg, .png, .gif or whatever type it&#8217;s supposed to be when the file is moved from the temp directory to the public web directory. A very simple, basic step that is too often overlooked when dealing with upload security. But it&#8217;s more effective and less processor intensive than any of the above techniques.</div>
<div>The &lt;0.1% of servers this will not work on are servers that run all files, or image files, through the PHP processor, regardless of extension. Weird, but yes, they are out there. On these servers, to prevent image header script execution, the GD (or Imagemagick) library should be used to recreate the image, and that new file should be saved. This will wipe the image headers, and any embedded code present.</div>
<div>There are more steps that can, and should be taken when dealing with file uploads, such as not putting them directly into a public web folder in the first place, but rather make a link to a file handler. There&#8217;s a whole new set of secure issues with that method for a later post, but done right, it is more effective. But by taking the simple precautions listed here, it will security the majority of sites and servers from most upload attacks.</div>
</div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://josephkeeler.com/2009/04/php-upload-security-the-1x1-jpeg-hack/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
