[SECURITY] Open redirection with jumpurl 34/18734/2
authorFranz G. Jahn <franzjahn@cron-it.de>
Wed, 6 Mar 2013 10:49:25 +0000 (11:49 +0100)
committerOliver Hader <oliver.hader@typo3.org>
Wed, 6 Mar 2013 10:49:27 +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: ad62088840f78ed3947cfb9b66ef20d6d9760b69
Security-Bulletin: TYPO3-CORE-SA-2013-001
Reviewed-on: https://review.typo3.org/18734
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 e8f5021..eb70447 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 bed95e6..88e9641 100644 (file)
@@ -4994,7 +4994,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') . '>';
                                }
@@ -5724,7 +5726,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;
                                        }
@@ -5742,7 +5747,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;
                                                }
@@ -6246,7 +6257,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 92d193d..938c118 100644 (file)
@@ -2878,7 +2878,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);
+                               }
                        }
                }
        }