Content Security Policy update

A quick update about CSP. Browsers are well on their way to all adopt the specification.

An early draft was already adopted by Firefox 4, and I just found out that it's also working in Chrome, Safari and IE 10.

IE10 and FF are using the following header:

  1. X-Content-Security-Policy: default-src 'self'

While Safari and Chrome use:

  1. X-Webkit-CSP: default-src 'self'

When the specification is finalized, the X- will be dropped, and it will simply be 'Content-Security-Policy'.

A call for support

Hi Developers! Start implementing this feature! It's important for the future and security of the web. The web's biggest vulnerability, from what I understand, is still XSS, but if people start to properly implement CSP, XSS can effectively be a thing from the past.

So even if you don't want to risk using CSP on a production environment, at least consider adding the headers in your development environment. It will force you to write better code, by not embedding javascript directly into the HTML source. By considering this right now, you will also make it much easier if you do decide to adopt CSP at some point in the future.

I'm implementing CSP full-on in a new project, and one of the things I've noticed already is that some of the javascript we embed from 3rd parties use eval() and inline html events (onclick & friends). For the sake of security we will most likely decide to only use 3rd party code if they are indeed CSP-compatible.

Mozilla Documentation Center

In case you're still using w3schools are a reference (which according to some is harmful to the web), a few new references have recently popped up from the browser vendors.

Mozilla Document Center is by a stretch my favourite. It's a rapidly growing wiki-based documentation and more often than not it will have what you need. The HTML, CSS and Javascript documentation is really excellent, and going there directly often beats googling.

My gripe with Prototype

Many of you might already know this, but I wanted to point out why I think using the Prototype Javascript library is a bad idea. The biggest problem is actually highlighted in it's name: it changes many of the prototypes of core javascript types.

You might have realized this before, when you tried to 'for(i in arr)' and came across many of the extra functions prototype added. (and you should have realized at this point this wasn't the proper way to loop through an array anyway.).

This is a big difference with other established libraries such as jQuery. If you want to use any of the jQuery functionality, you're expected to wrap other types in a jQuery object, for example:

  1. var myElem = $(myDomNode);

This augments the underlying variable with jQuery functionality. Besides the '$' (which can be turned off), jQuery pretty much keeps it's hands off your global namespace

Same with YUI. All the functionality is imported through the YUI object:

  1. YUI().use('node-base', function(Y) {
  2.  
  3. Y.on("domready", function() { console.log('ready!'); });
  4.  
  5. });

This is a stark contrast with Prototype. As soon as you include it, it changes basic types such as strings, arrays and numbers. An example:

  1. alert( [1, 2, 3].toJSON() ); // outputs "[1, 2, 3]"

While from an API perspective, this seems quite nice and by far the simplest. Prototype provides these handy methods close to where you need them.

This has one devastating effect though. It violates the holy "don't pollute the global namespace" rule. In an isolated environment this will work fine, but as soon as you work on an application that includes scripts from different sources or libraries these scripts are now also affected by prototypes changes to core types. In a "mash-up era" it's just not feasible to assume you'll be working in an isolated, sterile environment forever.

My latest example of having to hunt down what prototype feature caused a stir, was when I tried to use the JSON.stringify function. This is a fairly new feature, added by all the modern browsers.

Whenever stringify comes across an object that has a toJSON() method, it will call it. This allows objects to specify their own 'json representation' to for example filter out 'private properties'.

Example:

  1. var test = {
  2.  
  3. prop1: 'val1',
  4.  
  5. privateProp: 'hidden',
  6.  
  7. toJSON : function() {
  8.  
  9. return { prop1: this.prop1 };
  10.  
  11. }
  12. }
  13. alert(JSON.stringify(test));

The output of this last example will be :

  1. {"prop1":"val1"}

I would argue that this functionality is not a great design decision (separation of concerns!). However, it's there and it's standard. Prototype however, adds a toJSON() method to every Array, Object and String. In Prototype this has a different meaning though. The prototype methods actually json-encode themselves and return a string.

From an API perspective this is as bad as a choice as JSON.stringify defining toJSON(). And this problem highlights exactly why it's a bad idea, as these 2 libraries both define a global toJSON, and add their own meaning to it.

Example of how this fails:

  1. JSON.stringify({
  2. prop : [1, 2, 3, 4]
  3. });

The normal result:

  1. {"prop":[1,2,3,4]}

The result with prototype:

  1. {"prop":"[1, 2, 3, 4]"}

The easy fix is to simply get rid of toJSON functions as such:

  1. delete Object.prototype.toJSON;
  2. delete Array.prototype.toJSON;
  3. delete Hash.prototype.toJSON;
  4. delete String.prototype.toJSON;

There's even a comment on stackoverflow that fixes the issue and keeps Prototype's methods intact, but I know that as long as I will maintain applications that use Prototype, I'll have to deal with API collisions and incompatibilities.

Therefore, Prototype will never be the choice of JS library for me.

javascript's escape and encodeURI vs. PHP $_POST

I just stumbled upon an odd encoding issue with a web application.

Basically, data is coming into our PHP application through a Javascript's XMLHttpRequest (ajax). The data is sent as a standard form encoding (application/x-www-form-urlencoded), and picked up by PHP using the $_POST array. Any strings in form POST request are 'urlencoded', also known as Percent-encoding. As an example, this will turn a space into the often-seen %20.

Normally everything in the $_POST and $_GET arrays is already decoded, so when you're dealing with these arrays you don't really have to think about this. This time however, I was dealing with some non-latin unicode characters and for some reason they were never decoded and ended up in de database as raw url-encoded strings.

Doing a bit of research led me to the following: normally any special character is encoded as %XX, X and X being 2 hexadecimal values. These values simply represent bytes. The values I got were different altogether and took the form %uXXXX. I just assumed this was part of standard uri-encoding for unicode characters, so I was still a bit shook-up to see that PHP didn't just pick them up.

After a bit of research, I found out that the unicode representation was rejected by W3c, which is probably also why the PHP authors decided to not implement this. Javascript actually has 2 different methods to do percent-encoding, namely:

escape("☢"); // returns %u2622
encodeURI("☢"); // returns %E2%98%A2

Guess which one we were using?

Even though the %u syntax is arguably better to represent unicode characters, W3c seems to have voted against the syntax for backwards compatibility reasons. Before this happened the escape method was already adopted in javascript which in turn caused me to stumble upon this problem and write an article about it.

The more you know..

Game of life with checkboxes

I needed to kill a little bit of time, so I decided to write Conway's Game of Life in HTML.

Try it!

Preventing XSS in Javascript strings

Escaping user-input in your HTML is essential for preventing worlds #1 vulnerability.

When you're embedding user input into javascript, a simple htmlspecialchars won't cut it, you'll need to make sure you're escaping other things, like \n (line endings), and \ (slashes). Google doctype has a good list of characters in need of proper escaping to prevent users breaking your javascript.

However, when I dropped the question if a simple string replacement would be good enough, the members of the Web security mailing list gave me a different answer.

When escaping or filtering output using a blacklist (such as the one published on google doctype) browser/unicode escaping bugs are not taking into consideration. Some new vulnerability might appear in the future, which would immediately open a hole in your app. For this reason its wiser to go with a much more defensive white-list approach, essentially only letting things through you know is safe.

Introducing Reform

Reform is a tool that does exactly this. Reform allows you to escape your data for a javascript, xml, html or vbscript (yes it still exists) context. It provides libraries for Java, .NET, PHP, Perl, Python, Javascript and ASP. Pretty cool!

One dislike I have is that it only considers I really small set of unicode codepoints safe, especially when dealing with non-latin languages this is going to add a great deal to the bandwidth usage and the legibility of your sourcecode. One would think there has to be more ranges considered 'safe'.

PHP example:

  1. <?php
  2. // Assuming the Reform class is included..
  3.  
  4. echo '<script type="text/javascript"> var myString = ', Reform::JsString($userInput), '; </script>';
  5.  
  6. ?>

I made a couple of changes in the PHP version, specifically:

  • Prepended the 'static' keyword to every method to make it work in PHP5's strict mode.
  • Removed the UTF-8 checks, I'm in a controlled environment, mbstring is installed, and the internal encoding is utf-8.
  • Added a parameter to Reform::JsString to not automatically put the string between quotes (').
 1

About

My name is Evert, and I've been writing semi-regularly on this blog since 2006.

I'm currently available for contract work.

more info.

Subscribe

Dropbox

Dropbox is a simple cross-platform online backup and sync application. The first 2GB of space is free, and both you and me get an extra 250MB extra space if you sign up through this link.