[SECURITY] Open redirection with jumpurl 32/18732/2
authorFranz G. Jahn <franzjahn@cron-it.de>
Wed, 6 Mar 2013 10:49:12 +0000 (11:49 +0100)
committerOliver Hader <oliver.hader@typo3.org>
Wed, 6 Mar 2013 10:49:15 +0000 (11:49 +0100)
jumpurl allows redirect to any given URL. A hash on the url
is now required to know if the jumpurl has been created
by the system or by the outside.

The hook "jumpurlRedirectHandler" can be used to allow
redirects without hash or to custom redirects.

Fixes: #28587
Releases: 6.1, 6.0, 4.7, 4.6, 4.5
Change-Id: I63da18b1963ec50cd95dd49d1669c9873b7bab54
Security-Commit: db8748be003fdbd7fd179c239dd3dc92543e90bf
Security-Bulletin: TYPO3-CORE-SA-2013-001
Reviewed-on: https://review.typo3.org/18732
Reviewed-by: Oliver Hader
Tested-by: Oliver Hader
typo3/sysext/core/Classes/Utility/GeneralUtility.php
typo3/sysext/frontend/Classes/ContentObject/ContentObjectRenderer.php
typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php

index abeb964..6cef5ab 100644 (file)
@@ -779,25 +779,27 @@ class GeneralUtility {
         * Returns a proper HMAC on a given input string and secret TYPO3 encryption key.
         *
         * @param string $input Input string to create HMAC from
+        * @param string $additionalSecret additionalSecret to prevent hmac beeing used in a different context
         * @return string resulting (hexadecimal) HMAC currently with a length of 40 (HMAC-SHA-1)
         */
-       static public function hmac($input) {
+       static public function hmac($input, $additionalSecret = '') {
                $hashAlgorithm = 'sha1';
                $hashBlocksize = 64;
                $hmac = '';
+               $secret = $GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'] . $additionalSecret;
                if (extension_loaded('hash') && function_exists('hash_hmac') && function_exists('hash_algos') && in_array($hashAlgorithm, hash_algos())) {
-                       $hmac = hash_hmac($hashAlgorithm, $input, $GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey']);
+                       $hmac = hash_hmac($hashAlgorithm, $input, $secret);
                } else {
                        // Outer padding
                        $opad = str_repeat(chr(92), $hashBlocksize);
                        // Inner padding
                        $ipad = str_repeat(chr(54), $hashBlocksize);
-                       if (strlen($GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey']) > $hashBlocksize) {
+                       if (strlen($secret) > $hashBlocksize) {
                                // Keys longer than block size are shorten
-                               $key = str_pad(pack('H*', call_user_func($hashAlgorithm, $GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'])), $hashBlocksize, chr(0));
+                               $key = str_pad(pack('H*', call_user_func($hashAlgorithm, $secret)), $hashBlocksize, chr(0));
                        } else {
                                // Keys shorter than block size are zero-padded
-                               $key = str_pad($GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'], $hashBlocksize, chr(0));
+                               $key = str_pad($secret, $hashBlocksize, chr(0));
                        }
                        $hmac = call_user_func($hashAlgorithm, ($key ^ $opad) . pack('H*', call_user_func($hashAlgorithm, (($key ^ $ipad) . $input))));
                }
index 17d9b0a..3fe018c 100644 (file)
@@ -4961,7 +4961,9 @@ class ContentObjectRenderer {
                                        $target = $GLOBALS['TSFE']->extTarget;
                                }
                                if ($GLOBALS['TSFE']->config['config']['jumpurl_enable']) {
-                                       $res = '<a' . ' href="' . htmlspecialchars(($GLOBALS['TSFE']->absRefPrefix . $GLOBALS['TSFE']->config['mainScript'] . $initP . '&jumpurl=' . rawurlencode(('http://' . $parts[0])) . $GLOBALS['TSFE']->getMethodUrlIdToken)) . '"' . ($target ? ' target="' . $target . '"' : '') . $aTagParams . $this->extLinkATagParams(('http://' . $parts[0]), 'url') . '>';
+                                       $jumpurl = 'http://' . $parts[0];
+                                       $juHash = \TYPO3\CMS\Core\Utility\GeneralUtility::hmac($jumpurl, 'jumpurl');
+                                       $res = '<a' . ' href="' . htmlspecialchars(($GLOBALS['TSFE']->absRefPrefix . $GLOBALS['TSFE']->config['mainScript'] . $initP . '&jumpurl=' . rawurlencode($jumpurl))) . '&juHash=' . $juHash . $GLOBALS['TSFE']->getMethodUrlIdToken . '"' . ($target ? ' target="' . $target . '"' : '') . $aTagParams . $this->extLinkATagParams(('http://' . $parts[0]), 'url') . '>';
                                } else {
                                        $res = '<a' . ' href="http://' . htmlspecialchars($parts[0]) . '"' . ($target ? ' target="' . $target . '"' : '') . $aTagParams . $this->extLinkATagParams(('http://' . $parts[0]), 'url') . '>';
                                }
@@ -5693,7 +5695,10 @@ class ContentObjectRenderer {
                                                $scheme = '';
                                        }
                                        if ($GLOBALS['TSFE']->config['config']['jumpurl_enable']) {
-                                               $this->lastTypoLinkUrl = $GLOBALS['TSFE']->absRefPrefix . $GLOBALS['TSFE']->config['mainScript'] . $initP . '&jumpurl=' . rawurlencode(($scheme . $link_param)) . $GLOBALS['TSFE']->getMethodUrlIdToken;
+                                               $url = $GLOBALS['TSFE']->absRefPrefix . $GLOBALS['TSFE']->config['mainScript'] . $initP;
+                                               $jumpurl = $scheme . $link_param;
+                                               $juHash = \TYPO3\CMS\Core\Utility\GeneralUtility::hmac($jumpurl, 'jumpurl');
+                                               $this->lastTypoLinkUrl = $url . '&jumpurl=' . rawurlencode($jumpurl) . '&juHash='. $juHash . $GLOBALS['TSFE']->getMethodUrlIdToken;
                                        } else {
                                                $this->lastTypoLinkUrl = $scheme . $link_param;
                                        }
@@ -5711,7 +5716,13 @@ class ContentObjectRenderer {
                                                }
                                                if ($GLOBALS['TSFE']->config['config']['jumpurl_enable'] || $conf['jumpurl']) {
                                                        $theFileEnc = str_replace('%2F', '/', rawurlencode(rawurldecode($link_param)));
-                                                       $this->lastTypoLinkUrl = $GLOBALS['TSFE']->absRefPrefix . $GLOBALS['TSFE']->config['mainScript'] . $initP . '&jumpurl=' . rawurlencode($link_param) . ($conf['jumpurl.']['secure'] ? $this->locDataJU($theFileEnc, $conf['jumpurl.']['secure.']) : '') . $GLOBALS['TSFE']->getMethodUrlIdToken;
+                                                       $url = $GLOBALS['TSFE']->absRefPrefix . $GLOBALS['TSFE']->config['mainScript'] . $initP . '&jumpurl=' . rawurlencode($link_param);
+                                                       if ($conf['jumpurl.']['secure']) {
+                                                               $url .= $this->locDataJU($theFileEnc, $conf['jumpurl.']['secure.']);
+                                                       } else {
+                                                               $url .= '&juHash=' . \TYPO3\CMS\Core\Utility\GeneralUtility::hmac($link_param, 'jumpurl');
+                                                       }
+                                                       $this->lastTypoLinkUrl =  $url . $GLOBALS['TSFE']->getMethodUrlIdToken;
                                                } else {
                                                        $this->lastTypoLinkUrl = $GLOBALS['TSFE']->absRefPrefix . $link_param;
                                                }
@@ -6248,7 +6259,8 @@ class ContentObjectRenderer {
                                $linktxt = str_ireplace($mailAddress, $spamProtectedMailAddress, $linktxt);
                        }
                } else {
-                       $mailToUrl = $GLOBALS['TSFE']->absRefPrefix . $GLOBALS['TSFE']->config['mainScript'] . $initP . '&jumpurl=' . rawurlencode($mailToUrl) . $GLOBALS['TSFE']->getMethodUrlIdToken;
+                       $juHash = \TYPO3\CMS\Core\Utility\GeneralUtility::hmac($mailToUrl, 'jumpurl');
+                       $mailToUrl = $GLOBALS['TSFE']->absRefPrefix . $GLOBALS['TSFE']->config['mainScript'] . $initP . '&jumpurl=' . rawurlencode($mailToUrl) . '&juHash=' . $juHash . $GLOBALS['TSFE']->getMethodUrlIdToken;
                }
                return array(
                        $mailToUrl,
index 78c7cc5..a604001 100644 (file)
@@ -2919,7 +2919,29 @@ class TypoScriptFrontendController {
                                                break;
                                        }
                                }
-                               \TYPO3\CMS\Core\Utility\HttpUtility::redirect($this->jumpurl, $statusCode);
+
+                               $allowRedirect = FALSE;
+                               if (\TYPO3\CMS\Core\Utility\GeneralUtility::hmac($this->jumpurl, 'jumpurl') === (string)\TYPO3\CMS\Core\Utility\GeneralUtility::_GP('juHash')) {
+                                       $allowRedirect = TRUE;
+                               } elseif (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['jumpurlRedirectHandler'])) {
+                                       foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['jumpurlRedirectHandler'] as $classReference) {
+                                               $hookObject = \TYPO3\CMS\Core\Utility\GeneralUtility::getUserObj($classReference);
+                                               $allowRedirectFromHook = FALSE;
+                                               if (method_exists($hookObject, 'jumpurlRedirectHandler')) {
+                                                       $allowRedirectFromHook = $hookObject->jumpurlRedirectHandler($this->jumpurl, $this);
+                                               }
+                                               if ($allowRedirectFromHook === TRUE) {
+                                                       $allowRedirect = TRUE;
+                                                       break;
+                                               }
+                                       }
+                               }
+
+                               if ($allowRedirect) {
+                                       \TYPO3\CMS\Core\Utility\HttpUtility::redirect($this->jumpurl, $statusCode);
+                               } else {
+                                       throw new \Exception('jumpurl: Calculated juHash did not match the submitted juHash.', 1359987599);
+                               }
                        }
                }
        }