Bug #80888 ยป removexssdatauri.patch
typo3/sysext/core/Tests/Legacy/typo3/contrib/class.removexssTest.php (revision ) | ||
---|---|---|
public function checkAttackMetaWithUrl()
|
||
{
|
||
$testString = '<META HTTP-EQUIV="refresh" CONTENT="0;url=data:text/html;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4K">';
|
||
$expectedString = '<me<x>ta HTTP-EQUIV="refresh" CONTENT="0;url=data:text/html;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4K">';
|
||
$expectedString = '<me<x>ta HTTP-EQUIV="refresh" CONTENT="0;url=<sc<x>ript>alert(\'XSS\')</script>
|
||
">';
|
||
$actualString = RemoveXSS::process($testString);
|
||
$this->assertEquals($expectedString, $actualString);
|
||
... | ... | |
RemoveXSS::process($input)
|
||
);
|
||
}
|
||
/**
|
||
* @return array<array> input strings and expected output strings to test
|
||
*
|
||
* @see dataUrlWithDataProvider
|
||
*/
|
||
public function dataUrlDataProvider()
|
||
{
|
||
return array(
|
||
'attackWithUrlEncodedData' => array(
|
||
'<a href="data:,%3Cscript%3Ealert%28%27XSS%21%27%29%3B%3C%2Fscript%3E">click</a>',
|
||
'<a href="<sc<x>ript>alert(\'XSS!\');</script>">click</a>',
|
||
),
|
||
'attackWithUrlEncodedDataAndMimeType' => array(
|
||
'<a href="data:text/javascript,%3Cscript%3Ealert%28%27XSS%21%27%29%3B%3C%2Fscript%3E">click</a>',
|
||
'<a href="<sc<x>ript>alert(\'XSS!\');</script>">click</a>',
|
||
),
|
||
'attackWithUrlEncodedDataAndCharset' => array(
|
||
'<a href="data:charset=utf-8,%3Cscript%3Ealert%28%27XSS%21%27%29%3B%3C%2Fscript%3E">click</a>',
|
||
'<a href="<sc<x>ript>alert(\'XSS!\');</script>">click</a>',
|
||
),
|
||
'attackWithUrlEncodedDataAndMimeTypeAndCharset' => array(
|
||
'<a href="data:text/javascript;utf-8,%3Cscript%3Ealert%28%27XSS%21%27%29%3B%3C%2Fscript%3E">click</a>',
|
||
'<a href="<sc<x>ript>alert(\'XSS!\');</script>">click</a>',
|
||
),
|
||
'attackWithBase64Data' => array(
|
||
'<a href="data:base64,PHNjcmlwdD5hbGVydCgnWFNTIScpOzwvc2NyaXB0Pg">click</a>',
|
||
'<a href="<sc<x>ript>alert(\'XSS!\');</script>">click</a>',
|
||
),
|
||
'attackWithBase64DataAndMimeType' => array(
|
||
'<a href="data:text/javascript;base64,PHNjcmlwdD5hbGVydCgnWFNTIScpOzwvc2NyaXB0Pg">click</a>',
|
||
'<a href="<sc<x>ript>alert(\'XSS!\');</script>">click</a>',
|
||
),
|
||
'attackWithBase64DataAndCharset' => array(
|
||
'<a href="data:charset=utf-8;base64,PHNjcmlwdD5hbGVydCgnWFNTIScpOzwvc2NyaXB0Pg">click</a>',
|
||
'<a href="<sc<x>ript>alert(\'XSS!\');</script>">click</a>',
|
||
),
|
||
'attackWithBase64DataAndMimeTypeAndCharset' => array(
|
||
'<a href="data:text/javascript;chareset=utf-8;base64,PHNjcmlwdD5hbGVydCgnWFNTIScpOzwvc2NyaXB0Pg">click</a>',
|
||
'<a href="<sc<x>ript>alert(\'XSS!\');</script>">click</a>',
|
||
),
|
||
);
|
||
}
|
||
/**
|
||
* @test
|
||
*
|
||
* @param string $input input value to test
|
||
* @param string $expected expected output value
|
||
*
|
||
* @dataProvider dataUrlDataProvider
|
||
*/
|
||
public function dataUrlWithDataProvider($input, $expected)
|
||
{
|
||
$this->assertEquals(
|
||
$expected,
|
||
RemoveXSS::process($input)
|
||
);
|
||
}
|
||
}
|
typo3/sysext/core/Resources/PHP/RemoveXSS.php (revision ) | ||
---|---|---|
// Note that you have to handle splits with \n, \r, and \t later since they *are* allowed in some inputs
|
||
$value = preg_replace('/([\x00-\x08]|[\x0b-\x0c]|[\x0e-\x19])/', '', $value);
|
||
// Replace data URLs as they can obfuscate the payload
|
||
if (stripos($value, 'data:') !== false) {
|
||
$searchDataUris = '/data:((?<!base64|charset|,).*?)?(;?charset=.+?)?(;?base64)?(\,(?:[A-Za-z0-9+\/\._~%-]+)?)/m';
|
||
$value = preg_replace_callback(
|
||
$searchDataUris,
|
||
function($matches) {
|
||
$entireDataUri = array_shift($matches);
|
||
$data = '';
|
||
$encodingFunction = 'rawurldecode';
|
||
$charset = 'US-ASCII';
|
||
$mimeType = 'text';
|
||
foreach ($matches as $match) {
|
||
if (substr($match, 0, 1) === ',') {
|
||
// check for data block
|
||
$data = substr($match, 1);
|
||
} elseif (substr($match, 0, 7) === ';base64' || substr($match, 0, 6) === 'base64') {
|
||
// check for base64 notation
|
||
$encodingFunction = 'base64_decode';
|
||
} elseif (substr($match, 0, 9) === ';charset=' || substr($match, 0, 8) === 'charset=') {
|
||
// check for charset
|
||
$charset = substr(ltrim($match, ';'), 8);
|
||
} elseif (strpos($match, '/') !== false) {
|
||
// check for mime-type
|
||
$mimeTypeParts = explode('/', $match, 2);
|
||
$mimeType = $mimeTypeParts[0];
|
||
}
|
||
}
|
||
if ($mimeType !== 'text') {
|
||
// Anything else than text does not need handling
|
||
return $entireDataUri;
|
||
}
|
||
// charset handling needed?
|
||
return $encodingFunction($data);
|
||
},
|
||
$value);
|
||
}
|
||
// Straight replacements, the user should never need these since they're normal characters.
|
||
// This prevents like <IMG SRC=@avascript:alert('XSS')>
|
||
$searchHexEncodings = '/&#[xX]0{0,8}(21|22|23|24|25|26|27|28|29|2a|2b|2d|2f|30|31|32|33|34|35|36|37|38|39|3a|3b|3d|3f|40|41|42|43|44|45|46|47|48|49|4a|4b|4c|4d|4e|4f|50|51|52|53|54|55|56|57|58|59|5a|5b|5c|5d|5e|5f|60|61|62|63|64|65|66|67|68|69|6a|6b|6c|6d|6e|6f|70|71|72|73|74|75|76|77|78|79|7a|7b|7c|7d|7e);?/i';
|