Index: tests/t3lib/t3lib_div_testcase.php =================================================================== --- tests/t3lib/t3lib_div_testcase.php (Revision 6383) +++ tests/t3lib/t3lib_div_testcase.php (Revision 6385) @@ -346,71 +346,78 @@ //////////////////////////////////////// - // Tests concerning sanitizeBackEndUrl + // Tests concerning sanitizeLocalUrl //////////////////////////////////////// /** - * @test + * Data provider for valid URLs. + * @see sanitizeLocalUrlAcceptsValidUrls */ - public function sanitizeBackEndUrlForEmptyStringReturnsEmptyString() { - $this->assertEquals( - '', - t3lib_div::sanitizeBackEndUrl('') + public function validLocalUrlDataProvider() { + return array( + array('alt_intro.php'), + array('alt_intro.php?foo=1&bar=2'), + array('/typo3/alt_intro.php'), + array('/index.php'), + array('../index.php'), + array('../typo3/alt_intro.php'), + array('../~userDirectory/index.php'), + array('../typo3/mod.php?var1=test-case&var2=~user'), + array(PATH_site . 'typo3/alt_intro.php'), + array(t3lib_div::getIndpEnv('TYPO3_SITE_URL') . 'typo3/alt_intro.php'), + array(t3lib_div::getIndpEnv('TYPO3_REQUEST_HOST') . '/index.php'), ); } /** - * @test + * Data provider for invalid URLs. + * @see sanitizeLocalUrlDeniesInvalidUrls */ - public function sanitizeBackEndUrlLeavesAbsoluteIntroUrlUnchanged() { - $this->assertEquals( - '/typo3/alt_intro.php', - t3lib_div::sanitizeBackEndUrl('/typo3/alt_intro.php') + public function invalidLocalUrlDataProvider() { + return array( + array(''), + array('http://www.google.de/'), + array('https://www.google.de/'), + array('../typo3/whatever.php?argument=javascript:alert(0)'), ); } /** + * Tests whether valid local URLs are handled correctly. + * @dataProvider validLocalUrlDataProvider * @test */ - public function sanitizeBackEndUrlLeavesRelativeIntroUrlUnchanged() { - $this->assertEquals( - 'alt_intro.php', - t3lib_div::sanitizeBackEndUrl('alt_intro.php') - ); + public function sanitizeLocalUrlAcceptsPlainValidUrls($url) { + $this->assertEquals($url, t3lib_div::sanitizeLocalUrl($url)); } /** + * Tests whether valid local URLs are handled correctly. + * @dataProvider validLocalUrlDataProvider * @test */ - public function sanitizeBackEndUrlLeavesRelativeIntroUrlWithParameterUnchanged() { - $this->assertEquals( - 'alt_intro.php?foo=1&bar=2', - t3lib_div::sanitizeBackEndUrl('alt_intro.php?foo=1&bar=2') - ); + public function sanitizeLocalUrlAcceptsEncodedValidUrls($url) { + $this->assertEquals(rawurlencode($url), t3lib_div::sanitizeLocalUrl(rawurlencode($url))); } /** + * Tests whether valid local URLs are handled correctly. + * @dataProvider invalidLocalUrlDataProvider * @test */ - public function sanitizeBackEndUrlForFullUrlReturnsEmptyString() { - $this->assertEquals( - '', - t3lib_div::sanitizeBackEndUrl('http://www.google.de/') - ); + public function sanitizeLocalUrlDeniesPlainInvalidUrls($url) { + $this->assertEquals('', t3lib_div::sanitizeLocalUrl($url)); } /** + * Tests whether valid local URLs are handled correctly. + * @dataProvider invalidLocalUrlDataProvider * @test */ - public function sanitizeBackEndUrlForRelativeIntroUrlWithEncodedCharacterReturnsEmptyString() { - $this->assertEquals( - '', - t3lib_div::sanitizeBackEndUrl('alt_intro.php?%20') - ); + public function sanitizeLocalUrlDeniesEncodedInvalidUrls($url) { + $this->assertEquals('', t3lib_div::sanitizeLocalUrl(rawurlencode($url))); } - - ////////////////////////////////////// // Tests concerning removeDotsFromTS ////////////////////////////////////// Index: t3lib/class.t3lib_div.php =================================================================== --- t3lib/class.t3lib_div.php (Revision 6383) +++ t3lib/class.t3lib_div.php (Revision 6385) @@ -4172,13 +4172,38 @@ * @return string either $url if $url is considered to be harmless, or an * empty string otherwise */ - public static function sanitizeBackEndUrl($url = '') { - $whitelistPattern = '/^[a-zA-Z0-9_\/\.&=\?]+$/'; - if (!preg_match($whitelistPattern, $url)) { - $url = ''; + public static function sanitizeLocalUrl($url = '') { + $sanitizedUrl = ''; + $decodedUrl = rawurldecode($url); + + if (!empty($url) && self::removeXSS($decodedUrl) === $decodedUrl) { + $testAbsoluteUrl = self::resolveBackPath($decodedUrl); + $testRelativeUrl = self::resolveBackPath( + t3lib_div::dirname(t3lib_div::getIndpEnv('SCRIPT_NAME')) . '/' . $decodedUrl + ); + + // Pass if URL is on the current host: + if (self::isValidUrl($decodedUrl)) { + if (self::isOnCurrentHost($decodedUrl) && strpos($decodedUrl, self::getIndpEnv('TYPO3_SITE_URL')) === 0) { + $sanitizedUrl = $url; + } + // Pass if URL is an absolute file path: + } elseif (self::isAbsPath($decodedUrl) && self::isAllowedAbsPath($decodedUrl)) { + $sanitizedUrl = $url; + // Pass if URL is absolute and below TYPO3 base directory: + } elseif (strpos($testAbsoluteUrl, self::getIndpEnv('TYPO3_SITE_PATH')) === 0 && substr($decodedUrl, 0, 1) === '/') { + $sanitizedUrl = $url; + // Pass if URL is relative and below TYPO3 base directory: + } elseif (strpos($testRelativeUrl, self::getIndpEnv('TYPO3_SITE_PATH')) === 0 && substr($decodedUrl, 0, 1) !== '/') { + $sanitizedUrl = $url; + } } - return $url; + if (!empty($url) && empty($sanitizedUrl)) { + self::sysLog('The URL "' . $url . '" is not considered to be local and was denied.', 'Core', self::SYSLOG_SEVERITY_NOTICE); + } + + return $sanitizedUrl; } /** Index: typo3/alt_mod_frameset.php =================================================================== --- typo3/alt_mod_frameset.php (Revision 6383) +++ typo3/alt_mod_frameset.php (Revision 6385) @@ -87,7 +87,7 @@ global $BE_USER,$TBE_TEMPLATE,$TBE_STYLES; // GPvars: - $this->exScript = t3lib_div::sanitizeBackEndUrl(t3lib_div::_GP('exScript')); + $this->exScript = t3lib_div::sanitizeLocalUrl(t3lib_div::_GP('exScript')); $this->id = intval(t3lib_div::_GP('id')); $this->fW = t3lib_div::_GP('fW'); @@ -103,8 +103,8 @@ } // Navigation frame URL: - $script = t3lib_div::sanitizeBackEndUrl(t3lib_div::_GP('script')); - $nav = t3lib_div::sanitizeBackEndUrl(t3lib_div::_GP('nav')); + $script = t3lib_div::sanitizeLocalUrl(t3lib_div::_GP('script')); + $nav = t3lib_div::sanitizeLocalUrl(t3lib_div::_GP('nav')); $URL_nav = htmlspecialchars($nav.'¤tSubScript='.rawurlencode($script)); // List frame URL: @@ -114,12 +114,9 @@ $TBE_TEMPLATE->docType='xhtml_frames'; $this->content = $TBE_TEMPLATE->startPage('Frameset'); - // THis onload handler is a bug-fix for a possible bug in Safari browser for Mac. Posted by Jack COLE. Should not influence other browsers negatively. - $onLoadHandler = ' onload="if(top.content.nav_frame.location.href.length == 1) {top.content.nav_frame.location=\''.$URL_nav.'\';};"'; - if ($this->resizable) { $this->content.= ' - + @@ -129,7 +126,7 @@ } else { $this->content.= ' - +