CodeIgniter XSS Protection is good, but not enough by itself.

I have been looking at CodeIgniter lately mainly because a lot of my colleagues are using it already. As with most frameworks, I usually start using the framework in a project and then as I am developing the application, I notice some issues with the framework. One such case is with CodeIgniter’s built-in XSS protection. This functionality is quite nice (at least they included it in the framework) but there are some issues with using it that developers should be aware of.

Setting it all up

From CodeIgniter’s documentation (see  http://codeigniter.com/user_guide/libraries/input.html)…

CodeIgniter comes with a Cross Site Scripting Hack prevention filter which can either run automatically to filter all POST and COOKIE data that is encountered, or you can run it on a per item basis. By default it does not run globally since it requires a bit of processing overhead, and since you may not need it in all cases.

The XSS filter looks for commonly used techniques to trigger Javascript or other types of code that attempt to hijack cookies or do other malicious things. If anything disallowed is encountered it is rendered safe by converting the data to character entities.

XSS Protection functionality is turned off by default. To turn on this functionality, you simply either set the global configuration (i.e. system/application/config/config.php)…

$config['global_xss_filtering'] = TRUE;

…or, you can do it manually within your controller(s) like so…

$myvar = $this->input->xss_clean($data);

How CodeIgniter’s XSS  Protections Work

Once set up, you can now start to see what happens when you pass parameter values to your application. For example, lets assume we have a controller named HelloWorld which is coded like so…

class HelloWorld  {

public function index()  {

$myvar = $this->input->post(“myvar”);

$this->load->view(“myview”, array(“myvar” => $myvar));

}

}

A simple controller by any taste. So, the view is just as simple…

Hello World.<br />

<?php echo $myvar; ?>

If we supply a post parameter to our call to HelloWorld, the view will output the value we supply it. This is good way to test if the XSS filtering is working.

So, what happens when CodeIgniter knows that the XSS Protections are enabled and receives input from the client/browser? Well, as part of the Controller instantiation, the [CI_]Input class is loaded. The [CI_]Input class will firstly load the config.php file and see what settings need to be set then it will call the _sanitize_globals() private function. This function will setup everything and I will not get too deep into it other than to explain that it sets up the inputs into the application, including $_GET, $_POST, $_SERVER, and $_COOKIE as well as others. For each one of these constructs, it will call _clean_input_data() and xss_clean(). The function xss_clean() has the following code comments…

Sanitizes data so that Cross Site Scripting Hacks can be prevented.  This function does a fair amount of work but it is extremely thorough, designed to prevent even the most obscure XSS attempts.  Nothing is ever 100% foolproof, of course, but I haven’t been able to get anything passed the filter.

How cute. The developer goes on to record that he used the XSS Cheatsheet from ha.ckers.org. It would be nice if they actually read the material rather than simply looked over the various methods to get past various XSS filters listed on the page. Because, in 5mins I was able to get past this filter. I will show you why later.

Ok, to continue … xss_clean() will firstly remove any invisible characters like NULL terminators which could cause HTTP Parameter Pollution and/or HTTP Response Splitting issues. This is a good first step. The function continues on to decode URLencoded values, convert attributes and entities, remove invisible characters (again), and then…the magic. It will look for a standard list of elements, JS DOM Calls, etc. and then replace any found with the string “[removed]“.

The Issue(s)

The problems are: (1) this functionality is not turned on by default and (2) the authors of CodeIgniter decided to use a substitution method without the use of encoding before hand. I will focus on the latter issue here.

The age-old method of substitution to prevent XSS in web applications goes waaaayyyy back. MySpace and Yahoo! both used this methodology to protect their users from XSS attacks as well. The key to the substitution method is to be able to read the input to be able to convert it before outputting. But, like so many, most developers switched to a better method — encode-and-validate instead of find-and-replace.

The reason is simple: for web applications, there are literally a thousand ways to send a single object to the web server. With many, many different character sets (i.e. UTF-7) and encoding methods (i.e. Base64, Rot-13, URLEncoded, HTMLEntities, etc.) available to the user, it is really, really easy for a developer to miss out on one.

CodeIgniter developer(s) thought that by looking for common strings, they could write a XSS filter which replaces those common strings used in attacks to “removed”. Unfortunately, they missed out on Javascript events. So, a value for $myvar of fdsa” onload=”alert(1);” /> is possible to by-pass their protections. Yes, I know — we are not really outputting an image here to really use the onload event, but for all purposes, this should not possible.

Just what is the problem now?

The following results were found while testing various inputs to CodeIgniter (using the HelloWorld controller and view above)…

  • Input: fdsa” onload=”alert(1);” />, Output: fdsa” onload=”alert(1);” />
  • Input: fdsa<script>alert(1)</script>, Output: fdsa[removed]alert(1)[removed]
  • Input: fafa<script src=”http://ha.ckers.org/xss.html”>alert(1)</script>, Output: fdsa[removed]alert(1)[removed]
  • Input: fdsa<img src=”…” onload=”alert(1);” />, Output: fdsa<img  />

So, from the above tests, we can see that (1) CodeIgniter misses Javascript events when not within a HTML tag, (2) does not always strip the actual Javascript code, and (3) it only strips the attributes from normal HTML tags (i.e. IMG) it finds.

This means that the developer using CodeIgniter needs to remember these limitations or they can lead to a security issue. For example, if your view was to output an IMG tag or something based on the user’s input, you may introduce a XSS vuln to your application if you do not perform some additional encoding (and preferable validation as well).

What You Should Remember if Using CodeIgniter

You should always: (1) ENCODE and then (2) VALIDATE your inputs. Encoding can be done using the combination of the XSS protections already in CodeIgniter, but you should also use something like urlencode() or htmlentities() just to make sure. So, we can change our example HelloWorld controller to do just that…

class HelloWorld  {

public function index()  {

$myvar = urlencode($this->input->post(“myvar”));

$this->load->view(“myview”, array(“myvar” => $myvar));

}

}

By using encoding on top of the XSS protections within CodeIgniter, you can protect yourself against any limitations that CodeIgniter may have. You should additionally validate any data by data-typing (if possible) or if using strings, use a dictionary-lookup or a regular-expression check.