', true),
Array('', true),
Array('', true),
Array('
', true),
Array('
', true),
// false positiv tests
Array('If 1 < 2, what does that mean for description, if 2 > 1.', false),
Array('If 1 < 2, what does that mean for a script, if 2 > 1.', false),
Array('Script and Javascript: not evil ;-)', false),
Array('style=background-color', false),
Array('Hugo Sonstwas ', false),
Array('', false)
);
}
/**
* Test some URLs with bad stuff
*
* @param String $url
* @param Array $vectors
*
* @dataProvider urlProvider
*/
public function testURLs($url, $vectors = FALSE)
{
// no all xss attack vectors from http://ha.ckers.org/xssAttacks.xml are relevant here! (needs interpretation)
if (!$vectors)
{
$this->markTestSkipped("Could not download or parse $url with attack vectors");
return;
}
foreach($vectors as $line => $pattern)
{
$test = array($pattern);
_check_script_tag($test, 'line '.(1+$line), false);
$this->assertTrue(isset($GLOBALS['egw_unset_vars']), $line . ': ' . $pattern);
}
}
public function urlProvider()
{
$urls = array(
// we currently fail 76 of 666 test, thought they seem not to apply to our use case, as we check request data
'https://gist.github.com/JohannesHoppe/5612274' => file(
'https://gist.githubusercontent.com/JohannesHoppe/5612274/raw/60016bccbfe894dcd61a6be658a4469e403527de/666_lines_of_XSS_vectors.html'),
// we currently fail 44 of 140 tests, thought they seem not to apply to our use case, as we check request data
'https://html5sec.org/' => call_user_func(function() {
$payloads = $items = null;
try
{
if (!($items_js = file_get_contents('https://html5sec.org/items.js')) ||
!preg_match_all("|^\s+'data'\s+:\s+'(.*)',$|m", $items_js, $items, PREG_PATTERN_ORDER) ||
!($payload_js = file_get_contents('https://html5sec.org/payloads.js')) ||
!preg_match_all("|^\s+'([^']+)'\s+:\s+'(.*)',$|m", $payload_js, $payloads, PREG_PATTERN_ORDER))
{
return false;
}
}
catch (Exception $e)
{
unset($e);
return false;
}
$replace = array(
"\\'" => "'",
'\\\\'=> '\\,',
'\r' => "\r",
'\n' => "\n",
);
foreach($payloads[1] as $n => $from) {
$replace['%'.$from.'%'] = $payloads[2][$n];
}
return array_map(function($item) use ($replace) {
return strtr($item, $replace);
}, $items[1]);
}),
);
$test_data = array();
foreach($urls as $url => $vectors)
{
$test_data[] = array(
$url, $vectors
);
}
return $test_data;
}
/**
* Test safe unserialization
*
* @param String $str Serialized string to be checked
* @param boolean $result If we expect the string to fail or not
*
* @dataProvider unserializeProvider
* @requires PHP < 7
*/
public function testObjectsCannotBeUnserializedInPhp5($str, $result)
{
$r=@php_safe_unserialize($str);
$this->assertSame($result, (bool)$r, 'Save unserialize failed');
}
/**
* Test safe unserialization
*
* @param String $str Serialized string to be checked
* @param boolean $result If we expect the string to fail or not
*
* @dataProvider unserializeProvider
* @requires PHP 7
*/
public function testObjectsCannotBeUnserializedInPhp7($str, $result)
{
$r=@php_safe_unserialize($str);
if((bool)($r) !== $result)
{
if (!$result)
{
$matches = null;
if (preg_match_all('/([^ ]+) Object\(/', array2string($r), $matches))
{
foreach($matches[1] as $class)
{
if (!preg_match('/^__PHP_Incomplete_Class(#\d+)?$/', $class))
{
$this->fail($str);
}
}
}
}
else
{
$this->fail("false positive: $str");
}
}
// Avoid this test getting reported as no assertions, we do the testing
// in the foreach loop
$this->assertTrue(true);
}
/**
* Data set for unserialize test
*/
public function unserializeProvider()
{
$tests = array(
// Serialized string, expected result
// things unsafe to unserialize
Array("O:34:\"Horde_Kolab_Server_Decorator_Clean\":2:{s:43:\"\x00Horde_Kolab_Server_Decorator_Clean\x00_server\";", false),
Array("O:20:\"Horde_Prefs_Identity\":2:{s:9:\"\x00*\x00_prefs\";O:11:\"Horde_Prefs\":2:{s:8:\"\x00*\x00_opts\";a:1:{s:12:\"sizecallback\";", false),
Array("a:2:{i:0;O:12:\"Horde_Config\":1:{s:13:\"\x00*\x00_oldConfig\";s:#{php_injection.length}:\"#{php_injection}\";}i:1;s:13:\"readXMLConfig\";}}", false),
Array('a:6:{i:0;i:0;i:1;d:2;i:2;s:4:"ABCD";i:3;r:3;i:4;O:8:"my_Class":2:{s:1:"a";r:6;s:1:"b";N;};i:5;C:16:"SplObjectStorage":14:{x:i:0;m:a:0:{}}', false),
Array(serialize(new \stdClass()), false),
Array(serialize(array(new \stdClass(), new \SplObjectStorage())), false),
// string content, safe to unserialize
Array(serialize('O:8:"stdClass"'), true),
Array(serialize('C:16:"SplObjectStorage"'), true),
Array(serialize(array('a', 'O:8:"stdClass"', 'b', 'C:16:"SplObjectStorage"')), true)
);
if (PHP_VERSION >= 7)
{
// Fails our php<7 regular expression, because it has correct delimiter (^|;|{) in front of pattern :-(
$tests[] = Array(serialize('O:8:"stdClass";C:16:"SplObjectStorage"'), true);
}
return $tests;
}
}