<?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>Spare Pencil &#187; Articles</title>
	<atom:link href="http://sparepencil.com/archives/category/articles/feed/" rel="self" type="application/rss+xml" />
	<link>http://sparepencil.com</link>
	<description></description>
	<lastBuildDate>Sun, 06 Jun 2010 03:17:05 +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>Wordpress and the cookies</title>
		<link>http://sparepencil.com/archives/2007/06/03/wordpress-and-the-cookies/</link>
		<comments>http://sparepencil.com/archives/2007/06/03/wordpress-and-the-cookies/#comments</comments>
		<pubDate>Sun, 03 Jun 2007 21:09:14 +0000</pubDate>
		<dc:creator>Bas</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://sparepencil.com/archives/2007/06/03/wordpress-and-the-cookies/</guid>
		<description><![CDATA[<p><ins datetime="2007-08-21T17:03:59+00:00"><strong>Important:</strong> The workaround provided in this post is not reliable enough, there is now a more secure way to fix this problem. The new fix is available as <a href="http://sparepencil.com/code/ajax-referer-fix/">a convenient plugin</a>.</ins></p>
<p>Since the release of <a href="http://wordpress.org/">Wordpress</a> 2.0, a&#8230;</p>]]></description>
			<content:encoded><![CDATA[<p><ins datetime="2007-08-21T17:03:59+00:00"><strong>Important:</strong> The workaround provided in this post is not reliable enough, there is now a more secure way to fix this problem. The new fix is available as <a href="http://sparepencil.com/code/ajax-referer-fix/">a convenient plugin</a>.</ins></p>
<p>Since the release of <a href="http://wordpress.org/">Wordpress</a> 2.0, a pesky bug has been annoying several bloggers. The nice AJAX effects in the administrator panel stopped working; even a fully privileged user would receive a <strong>&#8220;You don&#8217;t have permission to do that&#8221;</strong> message when trying to add or remove categories, posts and more.</p>
<p>The Wordpress developers are <a href="http://trac.wordpress.org/ticket/3807">aware of this bug</a>, but the ticket has recently been moved to milestone 2.4. Which basically means we bloggers will have to wait another few months for an official fix.</p>
<p>So far, it has been unclear as to what is causing this problem. I recently upgraded to Wordpress version 2.2 (many important bugs have been fixed, I recommend it) but I was disappointed to find out that the AJAX problem was still there. That&#8217;s when I decided to check the root of this bug myself.</p>
<h2>Suhosin</h2>
<p><a href="http://www.hardened-php.net/suhosin/">Suhosin</a> is a patch for PHP that hardens it against <a href="http://www.hardened-php.net/suhosin/a_feature_list.html">a wide range of web attacks</a>. It&#8217;s got a truly amazing set of precautions for problems of which you didn&#8217;t even know they existed.</p>
<p>One of its features is cookie encryption. This basically encrypts the cookie using both server and client specific information (a custom key, user agent and more) before sending it to the client. This feature is useful, because if some malicious code on the client-side (<a href="http://en.wikipedia.org/wiki/Cross-site_scripting">XSS</a> is most common) manages to get a hold of the cookie it can not do anything with it.</p>
<p>In addition to encrypting the cookie before sending it to the client, Suhosin will also decrypt cookies it receives so you can use it in PHP without problems.</p>
<h2>Or can we&#8230;?</h2>
<p>All of the AJAX-powered actions performed in the Wordpress admin panel go to one script: <em>/wp-admin/admin-ajax.php</em><br />
The first thing this script does is calling the function <em>check_ajax_referer()</em> (located in <em>/wp-includes/pluggable.php</em>).<br />
This is what the function looks like:</p>
<pre><code lang="php">function check_ajax_referer() {
	$cookie = explode('; ', urldecode(empty($_POST['cookie']) ? $_GET['cookie'] : $_POST['cookie'])); // AJAX scripts must pass cookie=document.cookie
	foreach ( $cookie as $tasty ) {
		if ( false !== strpos($tasty, USER_COOKIE) )
			$user = substr(strstr($tasty, '='), 1);
		if ( false !== strpos($tasty, PASS_COOKIE) )
			$pass = substr(strstr($tasty, '='), 1);
	}
	if ( !sp_login( $user, $pass, true ) )
		die('-1');
	do_action('check_ajax_referer');
}</code></pre>
<p>As you can see, Wordpress avoids using the HTTP Cookie header for AJAX requests (it&#8217;s even mentioned in the comment). Instead, the cookie is appended to the request data.This is done, of course, on the client side using Javascript.</p>
<p>When <a href="http://developer.mozilla.org/en/docs/DOM:document.cookie">document.cookie</a> is appended to the request, there is still no problem. The Cookie header and the <em>document.cookie</em> are practically the same. But once the request arrives at the server, Suhosin will only decrypt the Cookie. Not the appended <em>document.cookie</em>, because it is not recognised as a cookie at all (it&#8217;s just an encoded variable).</p>
<p>So when Wordpress reads the cookie from the request data, it actually reads the encrypted cookie. And you can&#8217;t log in with an encrypted cookie, so you are denied permission.</p>
<h2>There is a workaround</h2>
<p>Fortunately, most browsers (as far as I know) also send the Cookie header. Suhosin flawlessly decrypts the data contained in this header and puts everything in the <em>$_COOKIE</em> variable.</p>
<p>I am not really sure why the Wordpress developers chose to send cookies via the request body, but until they come up with a better fix for this problem, I am providing the following workaround:</p>
<pre><code lang="php">function check_ajax_referer() {
	// Suhosin workaround
	$dough = ini_get('suhosin.cookie.encrypt');
	if ( 1 == $dough || 'On' == $dough || 'on' == $dough ) {
		$user = $_COOKIE[USER_COOKIE];
		$pass = $_COOKIE[PASS_COOKIE];
	} else {
		$cookie = explode('; ', urldecode(empty($_POST['cookie']) ? $_GET['cookie'] : $_POST['cookie'])); // AJAX scripts must pass cookie=document.cookie
		foreach ( $cookie as $tasty ) {
			if ( false !== strpos($tasty, USER_COOKIE) )
				$user = substr(strstr($tasty, '='), 1);
			if ( false !== strpos($tasty, PASS_COOKIE) )
				$pass = substr(strstr($tasty, '='), 1);
		}
	}
	if ( !sp_login( $user, $pass, true ) )
		die('-1');
	do_action('check_ajax_referer');
}</code></pre>
<p>This can be applied to any Wordpress installation. Servers without Suhosin will run Wordpress the regular way. Servers with Suhosin cookie encryption enabled will make Wordpress fall back to using the standard cookie.</p>
<p>I might look into writing a PHP function that simulates Suhosin cookie decryption. This will allow Wordpress to use the cookie in the request in both cases. Unfortunately, I was unable to find sufficient information for this.</p>
<h2><del datetime="2007-08-21T17:03:59+00:00">Patch for Wordpress 2.2</del></h2>
<p><del datetime="2007-08-21T17:03:59+00:00">I created a patch file for Wordpress 2.2. It must be applied to <em>/wp-includes/pluggable.php</em>.</del></p>
<p><del datetime="2007-08-21T17:03:59+00:00"><a href="">Download the file</a>.<br />
Linux users can patch using:</del><br />
<del datetime="2007-08-21T17:03:59+00:00"><code lang="bash">$ patch /path/to/wp-includes/pluggable.php /path/to/pluggable.diff</code><br />
Windows users can download <a href="http://gnuwin32.sourceforge.net/packages/patch.htm">GNU patch for Windows</a>. And run it from the Command line interface:</del></p>
<pre><code lang="DOS">C:\path\to\patch.exe \path\to\wp-includes\pluggable.php \path\to\pluggable.diff</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://sparepencil.com/archives/2007/06/03/wordpress-and-the-cookies/feed/</wfw:commentRss>
		<slash:comments>33</slash:comments>
		</item>
		<item>
		<title>Airtight sessions</title>
		<link>http://sparepencil.com/archives/2007/04/15/airtight-sessions/</link>
		<comments>http://sparepencil.com/archives/2007/04/15/airtight-sessions/#comments</comments>
		<pubDate>Sat, 14 Apr 2007 22:13:39 +0000</pubDate>
		<dc:creator>Bas</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://sparepencil.com/archives/2007/04/15/airtight-sessions/</guid>
		<description><![CDATA[<p>I recently read <a href="http://www.cbronline.com/article_news.asp?guid=484BC88B-630F-4E74-94E9-8D89DD0E6606">an article</a> which warns about the fact that cookie based authentication can be exploited using JavaScript. I am not going into detail about the problem itself, but I&#8217;ll try to give a brief explanation using an&#8230;</p>]]></description>
			<content:encoded><![CDATA[<p>I recently read <a href="http://www.cbronline.com/article_news.asp?guid=484BC88B-630F-4E74-94E9-8D89DD0E6606">an article</a> which warns about the fact that cookie based authentication can be exploited using JavaScript. I am not going into detail about the problem itself, but I&#8217;ll try to give a brief explanation using an example:<br />
Alice is a user browsing the web. She is logged in on site A using a session ID which is conveniently stored in a cookie on her PC. Meanwhile, she browses around a bit and stumbles upon site B. Site B contains an evil piece of JavaScript code that makes a request at site A. There is a loophole in Alice&#8217;s browser&#8217;s (which could be any modern browser) <a href="http://en.wikipedia.org/wiki/Same_origin_policy">same origin policy</a>: The request is submitted <strong>with the session cookie</strong> for site A. The request is automatically accepted by site A, because the session was authorised, but Alice has no idea (until she finds out that something disastrous has happened to her account).</p>
<p>You might think the browser is the weak link here, because it doesn&#8217;t handle the cookie correctly. That is true, but apparently it is difficult to flawlessly apply the same origin policy. I might be wrong though, but it doesn&#8217;t really matter for now, because this article focuses on something else.</p>
<p>The server side application at site A could have been protected against the attack. In this article, I will highlight a few methods that could make the process safer. Airtight sessions.</p>
<p>As developers of website applications, we will have to avoid relying on cookie data contained in the HTTP Cookie header when performing certain actions. These certain actions are basically the ones that require authentication (e.g.. changing user preferences, making a blog post, <a href="http://digg.com/">digg</a>ing a story, etc.)<br />
There are two ways in which this can occur: 1) using an HTML form (with <code>POST</code> data) and 2) using the <code><a href="http://www.w3.org/TR/XMLHttpRequest/">XMLHttpRequest</a></code> object. The difference is that the latter uses JavaScript and the first does not (or does not have to, at least).<br />
We&#8217;ll have a look at the HTML form scenario first.</p>
<h2>The HTML form way</h2>
<p>The following form allows an authenticated user to change his or her email address (just try to imagine it, if you don&#8217;t agree).<br />
It is generated by a PHP script (doesn&#8217;t matter for now, but will be useful later),</p>
<div class="geshi no php">
<ol>
<li class="li1">
<div class="de1"><span class="re1">$form</span> <span class="sy0">=</span> <span class="st0">&#39;&lt;form action=&quot;change_email.php&quot; method=&quot;post&quot; enctype=&quot;application/x-www-form-urlencoded&quot;&gt; &lt;input name=&quot;email&quot; type=&quot;text&quot; /&gt; &lt;input name=&quot;change_email&quot; value=&quot;Change&quot; type=&quot;submit&quot; /&gt; &lt;/form&gt;&#39;</span><span class="sy0">;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="kw3">echo</span> <span class="re1">$form</span><span class="sy0">;</span></div>
</li>
</ol>
</div>
<p>The relevant part of the PHP script that takes care of this form (<code>change_email.php</code>) looks like this:</p>
<div class="geshi no php">
<ol>
<li class="li1">
<div class="de1"><span class="kw3">session_start</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">if</span><span class="br0">&#40;</span><span class="kw2">true</span> <span class="sy0">!=</span> <span class="re1">$_SESSION</span><span class="br0">&#91;</span><span class="st0">&#39;logged_in&#39;</span><span class="br0">&#93;</span><span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; <span class="kw3">exit</span><span class="sy0">;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">if</span><span class="br0">&#40;</span><span class="kw3">isset</span><span class="br0">&#40;</span><span class="re1">$_POST</span><span class="br0">&#41;</span><span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; <span class="co1">// Deal with the form&#8230;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; <span class="co1">// &#8230;</span></div>
</li>
</ol>
</div>
<p>Note that the user is authenticated by means of the session variable <code>logged_in</code>. The session ID is, of course, obtained via a cookie.</p>
<p>We don&#8217;t want this, because the cookie might not be safe. Instead, we will use a custom solution. (There may be other possibilities to make this form safer, but I will demonstrate just one.)<br />
To avoid using a cookie, we will make the session ID part of the form. The form code snippet will look like this:</p>
<div class="geshi no php">
<ol>
<li class="li1">
<div class="de1"><span class="re1">$form</span> <span class="sy0">=</span> <span class="st0">&#39;&lt;form action=&quot;change_email.php&quot; method=&quot;post&quot; enctype=&quot;application/x-www-form-urlencoded&quot;&gt; &lt;input name=&quot;email&quot; type=&quot;text&quot; /&gt; &lt;input name=&quot;change_email&quot; value=&quot;Change&quot; type=&quot;submit&quot; /&gt; &lt;input name=&quot;session_id&quot; value=&quot;&#39;</span> <span class="sy0">.</span> <span class="kw3">session_id</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy0">.</span> <span class="st0">&#39;&quot; type=&quot;hidden&quot; /&gt; &lt;/form&gt;&#39;</span><span class="sy0">;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="kw3">echo</span> <span class="re1">$form</span><span class="sy0">;</span></div>
</li>
</ol>
</div>
<p>When the form is submitted, it will also pass the session ID. Easy, right?</p>
<p>Now on to the <code>change_email.php</code> script. We must tell the session handler that we want to use the <code>POST</code>ed session ID instead of the one in the cookie (which is the default).<br />
The relevant part is slightly rewritten:</p>
<div class="geshi no php">
<ol>
<li class="li1">
<div class="de1"><span class="kw1">if</span><span class="br0">&#40;</span><span class="kw3">isset</span><span class="br0">&#40;</span><span class="re1">$_POST</span><span class="br0">&#41;</span><span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; <span class="re1">$safe_id</span> <span class="sy0">=</span> <span class="br0">&#40;</span><span class="kw3">isset</span><span class="br0">&#40;</span><span class="re1">$_POST</span><span class="br0">&#91;</span><span class="st0">&#39;session_id&#39;</span><span class="br0">&#93;</span><span class="br0">&#41;</span> ? <span class="re1">$_POST</span><span class="br0">&#91;</span><span class="st0">&#39;session_id&#39;</span><span class="br0">&#93;</span> <span class="sy0">:</span> <span class="kw2">null</span><span class="sy0">;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; <span class="kw3">session_id</span><span class="br0">&#40;</span><span class="re1">$safe_id</span><span class="br0">&#41;</span><span class="sy0">;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="kw3">session_start</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">if</span><span class="br0">&#40;</span><span class="kw2">true</span> <span class="sy0">!=</span> <span class="re1">$_SESSION</span><span class="br0">&#91;</span><span class="st0">&#39;logged_in&#39;</span><span class="br0">&#93;</span><span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; <span class="kw3">exit</span><span class="sy0">;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">if</span><span class="br0">&#40;</span><span class="kw3">isset</span><span class="br0">&#40;</span><span class="re1">$_POST</span><span class="br0">&#41;</span><span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; <span class="co1">// Deal with the form&#8230;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; <span class="co1">// &#8230;</span></div>
</li>
</ol>
</div>
<p>Lines 2 through 6 make sure the <code>POST</code> request is handled using the session that was set in the form. Line 4 may seem kind of useless, but it prevents an <code>E_NOTICE</code> from being triggered (it&#8217;s become a habit of mine to code like this&#8230;)<br />
The <code><a href="http://php.net/manual/en/function.session-id.php">session_id()</a></code> function allows us to change the session ID manually before starting the session.</p>
<p>This method should stop malicious JavaScript on external sites from abusing your cookies.</p>
<h2>The <code>XMLHttpRequest</code> way</h2>
<p>Imagine the previous situation of changing an email address, but then in AJAX style. I am not going into detail regarding the usage of the <code>XMLHttpRequest</code> object, because there are a bunch of frameworks that all work a bit differently.<br />
Just keep the following points in mind:</p>
<ul>
<li>The request method is <code>POST</code> (the recommended method for this kind of stuff, by the way)</li>
<li>The server side file is the same as the last version of <code>change_email.php</code></li>
</ul>
<p>So, basically, you will need to add the session ID cookie to the <code>POST</code> data. Luckily, you can use JavaScript to extract the ID from the existing cookies:</p>
<div class="geshi no javascript">
<ol>
<li class="li1">
<div class="de1"><span class="kw2">function</span> read_cookie<span class="br0">&#40;</span><span class="kw3">name</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; <span class="kw2">var</span> nameEQ = <span class="kw3">name</span> + <span class="st0">&quot;=&quot;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; <span class="kw2">var</span> ca = document.<span class="me1">cookie</span>.<span class="me1">split</span><span class="br0">&#40;</span><span class="st0">&#39;;&#39;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; <span class="kw1">for</span><span class="br0">&#40;</span><span class="kw2">var</span> i=<span class="nu0">0</span>;i <span class="sy0">&amp;</span>lt; ca.<span class="me1">length</span>;i++<span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw2">var</span> c = ca<span class="br0">&#91;</span>i<span class="br0">&#93;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">while</span> <span class="br0">&#40;</span>c.<span class="me1">charAt</span><span class="br0">&#40;</span><span class="nu0">0</span><span class="br0">&#41;</span>==<span class="st0">&#39; &#39;</span><span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; c = c.<span class="me1">substring</span><span class="br0">&#40;</span><span class="nu0">1</span>,c.<span class="me1">length</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>c.<span class="me1">indexOf</span><span class="br0">&#40;</span>nameEQ<span class="br0">&#41;</span> == <span class="nu0">0</span><span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; <span class="kw1">return</span> c.<span class="me1">substring</span><span class="br0">&#40;</span>nameEQ.<span class="me1">length</span>,c.<span class="me1">length</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; <span class="kw1">return</span> <span class="kw2">null</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">session_id = read_cookie<span class="br0">&#40;</span><span class="st0">&#39;PHPSESSID&#39;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1"><span class="co1">// Include session_id in your POST data&#8230;</span></div>
</li>
</ol>
</div>
<p>On line 14, <code>PHPSESSID</code> is the name of the session. It is the default, but if you use a different one, you should keep that in mind. (You can use the <code><a href="http://php.net/manual/en/function.session-name.php">session_name()</a></code> function to find it out.)</p>
<p>This code works because <code>document.cookie</code> is only &#8216;allowed to look at&#8217; cookies that are associated with the current document (so external sites don&#8217;t stand a chance).</p>
<h2>Conclusion</h2>
<p>Cookies are a nice means of keeping sessions going. But when users of your web application perform sensitive tasks, you should not simply rely on a cookie for authentication.<br />
The increasing possibilities of JavaScript can greatly enhance the usability of your application, but it also makes it harder for the browser (but also the developer) to keep things secure. Therefore, make sure sessions are airtight whenever there is interaction between the client and the server.</p>
<p><small>This is my first real article here, so if I forgot to mention basic things or something else, please tell me.</small></p>
]]></content:encoded>
			<wfw:commentRss>http://sparepencil.com/archives/2007/04/15/airtight-sessions/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>
