0

xss.php

<?php
header('Content-Type:text/html; charset=UTF-8');

var_dump(ini_get('filter.default'));

if (isset($_GET['name'])) {
    echo $_GET['name'];
    exit();
}

browsing http://localhost/xss.php?name=%3Cscript%3Ealert('XSS')%3C/script%3E

output:

string(10) "unsafe_raw"

I was under impression that this would be safe against XSS vulnerabilities because of filter extension, but it is not! It outputs a javascript alert dialog. My questions are:

  • Why is the default filter unsafe_raw. I read that unsafe_raw does not protect against XSS?
  • How can I protect PHP against this vulnerability. I could modify my php.ini, but I would like to do it with at runtime but ini_set, .htaccess aren't working by default on my Ubuntu box. I want to have it affect at runtime so that all php instances(when deployed on other machines) are safe. Is that possible, or do I really need to sprinkle my code with filter_input(INPUT_GET, 'search', FILTER_SANITIZE_SPECIAL_CHARS); to make it safe.

P.S: This code is safe and also not looking that bad, but if I could set it up on runtime it would be nicer.

<?php
header('Content-Type:text/html; charset=UTF-8');

$_GET = filter_input_array(INPUT_GET, FILTER_SANITIZE_STRING);
if (isset($_GET['name'])) {
    echo $_GET['name'];
    exit();
}
Alfred
  • 60,935
  • 33
  • 147
  • 186

1 Answers1

2

The filter extension does not protect against XSS input strings. Most of the filter functions do some limited sanitizing based on character sets. Some like _VALIDATE_EMAIL and _VALIDATE_URL just verify a format according to regular expressions (mostly).

Even w3fools says:

The FILTER_UNSAFE_RAW filter does nothing, or encodes and strips specified characters.

You need to use it in combination with a _FLAG_STRIP_* or _FLAG_ENCODE_* option to make it useful.

And regarding FILTER_SANITIZE_SPECIAL_CHARS you are mostly better off just using htmlspecialchars().

Why is the default filter unsafe_raw.

To not screw up the behaviour existing scripts, the default filter settings are intended to do nothing.

How can I protect PHP against this vulnerability. I could modify my php.ini, but I would like to do it with at runtime but ini_set, ...

Write a short wrapper function for htmlspecialchars(), and apply it to all output you make - regardless of where the input came from.

Setting a default filter function via ini_set() is not possible AFAIK, because the filter operates basically like magic_quotes. It's just invoked once on all input data when PHP starts up. Calling ini_set has no effect on the existing input arrays.

mario
  • 144,265
  • 20
  • 237
  • 291
  • You should read this blog entry from Rasmus => http://toys.lerdorf.com/archives/38-The-no-framework-PHP-MVC-framework.html. He says he does not sprinkle his code with it, but uses pecl extension, filter_raw_string is safe! You don't need htmlspecialchars() anymore .... – Alfred Jan 26 '11 at 21:37
  • @Alfred: I've read a better explanation from him once, can't find it right now. But he certainly doesn't use *just* `_raw_string`. He has a configuration that amounts to `$_REQUEST = array_map_rec("htmlspecialc",...)` – mario Jan 26 '11 at 21:42
  • @Alfred I think it might have been in comments (somehwere else). But anyway, you can just use `sanitize_string` and `_FLAG_STRIP_LOW | _FLAG_ENCODE_HIGH | _FLAG_ENCODE_AMP`. Use `_special_chars` if you only want encoding and no tag stripping. But take care that both are designed for Latin-1, not UTF-8. – mario Jan 26 '11 at 21:55
  • 1
    If you want something more fancy, try http://sourceforge.net/p/php7framework/wiki/input/ – mario Jan 26 '11 at 21:55
  • I updated my code to make it safe. And it looks also pretty clean. But I want to use FILTER_SANITIZE_STRING as default to make code safer. P.S: nice library thanks :). I really appreciate your help, but I hope somebody has even a better answer. If not then I will accept your answer. – Alfred Jan 26 '11 at 21:59
  • 1
    @Alfred: Looks very okay, but don't forget to add some flags. Btw, you could just overwrite `$_GET` directly instead of using a secondary array. That would be more equivalent to a php.ini override. -- But wait for some other people to chime in, there were some good discussions on SO about this before. http://stackoverflow.com/questions/129677/whats-the-best-method-for-sanitizing-user-input-with-php or http://stackoverflow.com/questions/71328/what-are-the-best-practices-for-avoid-xss-attacks-in-a-php-site - though neither answers your specific question. – mario Jan 26 '11 at 22:20
  • add some flags? The point about overriding $_GET is a very good one. Why did I not think of that myself ;). – Alfred Jan 26 '11 at 22:32