Created
July 15, 2012 23:21
-
-
Save chrisallenlane/3119140 to your computer and use it in GitHub Desktop.
A Heavy-handed Approach to Sanitization in PHP
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Chris Allen Lane | |
* chris@chris-allen-lane.com | |
* twitter.com/chrisallenlane | |
* | |
* This gist is a snippet of companion code for the blog article posted here: | |
* http://chris-allen-lane.com/2012/05/a-heavy-handed-approach-to-sanitization-in-php/ | |
*/ | |
/* | |
* @note: You MUST provide valid connection strings here (to some database | |
* on your local machine), or otherwise mysql_real_escape_string will | |
* fail on line 71; | |
*/ | |
$db = mysql_connect('localhost', 'root', 'root'); | |
/********************************************************************* | |
* First, define our Security class | |
*********************************************************************/ | |
/** | |
* This class encapuslates the security-related functionality. | |
*/ | |
abstract class Security{ | |
/** | |
* Returns a PHP code snippet to be passed to eval() which will | |
* obliterate all tainted variables within a function's scope. | |
* | |
* This unusual mechanic is a clever way of avoiding issues which | |
* would otherwise be encountered regarding function scope. By | |
* eval()'ing this code within the function body, it is given direct | |
* access to the variables which reside within the function's scope. | |
* | |
* @example: | |
* eval(Security::cleanAllParams()); | |
*/ | |
static function cleanAllParams(){ | |
$code =<<<CDE | |
foreach(get_defined_vars() as \$key => \$val){ | |
$\$key = Security::clean(\$val); | |
} | |
CDE; | |
return $code; | |
} | |
/** | |
* HTML encodes entities to protect against XSS attacks | |
* | |
* @param mixed $input A string or array of strings to be sanitized | |
* @return mixed $clean A sanitized string or array of strings | |
*/ | |
static function clean($input){ | |
# is true, false, or null | |
if($input === true || $input === false || $input === null){ | |
return $input; | |
} | |
# is array | |
if(is_array($input)){ | |
foreach($input as $key => $val){ | |
# sanitize both the keys and the values for good measure | |
$clean_key = self::clean($key); | |
$input[$clean_key] = self::clean($val); | |
} | |
} | |
# is scalar | |
else { | |
$input = mysql_real_escape_string(htmlspecialchars(trim($input), ENT_QUOTES, 'ISO-8859-1', false)); | |
} | |
return $input; | |
} | |
} | |
/********************************************************************* | |
* Second, craft a few malicious payloads | |
*********************************************************************/ | |
$payloads = array( | |
'xss' => array( | |
"<script>alert('XSS')</script>", | |
"<iframe src='http://evil.example.com' style='display:none'></iframe>", | |
"<img src='http://evilsite.com?some-bad-payload' />", | |
), | |
'sql' => array( | |
"' OR 1=1; -- ", | |
"' UNION SELECT * FROM someTable", | |
), | |
); | |
/********************************************************************* | |
* Third, define our sensitive function | |
*********************************************************************/ | |
function mySensitiveFunction($untrusted_data){ | |
# sanitize our malicious payloads | |
eval(Security::cleanAllParams()); | |
# and print it to the screen. Let's see what we've got! | |
print_r($untrusted_data); | |
} | |
/********************************************************************* | |
* Fourth, pass our malicious code into the sensitive function | |
*********************************************************************/ | |
mySensitiveFunction($payloads); |
Understood. Yeah, I agree that this particular solution shouldn't be used in production. And yeah, I fist-pumped pretty hard (alone in my apartment, of course) when I hacked out that eval
bit. I'm glad you agree it's clever :)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Yes, I didn't mean to state that work into preventive measures like this was useless; just that it generally isn't a good idea.
At any rate, I can't believe I missed that
eval
, that is pure evil - but a neat trick. :)