Added feature #7461: Transfer cookies via SSL only whenever possible
authorOliver Hader <oliver.hader@typo3.org>
Wed, 30 Sep 2009 21:57:01 +0000 (21:57 +0000)
committerOliver Hader <oliver.hader@typo3.org>
Wed, 30 Sep 2009 21:57:01 +0000 (21:57 +0000)
git-svn-id: https://svn.typo3.org/TYPO3v4/Core/trunk@6080 709f56b5-9817-0410-a4d7-c38de5d9e867

ChangeLog
t3lib/class.t3lib_userauth.php
t3lib/config_default.php

index 81972f6..a299b42 100755 (executable)
--- a/ChangeLog
+++ b/ChangeLog
@@ -6,6 +6,7 @@
 
        * Fixed bug #12035: BE style must match t3skin in reports module and flash messages (thanks to Tom Ruether)
        * Fixed bug #12036: BE style must match t3skin in Install Tool (thanks to Tom Ruether)
+       * Added feature #7461: Transfer cookies via SSL only whenever possible
 
 2009-09-30  Rupert Germann  <rupi@gmx.li>
 
index 12a7ae8..089a2ee 100644 (file)
@@ -274,41 +274,8 @@ class t3lib_userAuth {
                if ($this->writeDevLog && !is_array($this->user)) t3lib_div::devLog('No user session found.', 't3lib_userAuth', 2);
 
                        // Setting cookies
-               if ($TYPO3_CONF_VARS['SYS']['cookieDomain'])    {
-                       if ($TYPO3_CONF_VARS['SYS']['cookieDomain']{0} == '/')  {
-                               $matchCnt = @preg_match($TYPO3_CONF_VARS['SYS']['cookieDomain'], t3lib_div::getIndpEnv('TYPO3_HOST_ONLY'), $match);
-                               if ($matchCnt === FALSE)        {
-                                       t3lib_div::sysLog('The regular expression of $TYPO3_CONF_VARS[SYS][cookieDomain] contains errors. The session is not shared across sub-domains.', 'Core', 3);
-                               } elseif ($matchCnt)    {
-                                       $cookieDomain = $match[0];
-                               }
-                       } else {
-                               $cookieDomain = $TYPO3_CONF_VARS['SYS']['cookieDomain'];
-                       }
-               }
-
-                       // If new session and the cookie is a sessioncookie, we need to set it only once!
-               if ($this->isSetSessionCookie())        {
-                       if (!$this->dontSetCookie)      {
-                               if ($cookieDomain)      {
-                                       SetCookie($this->name, $id, 0, '/', $cookieDomain);
-                               } else {
-                                       SetCookie($this->name, $id, 0, t3lib_div::getIndpEnv('TYPO3_SITE_PATH'));
-                               }
-                               if ($this->writeDevLog)         t3lib_div::devLog('Set new Cookie: '.$id.($cookieDomain ? ', '.$cookieDomain : ''), 't3lib_userAuth');
-                       }
-               }
-
-                       // If it is NOT a session-cookie, we need to refresh it.
-               if ($this->isRefreshTimeBasedCookie())  {
-                       if (!$this->dontSetCookie)      {
-                               if ($cookieDomain)      {
-                                       SetCookie($this->name, $id, $GLOBALS['EXEC_TIME'] + $this->lifetime, '/', $cookieDomain);
-                               } else {
-                                       SetCookie($this->name, $id, $GLOBALS['EXEC_TIME'] + $this->lifetime, t3lib_div::getIndpEnv('TYPO3_SITE_PATH'));
-                               }
-                               if ($this->writeDevLog)         t3lib_div::devLog('Update Cookie: '.$id.($cookieDomain ? ', '.$cookieDomain : ''), 't3lib_userAuth');
-                       }
+               if (!$this->dontSetCookie)      {
+                       $this->setSessionCookie();
                }
 
                        // Hook for alternative ways of filling the $this->user array (is used by the "timtaw" extension)
@@ -345,6 +312,80 @@ class t3lib_userAuth {
        }
 
        /**
+        * Sets the session cookie for the current disposal.
+        *
+        * @return      void
+        */
+       protected function setSessionCookie() {
+               $isSetSessionCookie = $this->isSetSessionCookie();
+               $isRefreshTimeBasedCookie = $this->isRefreshTimeBasedCookie();
+
+               if ($isSetSessionCookie || $isRefreshTimeBasedCookie) {
+                       $settings = $GLOBALS['TYPO3_CONF_VARS']['SYS'];
+
+                       // Get the domain to be used for the cookie (if any):
+                       $cookieDomain = $this->getCookieDomain();
+                       // If no cookie domain is set, use the base path:
+                       $cookiePath = ($cookieDomain ? '/' : t3lib_div::getIndpEnv('TYPO3_SITE_PATH'));
+                       // If the cookie lifetime is set, use it:
+                       $cookieExpire = ($isRefreshTimeBasedCookie ? $GLOBALS['EXEC_TIME'] + $this->lifetime : 0);
+                       // Use the secure option when the current request is served by a secure connection:
+                       $cookieSecure = (bool)$settings['cookieSecure'] && t3lib_div::getIndpEnv('TYPO3_SSL');
+                       // Deliver cookies only via HTTP and prevent possible XSS by JavaScript:
+                       $cookieHttpOnly = (bool)$settings['cookieHttpOnly'];
+
+                       // Do not set cookie if cookieSecure is set to "1" (force HTTPS) and no secure channel is used: 
+                       if ((int)$settings['cookieSecure'] !== 1 || t3lib_div::getIndpEnv('TYPO3_SSL')) {
+                               setcookie(
+                                       $this->name,
+                                       $this->id,
+                                       $cookieExpire,
+                                       $cookiePath,
+                                       $cookieDomain,
+                                       $cookieSecure,
+                                       $cookieHttpOnly
+                               );
+                       } else {
+                               throw new t3lib_exception(
+                                       'Cookie was not set since HTTPS was forced in $TYPO3_CONF_VARS[SYS][cookieSecure].',
+                                       1254325546
+                               );
+                       }
+
+                       if ($this->writeDevLog) {
+                               $devLogMessage = ($isRefreshTimeBasedCookie ? 'Updated Cookie: ' : 'Set Cookie: ') . $this->id;
+                               t3lib_div::devLog($devLogMessage . ($cookieDomain ? ', '.$cookieDomain : ''), 't3lib_userAuth');
+                       }
+               }
+       }
+
+       /**
+        * Gets the domain to be used on setting cookies.
+        * The information is taken from the value in $TYPO3_CONF_VARS[SYS][cookieDomain].
+        * 
+        * @return      string          The domain to be used on setting cookies
+        */
+       protected function getCookieDomain() {
+               $result = '';
+               $cookieDomain = $GLOBALS['TYPO3_CONF_VARS']['SYS']['cookieDomain'];
+
+               if ($cookieDomain) {
+                       if ($cookieDomain{0} == '/') {
+                               $matchCnt = @preg_match($cookieDomain, t3lib_div::getIndpEnv('TYPO3_HOST_ONLY'), $match);
+                               if ($matchCnt === FALSE) {
+                                       t3lib_div::sysLog('The regular expression of $TYPO3_CONF_VARS[SYS][cookieDomain] contains errors. The session is not shared across sub-domains.', 'Core', 3);
+                               } elseif ($matchCnt) {
+                                       $result = $match[0];
+                               }
+                       } else {
+                               $result = $TYPO3_CONF_VARS['SYS']['cookieDomain'];
+                       }
+               }
+
+               return $result;
+       }
+
+       /**
         * Determine whether a session cookie needs to be set (lifetime=0)
         *
         * @return      boolean
index fc35411..08dfb4f 100644 (file)
@@ -62,6 +62,8 @@ $TYPO3_CONF_VARS = Array(
                'compat_version' => '3.8',                              // Compatibility version. TYPO3 behavior will try to be compatible with the output from the TYPO3 version set here. It is recommended to change this setting with the Upgrade Wizard.
                'encryptionKey' => '',                                  // This is a "salt" used for various kinds of encryption, CRC checksums and validations. You can enter any rubbish string here but try to keep it secret. You should notice that a change to this value might invalidate temporary information, URLs etc. At least, clear all cache if you change this so any such information can be rebuild with the new key.
                'cookieDomain' => '',                                   // When setting the value to ".example.com" (replace example.com with your domain!), login sessions will be shared across subdomains. Alternatively, if you have more than one domain with sub-domains, you can set the value to a regular expression to match against the domain of the HTTP request. The result of the match is used as the domain for the cookie. eg. /\.(example1|example2)\.com$/ or /\.(example1\.com)|(example2\.net)$/
+               'cookieSecure' => 0,                                    // Integer (0, 1, 2): Indicates that the cookie should only be transmitted over a secure HTTPS connection from the client. If set to 1 (force HTTPS), the cookie will only be set if a secure (HTTPS) connection exists - use this in combination with lockSSL since otherwise the application will fail and throw an exception! If set to 2, the cookie will be set in each case, but uses the secure flag if a secure (HTTPS) connection exists.
+               'cookieHttpOnly' => 0,                                  // Boolean: When enabled the cookie will be made accessible only through the HTTP protocol. This means that the cookie won't be accessible by scripting languages, such as JavaScript. This setting can effectively help to reduce identity theft through XSS attacks (although it is not supported by all browsers).
                'doNotCheckReferer' => 0,                               // Boolean. If set, it's NOT checked numerous places that the refering host is the same as the current. This is an option you should set if you have problems with proxies not passing the HTTP_REFERER variable.
                'recursiveDomainSearch' => 0,                   // Boolean. If set, the search for domain records will be done recursively by stripping parts of the host name off until a matching domain record is found.
                'devIPmask' => '127.0.0.1,::1',                 // Defines a list of IP addresses which will allow development-output to display. The debug() function will use this as a filter. See the function t3lib_div::cmpIP() for details on syntax. Setting this to blank value will deny all. Setting to "*" will allow all.