Snippets Of Defense Pt.III

Sat, 20 Oct 2007 08:47:10 GMT
by mario-heiderich

This article is part of a series of posts about small and easy to understand code fragments you can use on your site for protection against certain kinds of attacks. Also this series is targeted to help you understand better what tricks are used by attackers to break into your site and how to avert them. If you have a Snippet of defense yourself and you want to share it, feel free to contact us. Self-defense with a Walking-stick.

The snippet - sanitize your input recursively

This time we are going to show a PHP snippet which you can use to filter your input recursively - working for PHP4 and PHP5 and being pretty copy&paste ready. Furthermore, the snippet shows how you can defeat XSS on your application without being too aggressive and not forbidding the user to use certain characters. Several large applications use this method or similar ones - although, of course, it is not suitable for all platform out there.

You can use this snippet to secure existing applications by embedding it via auto_prepend_file or using it at a centralized position in your application's index.php. It doesn't rely on any external software or extensions so it should be running fine on most PHP environments without any problems. And of course don't use it sightlessly - but that goes for all snippets of this series.

<?php
    /**
     * Initial filter method
     *
     * @param array $to_filter
     * @return array
     */
    function filter($to_filter) {
        if (!empty($to_filter)) {
            foreach ($to_filter as $key => $value) {
                $filtered[$key] = iterate($key, $value);
            }
        }
        return $filtered;
    }

    /**
     * Iterates recursively of the array to 
     * be filtered
     *
     * @param string $key
     * @param string $value
     * @return mixed
     */
    function iterate($key, $value) {
        if (!is_array($value)) {
            if (is_string($value)) {
                $filtered[$key] = sanitize($value);    
            }
        } else {
            foreach ($value as $subKey => $subValue) {
                $filtered[$key][$subKey] = sanitize($subValue);
            }
        }
        return $filtered[$key];
    }

    /**
     * The sanitization method
     *
     * @param string $string
     * @return string
     */
    function sanitize($string) {

        $search = array('"', "'");
        $replace = array('"', '''); // &rdquo; and &rsquo; are used here

        /**
         * Remind that the replacement is just one way of many.
         * You can also use html_special_chars() or htmlentities() - but 
         * don't forget the third parameter :)
         */
        return strip_tags(str_replace($search, $replace, $string)
    }

    /**
     * overwrite the original request array with the filtered one
     */
    $_REQUEST = filter($_REQUEST);
?>

We hope that you enjoy the trick - please tell us what you think. Till the next time.

Archived Comments

NIXNIX
thats a good one ;) thanks
Sirw2pSirw2p
Good code, but there are easier ways to filter and prevent xss attacks.
kuza55kuza55
You're missing the end of a line:
return strip_tags(str_replace($search, $replace, $string)
should be
return strip_tags(str_replace($search, $replace, $string));
Furthermore editing $_REQUEST does not change the values in $_GET, $_POST, $_COOKIE, etc. SO you would need to do this to every array you want to sanitize, and then reconstruct $_REQUEST from your already filtered initial arrays. This is purely IMO, but $_REQUEST seems like a bad idea, since you don't know where the stuff your working with came from, especially considering it relies on the variables_order directive. Anyway, this seems pretty much identical to magic_quotes so I'm not going to bother criticising it since the arguments for/against magic_quotes have been rehashed enough times already.
.mario.mario
Hi! Thanks for the comments. Kuza55 you are right - $_REQUEST _can_ be problematic in some setups but this is example is more to show on how you can build an easy to extend first solution to cope with global input filtering - which I really rarely come to see during work. It of course no 'use it and be happy forever' solution but a snippet to point into a certain direction. Greetings, .mario
DavidDavid
Not really recursive (function doesn't call itself, just goes 1 level into an array). Seems you can reduce the whole thing to 1 function by using actual recursion:
 $var) {
				$safe_html[$key]=recurs_escape_html($var);
			}
		} else {
			return htmlentities($data, ENT_QUOTES, 'ISO-8859-1');
		}
		return $safe_html;
	}
?>
digi7al64digi7al64
I been using a similar method to the one you presented here for a while now but there are a few different things in mine that perhaps could be blended into yours to make it safer. I.E
> I use the iconv function to force an encoding set on the supplied data > I loop through each $_POST and $_GET and set the values that way (as kuza55 suggested [cookie not included as this is only an idea to get you going])
Finally, there is a small bug in my code (intentional for this post) so post back if you can find how to make it throw an error, should be easy :) oh and as a final thought, generally you might want to trim the string straight up to a fixed length you know you can handle it with whatever you want to do.
$value){
			$_POST[$name] = santize($value);
		}
	}
	
	// Clean any supplied get values
	if(isset($_GET)) {
		foreach($_GET as $name => $value){
			$_GET[$name] = santize($value);
		}
	}
?>
digi7al64digi7al64
it seems this blog removed half of my code. therefore don't worry about approving my post, please delete it. i don't intend to repost
pdppdp
digi7al64, wordpress will try to prevent you from posting anything that looks like HTML. Just make sure that all your < are replaced &lt; and > is replaced with &gt; :) cheers
WadeWade
mario. sorry for rehashing this again, but I don't want to see anyone using this code thinking that it's going to save them against XSS. As previously mentioned by kuza55 and digi7al64, $_GET and $_POST values (which would typically used by developers) are not being affected by the sanitation script. For this to be more "copy and paste" friendly, you might want to initialize the whole thing by using:
$_GET = filter($_GET);
$_POST = filter($_POST);
$_COOKIE = filter($_COOKIE);
ReZENReZEN
.mario: Wow this is hilarious. Kids and their games. Next time you want to post pure crap just through up a link to rotten.com or ogrish or something and quit wasting everyones time with your absolute shit code. Have you done NO research on this subject at all? And if you had THIS IS WHAT YOU CAME UP WITH?
pdppdp
ReZEN, if you don't like it, please don't read it. All .mario did is to show a kind of code which may fit into some scenarios. We all know that there are no bulletproof solutions.
Mario HeiderichMario Heiderich
Hey ReZEN - click that, junior! http://tinyurl.com/2h3ps6 You should have read my post ;)
Raaka!Raaka!
LOL =)) where is reZen now :p thanks for the code