September 2006

You are currently browsing the monthly archive for September 2006.

This follows up from my previous entry where I found a very easy way to set HttpOnly cookies for Internet Explorer 6 (SP1+) without requiring PHP 5.2 or hand-rolling set-cookie routines.

Due to reasons too long to explain here Firefox doesn’t have support for these cookies yet. However, there is a Firefox (well, Gecko) only solution.

The solution requires you to add this simple line of javascript as near to the top of your document as you can.

HTMLDocument.prototype.__defineGetter__("cookie",function (){return null;});

This overwrites the default cookie “getter” function and simply returns “null” when document.cookie is requested.

Unfortunately, it suffers from two major problems.

Firstly, it prevents any cookies from being read by javascript. This is a problem if you have javascript set and get cookies on the fly for dynamic web applications (read Web 2.0). and more fatally it can be undone simply by using:

delete HTMLDocument.prototype.cookie.

For example, if you managed to craft a link like so:

<a href='javascript:alert(document.cookie)'>Click me!</a>

Then you’d get an alert box with “null” thanks to the overridden cookie getter - however, crafting this link:

<a href='javascript:delete HTMLDocument.prototype.cookie; alert(document.cookie)'>Click me!</a>

Then you’d get access to the document.cookie as we’ve just deleted our custom getter.

The first problem is quite easy to overcome. You can set up an array of cookies that you want to ‘hide’ then parse up document.cookie storing the cookie values into an array and simply return the value of the array key when you would otherwise request a cookie.

The second problem is a little more difficult. After toying with it for a little while, I took a rather crude approach. I simply add an onload function that examines the document’s innerHTML and just replace “HTMLDocument.prototype” with a safer version (note, you can’t convert to hex or ascii entities as Firefox runs it just the same). There are two cavaets however.

Firstly, this will only stop “passive” attacks - that is scripting in URLs and images. It won’t stop a <script>..&lt/script> block of code as the script code is executed before the onload function is called. Secondly, as the document’s innerHTML is replaced, all subsequent javascript on the page will stop working. I don’t consider that a major stumbling block as there aren’t many legitimate cases where you’d want someone to post “HTMLDocument.prototype”. If it is a problem, then I suggest you add a line of code in your PHP script to convert this string into something safer before javascript has a chance to see it.

Of course, this isn’t an excuse to stop checking for javascript in URLs and images - but it does provide another barrier a determined hacker must overcome before accessing your cookie information. It’s also not fool proof. There are hundreds of ways to obfuscate javascript code and it’s almost impossible to catch them all. Hopefully when Firefox 2 is out of BETA it’ll support HttpOnly cookies and deprecate this rather crude solution.

Here’s the complete code.

var ignore_cookies = new Array( ’session_id’, ‘password’, ‘member_id’ );
var COOKIES = new Array();
var uagent = navigator.userAgent.toLowerCase();
var is_moz = ( navigator.product == ‘Gecko’ );
var _tmp = document.cookie.split(’;');

if ( _tmp.length )
{
for( i = 0 ; i < _tmp.length ; i++ )
{
var _data = _tmp[i].split('=');
var _key = php_trim( _data[0] );
var _value = unescape( php_trim( _data[1] ) );

if ( _key && ( ! php_in_array( _key, ignore_cookies ) ) )
{
COOKIES[ _key ] = _value;
}
}
}

_tmp = null;

if ( is_moz )
{
HTMLDocument.prototype.__defineGetter__( "cookie", function () { return null; } );

window.addEventListener( 'load', function() {
var _a = document.body;
var _x = _a.innerHTML;
var _y = new RegExp( "HTMLDocument\.prototype", 'ig' );

if ( _x.match( _y ) )
{
_x = _x.replace( _y, 'HTMLDocument_prototype' );
_a.innerHTML = _x;
}
}, false );
}

/**
* Emulate PHPs trim function
*/
function php_trim( text )
{
text = text.replace(/^\s+/, '');
return text.replace(/\s+$/, '');
};

/**
* Emulate PHPs in_array function
*/
function php_in_array( needle, haystack )
{
if ( ! haystack.length )
{
return false;
}

for ( var i = 0 ; i < haystack.length ; i++)
{
if ( haystack[i] === needle )
{
return true;
}
}

return false;
};

function get_cookie( name )
{
return COOKIES[ name ];
}

For a while, Microsoft have had a flag for cookies called ‘httponly’. This doesn’t sound particularly exciting, but it is a vital step forward for web application security.

This flag tells Internet Explorer to make this cookie ‘invisible’ to javascript (and other scripting languages) which means that an XSS attack will no longer be able to steal your sensitive cookies.

The problem is that ‘http only’ support has only just been added into PHP 5.2. This makes this feature unavailable to most webservers.

However, there appears to be a way to force this flag to be written regardless of your PHP version by simply adding “; HttpOnly” at the end of the domain name when setting the cookie. PHP’s “setcookie” function merely formats the data into a “set-cookie” header. Fortunately, PHP doesn’t appear to filter out or escape the semi-colon so it’s added to the end of the “set-cookie” request.

if ( PHP_VERSION < 5.2 )
{
  @setcookie( $name, $value, $expires, $path, $domain. '; HttpOnly' );
}
else
{
  @setcookie( $name, $value, $expires, $path, $domain, NULL, TRUE );
}

I’ve tested this out and it appears to work fine. IE7 shows the “sensitive” cookie data in the document.cookie string without adding the flag. Adding the flag onto the domain string causes the sensitive cookies to disappear from the document.cookie string.

Firefox ignores it and sets cookies as does Safari and Opera. I’ll do some more testing and report in on my findings. I also have a Firefox friendly version to stop access to the document.cookie which I’ll post up tomorrow.

UPDATE 14th September
I’ve downloaded the source to PHP 5 to make confirm that this ‘hack’ will work across different platforms. The source code confirms that no cleaning takes place on the domain name attribute (or indeed any other than the cookie name and value).

These snippets are from the head.c document, function php_set_cookie:

if (name && strpbrk(name, "=,; \t\r\n\013\014") != NULL) { /* man isspace for \013 and \014 */
zend_error( E_WARNING, "Cookie names can not contain any of the folllowing '=,; \t\r\n\013\014' (%s)", name );
return FAILURE;
}

if (!url_encode && value && strpbrk(value, ",; \t\r\n\013\014") != NULL) { /* man isspace for \013 and \014 */
zend_error( E_WARNING, "Cookie values can not contain any of the folllowing ',; \t\r\n\013\014' (%s)", value );
return FAILURE;
}

That shows the check for the key and value:


if (path && path_len > 0) {
strcat(cookie, "; path=");
strcat(cookie, path);
}
if (domain && domain_len > 0) {
strcat(cookie, "; domain=");
strcat(cookie, domain);
}

That shows that no cleaning takes place and this ‘hack’ will execute perfectly.

It’s been a while since I’ve talked about Invision Power Board 2.2 so I figured it was time for an update.

First off, there’s a fairly sizeable new feature that we’re really pleased with. I’m not going to say what it is or post cool screen-shots because we want to keep this underwraps until we’re ready for the first public beta. We don’t mind sharing our forthcoming features but we don’t want to see this one appearing anywhere else first as I’m fairly confident that our competition will adopt this new feature for their own products.

IPB is currently undergoing a security audit to ensure that our new security features make the grade and the base code is solid. It’s progressing well and although no specific vulnerabilities have been discovered we’ve had some good advise on ‘hardening’ the code in several specific areas which we’ve taken onboard and tweaked the code to suit. The new ‘parse_incoming’ function will greatly reduce the threat of any file traversal issues and stop any possible preg_replace PHP code injections (especially when using preg_replace’s “eval” mode).

Finally, there have been some template tweaks here and there to improve the layout and functionality. There’s nothing too dramatic and as usual we’ll be providing a diff report for upgraders so they can manually update their custom skins if they wish.

Although we don’t have a firm estimate for our first public beta, it shouldn’t be *that* far off…

IP.Dynamic: Calendar

I hate writing calendars.

I suck at maths. For a programming nerd, that’s unsual - but it’s true. Even after a month of intense DS Lite Brain Training, I still can’t work out how much change I’m supposed to have at the till. Mainly because I use a visa card, but I digress.

Calendars suck because you have to take into account different timezones when storing the event and when showing the event. Stick on some daylight saving time variances and it’s enough to push me over the edge.

Not being satisfied by getting whipped by basic mathematics that my six year old nephew could do with both hands behind his back, I went and threw some javascript into the mix to ensure the last remaining clumps of hair I have were majestically pulled from my scalp.

Now I know there’s some fancy AJAX calendars out there. Google’s calendar app and 30boxes are both good examples of what can be done with enough time and enough programmers. I didn’t really want to compete with those programs because basically, I don’t have the time.

Here’s a quick look at the interface thus far. (Quicktime .mov, 1.1mb)

My last few blog entries have been about the iPod+Nike kit for the iPod.

I’ve completed my first 5mile run using my temporary shoe ‘hack’ to secure the sensor between the shoe tongue and the laces. I’ve uploaded my data to the nikeplus website and that’s when I experienced the first real disappointment with this product.

The Nikeplus website is a bit of a let down. It looks pretty enough as it’s all Flash driven but it lacking in several other areas. Firstly, there’s no sense of community. You can look up the ‘leader-boards’ for those who’ve run the furthest, those who’ve run for the longest and those who’ve turned in quick times for 5k and 10k runs - but that’s about it. You can’t browse their stats or their run histories to see how they’ve improved. I can appreciate that some runners will want to keep their data private but an opt-in setting to “share my stats with the community” would be a welcome improvement.

Click for a larger version

Worse yet; I can’t share my data with anyone. I was going to link up to my stats so you can browse my data and get a feel for the system but I can’t even do that — unless I gave out my log in information. In this age of community focused web-applications it feels like a bit of a step back.

This got me thinking: surely there’s a way to extract the run data from one’s iPod in it’s raw format. Apple are fond of using either XML or SQLite to store data locally so reading the data wouldn’t be a problem. I ran (pun intended) a few spotlight searches to see if the data is cached on my harddrive. It’s not. Hmmm.

I plugged back in my iPod Nano and enabled ‘Disk Mode’ and double clicked the icon. In typical Apple fashion, anything remotely scary is hidden. So, it’s over to terminal.
After a bit of digging around, I located the data. It’s stored in XML format (no surprise there) and is found in: iPod/iPod_Control/Device/Trainer/Workouts/Empeds/{Sensor ID}.
My sensor ID is ‘4H627YP2VSX’. This sensor ID is also located in a file called ‘linkData’ in the Emped folder. I copied the folder to my desktop so I could poke around without risking the data on my iPod.

As the data is in XML format, it makes for easy reading. The first part holds some interesting data:

<runSummary>
<workoutName>Basic</workoutName>
<time>2006-09-05T12:53:57+01:00</time>
<duration>3538875</duration>
<durationString>58:58</durationString>
<distance unit=”km”>8.0492</distance>
<distanceString>5.00 mi</distanceString>
<pace>11:47 min/mi</pace>
<calories>752</calories>
<battery></battery>
<playlistList>
<playlist>
<playlistName>a.Current</playlistName>
</playlist>
</playlistList>
<stepCounts>
<walkBegin>4490</walkBegin>
<walkEnd>9130</walkEnd>
<runBegin>3600</runBegin>
<runEnd>7666</runEnd>
</stepCounts>
</runSummary>

The most curious is the “stepCounts”. This data doesn’t appear to be used by the system currently and it’s unclear how it calculates “walkBegin” and “runBegin”.
Further down the file we get the KM and mile splits.

<startTime>2006-09-05T12:53:57+01:00</startTime>
<snapShotList snapShotType=”kmSplit”>
<snapShot><duration>435715</duration>
<distance>1.002</distance>
</snapShot>
<snapShot><duration>848088</duration>
<distance>2.0</distance>
</snapShot>
<snapShot><duration>1258480</duration>
<distance>3.001</distance>
</snapShot>
<snapShot><duration>1708667</duration>
<distance>4.002</distance>
</snapShot>
<snapShot><duration>2149958</duration>
<distance>5.003</distance>
</snapShot>
<snapShot><duration>2593229</duration>
<distance>6.003</distance>
</snapShot>
<snapShot><duration>3060237</duration>
<distance>7.002</distance>
</snapShot>
<snapShot><duration>3517397</duration>
<distance>8.0</distance>
</snapShot>
</snapShotList>

Right at the bottom is the extended data which must be used to fill the ‘curve’ shown when you’ve uploaded your data and when you view previous runs.

The most exciting prospect is writing a little application that can take this data from your iPod and upload it to another website where it’s stored, consumed and written out without a ton of flash. One could then invite others to download the application and upload their stats and create a ‘real’ community site where runners could browse other’s stats and share their own.

Hmmm….

Update 6th September
I’ve written a dashboard widget that uses the widget.system() functionality in javascript to call a perl script which locates the iPod, iPod serial number and training data. It then POSTs this to a PHP file sitting on this server which simply writes the data to a temporary file.

It’s ugly, but it works

I’m using the ‘lastWorkout.xml file as my test subject. It works well. I can now add a username and password field in the widget and write a basic log in handler and we have the beginnings of our community of runners. The next step is to store the last sync date and upload the real XML files as attachments for storing in a database.

I had previously blogged about the ipod+nike kit which comprises of a sensor for your running shoes and a little unit that “docks” onto the iPod nano.

As I mentioned in that other blog entry, you need to purchase Nike’s running shoes that have a cut-out for the sensor. Most runners have chosen shoes that work for them and won’t want to part with them which is where Podophile stepped in and came up with the sensor hack to fix the sensor to the shoe’s tongue.

Today I took delivery of the iPod nano, ipod+Nike sensor and iPod unit and a new wrist strap and I was itching for a go on the treadmill.

The Podophile website makes it very clear that laces alone will not keep the sensor inplace for very long and I found this to be true. I didn’t have any velcro handy so I couldn’t ‘hack’ my trainers as per the Podophile instructions. I gave it a go anyway.

I walked the first quarter of a mile to see how accurate the sensor was. The treadmill completed a lap (0.25 miles) and my iPod reported 0.25 miles which is absolutely spot on. A quick run for another 0.25 miles at 7.5mph at a 2% elevation caused the sensor to slip a little inside my shoe. After 0.50 miles my iPod reported 0.49 miles - which is very good considering the sensor slipped.

A stopped to re-adjust the sensor which took a few minutes. A few miles further into my run the sensor popped out and bounced from the treadmill deck onto the tiled floor.

I rummaged through a few drawers and located some low-tack masking tape. I used that to secure the sensor in place (see the image below). Even though the low-tack tape didn’t adhere well to the shoes (especially as I was dripping sweat on them when I was trying to tape them up) it kept the sensor in place for the rest of my run (another 3 miles or so). It appeared that the laces has a greater surface area to grip which did a good job of keeping the sensor in place.

Now, I did spend the rest of my run stopping now and again for a second to make sure the sensor wasn’t going to make another journey across the room which kept breaking my concentration. I knew I had to find a more secure way to keep the sensor in my shoe. The tape did its job but it’s obvious that a few more miles and the sensor would have come unstuck again.

I had a few ideas - from taping it down with duck tape to using a large plaster strip to secure it in place and ended up using a spare heart rate monitor pad. I have a Slendertone belt that is designed to be used while out running and it has a separate heart rate belt for your chest. The pads are extremely sticky and the replacement pad set that I buy has two skin pads designed for the lady’s version of the heart rate monitor. These are the perfect size for securing the sensor to my shoe.

The pads are designed to be stuck to your skin so I was confident that it wouldn’t damage the sensor and they adhered nicely to the shoe tongue. The laces cross over snugly and have more surface area to grip. I had another quick test to make sure it would suffice and so far, it’s doing the job well.

I have also ordered a Nike running wallet as a more permanent solution but I’m hoping that my makeshift ‘hack’ will keep me going until it arrives.

About Me

Me
I'm a web developer (PHP / MySQL / DOM) based in the UK. I am the co-founder and C.S.A of Invision Power Services, Inc.

Last.fm Chart

XBox Live

Spam Monitor