Successful login loops back to login page; SID resets

Get help with installation and running phpBB 3.0.x here. Please do not post bug reports, feature requests, or MOD-related questions here.
Anti-Spam Guide
Forum rules
END OF SUPPORT: 1 January 2017 (announcement)
Locked
User avatar
Seibertron
Registered User
Posts: 57
Joined: Tue Oct 01, 2002 7:54 pm
Location: Chicago, IL
Contact:

Successful login loops back to login page; SID resets

Post by Seibertron »

Support Request Template
What version of phpBB are you using? phpBB 3.0.11
What is your board's URL? http://www.seibertron.com/energonpub/
Who do you host your board with? 1and1
How did you install your board? I used the download package from phpBB.com
What is the most recent action performed on your board? Update from a previous version of phpBB3
Is registration required to reproduce this issue? Yes
Do you have any MODs installed? Yes
What version of phpBB3 did you update from? phpBB 3.0.7
What MODs do you have installed? An SEO mod a couple of years ago, but this problem has persisted long before that mod
What styles do you currently have installed? Prosilver
What language(s) is your board currently using? English
Which database type/version are you using? MySQL 5
What is your level of experience? Experienced with PHP and phpBB
What username can be used to view this issue? Test
What password can be used to view this issue? phpBB3_
When did your problem begin? A few years ago
Please describe your problem. Users regularly report experiencing issues with the "Log me on automatically each visit" functionality not working ... some users experiencing needing to login every day even though they click this checkbox.

After changing the cookie name, we are not able to login at all now. We keep looping back to the login page and the SID seems to keep changing which causes us to never have our session set.

I'm sure some combination of deleting browser cookies, clearing the session tables, etc will allow us to log back in but it's so finicky that I'd like to get to the bottom of this problem. I also can't expect all of the members of my site to do this task.
Generated by SRT Generator

I updated my site's forums to the latest stable non-beta version of phpBB (3.0.11) earlier today in order to eliminate that as a reason that this was happening. I see a lot of people having the same issue as me with phpbb here on these forums but can't find any solutions to help me with this problem.

I also installed this session script I found in another topic which might help debug this problem. I'm open to suggestions and hope that someone can point me in the right direction. I have spent countless hours chasing after this bug and would love to put this problem to bed at long last.

http://www.seibertron.com/energonpub/cookie-test.php

Code: Select all

<?php
class mini_session
{
   var $cookie_data = array();
   var $data = array();
   var $browser = '';
   var $forwarded_for = '';
   var $session_id = '';
   var $ip = '';
   var $time_now = 0;

   function session_begin()
   {
      global $config, $db;

      $this->cookie_data         = array('u' => 0, 'k' => '');
      $this->browser            = (!empty($_SERVER['HTTP_USER_AGENT'])) ? htmlspecialchars((string) $_SERVER['HTTP_USER_AGENT']) : '';
      $this->referer            = (!empty($_SERVER['HTTP_REFERER'])) ? htmlspecialchars((string) $_SERVER['HTTP_REFERER']) : '';
      $this->forwarded_for      = (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) ? htmlspecialchars((string) $_SERVER['HTTP_X_FORWARDED_FOR']) : '';
      $this->time_now            = time();

      $this->ip = (!empty($_SERVER['REMOTE_ADDR'])) ? (string) $_SERVER['REMOTE_ADDR'] : '';
      $this->ip = preg_replace('# {2,}#', ' ', str_replace(',', ' ', $this->ip));

      // split the list of IPs
      $ips = explode(' ', trim($this->ip));

      // Default IP if REMOTE_ADDR is invalid
      $this->ip = '127.0.0.1';

      foreach ($ips as $ip)
      {
         if (preg_match(get_preg_expression('ipv4'), $ip))
         {
            $this->ip = $ip;
         }
         else if (preg_match(get_preg_expression('ipv6'), $ip))
         {
            // Quick check for IPv4-mapped address in IPv6
            if (stripos($ip, '::ffff:') === 0)
            {
               $ipv4 = substr($ip, 7);

               if (preg_match(get_preg_expression('ipv4'), $ipv4))
               {
                  $ip = $ipv4;
               }
            }

            $this->ip = $ip;
         }
         else
         {
            // We want to use the last valid address in the chain
            // Leave foreach loop when address is invalid
            break;
         }
      }

      if (isset($_COOKIE[$config['cookie_name'] . '_sid']) || isset($_COOKIE[$config['cookie_name'] . '_u']))
      {
         $this->cookie_data['u'] = request_var($config['cookie_name'] . '_u', 0, false, true);
         $this->cookie_data['k'] = request_var($config['cookie_name'] . '_k', '', false, true);
         $this->session_id       = request_var($config['cookie_name'] . '_sid', '', false, true);

         $SID = (defined('NEED_SID')) ? '?sid=' . $this->session_id : '?sid=';
         $_SID = (defined('NEED_SID')) ? $this->session_id : '';

         if (empty($this->session_id))
         {
            $this->session_id = $_SID = request_var('sid', '');
            $SID = '?sid=' . $this->session_id;
            $this->cookie_data = array('u' => 0, 'k' => '');
         }
      }
      else
      {
         echo 'Cookies not found<br />';
      }

      // Is session_id is set or session_id is set and matches the url param if required
      if (!empty($this->session_id) && (!defined('NEED_SID') || (isset($_GET['sid']) && $this->session_id === $_GET['sid'])))
      {
         $sql = 'SELECT u.*, s.*
            FROM ' . SESSIONS_TABLE . ' s, ' . USERS_TABLE . " u
            WHERE s.session_id = '" . $db->sql_escape($this->session_id) . "'
               AND u.user_id = s.session_user_id";
         $result = $db->sql_query($sql);
         $this->data = $db->sql_fetchrow($result);
         $db->sql_freeresult($result);

         // Did the session exist in the DB?
         if (isset($this->data['user_id']))
         {
            if (strpos($this->ip, ':') !== false && strpos($this->data['session_ip'], ':') !== false)
            {
               $s_ip = short_ipv6($this->data['session_ip'], $config['ip_check']);
               $u_ip = short_ipv6($this->ip, $config['ip_check']);
            }
            else
            {
               $s_ip = implode('.', array_slice(explode('.', $this->data['session_ip']), 0, $config['ip_check']));
               $u_ip = implode('.', array_slice(explode('.', $this->ip), 0, $config['ip_check']));
            }

            $s_browser = ($config['browser_check']) ? trim(strtolower(substr($this->data['session_browser'], 0, 149))) : '';
            $u_browser = ($config['browser_check']) ? trim(strtolower(substr($this->browser, 0, 149))) : '';

            $s_forwarded_for = ($config['forwarded_for_check']) ? substr($this->data['session_forwarded_for'], 0, 254) : '';
            $u_forwarded_for = ($config['forwarded_for_check']) ? substr($this->forwarded_for, 0, 254) : '';

            // referer checks
            // The @ before $config['referer_validation'] suppresses notices present while running the updater
            $check_referer_path = (@$config['referer_validation'] == REFERER_VALIDATE_PATH);
            $referer_valid = true;

            // we assume HEAD and TRACE to be foul play and thus only whitelist GET
            if (@$config['referer_validation'] && isset($_SERVER['REQUEST_METHOD']) && strtolower($_SERVER['REQUEST_METHOD']) !== 'get')
            {
               $referer_valid = $this->validate_referer($check_referer_path);
            }

            if ($u_ip === $s_ip && $s_browser === $u_browser && $s_forwarded_for === $u_forwarded_for && $referer_valid)
            {
               $session_expired = false;
               if (!$session_expired)
               {
                  // Check the session length timeframe if autologin is not enabled.
                  // Else check the autologin length... and also removing those having autologin enabled but no longer allowed board-wide.
                  if (!$this->data['session_autologin'])
                  {
                     if ($this->data['session_time'] < $this->time_now - ($config['session_length'] + 60))
                     {
                        $session_expired = true;
                     }
                  }
                  else if (!$config['allow_autologin'] || ($config['max_autologin_time'] && $this->data['session_time'] < $this->time_now - (86400 * (int) $config['max_autologin_time']) + 60))
                  {
                     $session_expired = true;
                  }
               }

               if (!$session_expired)
               {
                  $this->data['is_registered'] = ($this->data['user_id'] != ANONYMOUS && ($this->data['user_type'] == USER_NORMAL || $this->data['user_type'] == USER_FOUNDER)) ? true : false;
                  $this->data['is_bot'] = (!$this->data['is_registered'] && $this->data['user_id'] != ANONYMOUS) ? true : false;
                  $this->data['user_lang'] = basename($this->data['user_lang']);

                  echo 'Valid session found.<br />';
                  return true;
               }
               else
               {
                  echo 'Session is expired<br />';
               }
            }
            else
            {
               echo 'Session is invalid: ';
               if($u_ip !== $s_ip)
               {
                  echo 'IPs do not match (' . $u_ip . ' vs ' . $s_ip . ') ';
               }

               if($s_browser !== $u_browser)
               {
                  echo 'User agents do not match. ';
               }

               if($s_forwarded_for !== $u_forwarded_for)
               {
                  echo 'Forwarded For does not match. ';
               }

               if(!$referer_valid)
               {
                  echo 'Referrer is invalid.';
               }
               echo '<br />';
            }
         }
         else
         {
            echo 'Session could not be found in database<br />';
         }
      }
      else
      {
         if(empty($this->session_id))
         {
            echo 'Session ID empty: ' . request_var($config['cookie_name'] . '_sid', '', false, true) . '(cookie rv), ' . request_var('sid', '') . '(sid rv)<br />';
         }

         if(defined('NEED_SID'))
         {
            echo 'NEED_SID is defined. This should only happen in the ACP.<br />';
         }

         if((isset($_GET['sid']) && $this->session_id === $_GET['sid']))
         {
            echo '_GET[sid] is set (' . $_GET['sid'] . '), but does not match cookie\'s session id (' . $this->session_id . ').<br />';
         }
      }

      // If we reach here then no (valid) session exists. So we'll create a new one
      echo 'Session does not exist or is invalid, creating a new one<br />';
      return $this->session_create();
   }

   function session_create($user_id = false, $set_admin = false, $persist_login = false, $viewonline = true)
   {
      global $SID, $_SID, $db, $config, $cache, $phpbb_root_path, $phpEx;

      $this->data = array();

      // Do we allow autologin on this board? No? Then override anything
      // that may be requested here
      if (!$config['allow_autologin'])
      {
         $this->cookie_data['k'] = $persist_login = false;
      }

      /**
      * Here we do a bot check, oh er saucy! No, not that kind of bot
      * check. We loop through the list of bots defined by the admin and
      * see if we have any useragent and/or IP matches. If we do, this is a
      * bot, act accordingly
      */
      $bot = false;
      $active_bots = $cache->obtain_bots();

      foreach ($active_bots as $row)
      {
         if ($row['bot_agent'] && preg_match('#' . str_replace('\*', '.*?', preg_quote($row['bot_agent'], '#')) . '#i', $this->browser))
         {
            $bot = $row['user_id'];
         }

         // If ip is supplied, we will make sure the ip is matching too...
         if ($row['bot_ip'] && ($bot || !$row['bot_agent']))
         {
            // Set bot to false, then we only have to set it to true if it is matching
            $bot = false;

            foreach (explode(',', $row['bot_ip']) as $bot_ip)
            {
               $bot_ip = trim($bot_ip);

               if (!$bot_ip)
               {
                  continue;
               }

               if (strpos($this->ip, $bot_ip) === 0)
               {
                  $bot = (int) $row['user_id'];
                  break;
               }
            }
         }

         if ($bot)
         {
            break;
         }
      }

      // If we're presented with an autologin key we'll join against it.
      // Else if we've been passed a user_id we'll grab data based on that
      if (isset($this->cookie_data['k']) && $this->cookie_data['k'] && $this->cookie_data['u'] && !sizeof($this->data))
      {
         $sql = 'SELECT u.*
            FROM ' . USERS_TABLE . ' u, ' . SESSIONS_KEYS_TABLE . ' k
            WHERE u.user_id = ' . (int) $this->cookie_data['u'] . '
               AND u.user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ")
               AND k.user_id = u.user_id
               AND k.key_id = '" . $db->sql_escape(md5($this->cookie_data['k'])) . "'";
         $result = $db->sql_query($sql);
         $this->data = $db->sql_fetchrow($result);
         $db->sql_freeresult($result);
         $bot = false;
      }
      else if ($user_id !== false && !sizeof($this->data))
      {
         $this->cookie_data['k'] = '';
         $this->cookie_data['u'] = $user_id;

         $sql = 'SELECT *
            FROM ' . USERS_TABLE . '
            WHERE user_id = ' . (int) $this->cookie_data['u'] . '
               AND user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ')';
         $result = $db->sql_query($sql);
         $this->data = $db->sql_fetchrow($result);
         $db->sql_freeresult($result);
         $bot = false;
      }

      if ($bot)
      {
         echo 'User has been detected as a bot<br />';
      }

      // If no data was returned one or more of the following occurred:
      // Key didn't match one in the DB
      // User does not exist
      // User is inactive
      // User is bot
      if (!sizeof($this->data) || !is_array($this->data))
      {
         $this->cookie_data['k'] = '';
         $this->cookie_data['u'] = ($bot) ? $bot : ANONYMOUS;

         if (!$bot)
         {
            $sql = 'SELECT *
               FROM ' . USERS_TABLE . '
               WHERE user_id = ' . (int) $this->cookie_data['u'];
         }
         else
         {
            // We give bots always the same session if it is not yet expired.
            $sql = 'SELECT u.*, s.*
               FROM ' . USERS_TABLE . ' u
               LEFT JOIN ' . SESSIONS_TABLE . ' s ON (s.session_user_id = u.user_id)
               WHERE u.user_id = ' . (int) $bot;
         }

         $result = $db->sql_query($sql);
         $this->data = $db->sql_fetchrow($result);
         $db->sql_freeresult($result);
      }

      if ($this->data['user_id'] != ANONYMOUS && !$bot)
      {
         $this->data['session_last_visit'] = (isset($this->data['session_time']) && $this->data['session_time']) ? $this->data['session_time'] : (($this->data['user_lastvisit']) ? $this->data['user_lastvisit'] : time());
      }
      else
      {
         $this->data['session_last_visit'] = $this->time_now;
      }

      // Force user id to be integer...
      $this->data['user_id'] = (int) $this->data['user_id'];

      // At this stage we should have a filled data array, defined cookie u and k data.
      // data array should contain recent session info if we're a real user and a recent
      // session exists in which case session_id will also be set

      $this->data['is_registered'] = (!$bot && $this->data['user_id'] != ANONYMOUS && ($this->data['user_type'] == USER_NORMAL || $this->data['user_type'] == USER_FOUNDER)) ? true : false;
      $this->data['is_bot'] = ($bot) ? true : false;

      // If our friend is a bot, we re-assign a previously assigned session
      if ($this->data['is_bot'] && $bot == $this->data['user_id'] && $this->data['session_id'])
      {
         // Only assign the current session if the ip, browser and forwarded_for match...
         if (strpos($this->ip, ':') !== false && strpos($this->data['session_ip'], ':') !== false)
         {
            $s_ip = short_ipv6($this->data['session_ip'], $config['ip_check']);
            $u_ip = short_ipv6($this->ip, $config['ip_check']);
         }
         else
         {
            $s_ip = implode('.', array_slice(explode('.', $this->data['session_ip']), 0, $config['ip_check']));
            $u_ip = implode('.', array_slice(explode('.', $this->ip), 0, $config['ip_check']));
         }

         $s_browser = ($config['browser_check']) ? trim(strtolower(substr($this->data['session_browser'], 0, 149))) : '';
         $u_browser = ($config['browser_check']) ? trim(strtolower(substr($this->browser, 0, 149))) : '';

         $s_forwarded_for = ($config['forwarded_for_check']) ? substr($this->data['session_forwarded_for'], 0, 254) : '';
         $u_forwarded_for = ($config['forwarded_for_check']) ? substr($this->forwarded_for, 0, 254) : '';

         if ($u_ip === $s_ip && $s_browser === $u_browser && $s_forwarded_for === $u_forwarded_for)
         {
            $this->session_id = $this->data['session_id'];

            $SID = '?sid=';
            $_SID = '';

            echo 'Valid bot session found<br />';
            return true;
         }
      }

      $session_autologin = (($this->cookie_data['k'] || $persist_login) && $this->data['is_registered']) ? true : false;

      // Something quite important: session_page always holds the *last* page visited, except for the *first* visit.
      // We are not able to simply have an empty session_page btw, therefore we need to tell phpBB how to detect this special case.
      // If the session id is empty, we have a completely new one and will set an "identifier" here. This identifier is able to be checked later.
      if (empty($this->data['session_id']))
      {
         // This is a temporary variable, only set for the very first visit
         $this->data['session_created'] = true;
         echo 'This is the first visit for this session<br />';
      }

      $this->session_id = $this->data['session_id'] = md5(unique_id());

      // refresh data
      $SID = '?sid=' . $this->session_id;
      $_SID = $this->session_id;

      echo 'New session created<br />';
      return true;
   }
}

$c_user_id = $c_sid = '';
foreach($_COOKIE as $key => $value)
{
   if(stripos($key, '_u') !== false)
   {
      $c_user_id = $value;
   }
   else if(stripos($key, '_sid') !== false)
   {
      $c_sid = $value;
   }
}

define('IN_PHPBB', true);
$phpbb_root_path = './';
$phpEx = substr(strrchr(__FILE__, '.'), 1);
include($phpbb_root_path . 'common.' . $phpEx);

$session = new mini_session();
$session->session_begin();

echo 'Cookie user ID: ' . $c_user_id . '<br />';
echo 'Cookie session ID: ' . $c_sid . '<br />';
echo 'Mini session user ID: ' . $session->data['user_id'] . '<br />';
echo 'Mini session ID: ' . $session->session_id . '<br />';

echo '<br />Starting phpBB session<br />';
// Start session management
$user->session_begin();
$auth->acl($user->data);
$user->setup();

echo 'Cookie user ID: ' . request_var($config['cookie_name'] . '_u', 0, false, true) . '<br />';
echo 'Cookie session ID: ' . request_var($config['cookie_name'] . '_sid', '', false, true) . '<br />';
echo 'phpBB session user ID: ' . $user->data['user_id'] . '<br />';
echo 'phpBB session ID: ' . $user->session_id . '<br />';

$path = pathinfo($_SERVER['SCRIPT_FILENAME']);
$current_page = $path['basename'];
echo '<br /><a href="' . $current_page . '?sid=' . $c_sid . '">Visit this page via SID</a>';
echo '<br />';

echo 'Server IP: ' . $_SERVER['SERVER_ADDR'] . '<br />';
echo 'Your IP: ' . $_SERVER['REMOTE_ADDR'];

if(isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
   echo '<br />Forwarded For: ' . $_SERVER['HTTP_X_FORWARDED_FOR'];
}
?>
Seibertron.com
http://www.seibertron.com
The Ultimate Transformers Fansite
User avatar
Seibertron
Registered User
Posts: 57
Joined: Tue Oct 01, 2002 7:54 pm
Location: Chicago, IL
Contact:

Re: Successful login loops back to login page; SID resets

Post by Seibertron »

Another related issue that we are experiencing is the "Log me on automatically each visit" option does not work consistently. I often have to log in again after a couple of days. Many users report this problem as well.

After further investigation and reading on various sites pertaining to similar issues other phpBB sites are experiencing, I significantly reduced my site's phpBB security settings (such as disabling the "Session IP validation" and "Validate browser" settings).

We are still experiencing these problems after these changes.
Seibertron.com
http://www.seibertron.com
The Ultimate Transformers Fansite
User avatar
Brf
Support Team Member
Support Team Member
Posts: 52169
Joined: Tue May 10, 2005 7:47 pm
Location: {postrow.POSTER_FROM}
Contact:

Re: Successful login loops back to login page; SID resets

Post by Brf »

Why does your script say my user_id is 47073?
The Anonymous user should be 1.
User avatar
Seibertron
Registered User
Posts: 57
Joined: Tue Oct 01, 2002 7:54 pm
Location: Chicago, IL
Contact:

Re: Successful login loops back to login page; SID resets

Post by Seibertron »

Brf wrote:Why does your script say my user_id is 47073?
The Anonymous user should be 1.
That is the default setting but you can change it to be another number. Back in late 2006 or early 2007 when I upgraded from phpBB 2 to 3, I followed some instructions on phpBB.com to change the default user ID. I needed to change the Anonymous user id because I use phpBB's logins elsewhere on my site. Changing my user id at the time created too much conflict with legacy code on my site. The Anonymous user id is defined in includes/constants.php

Code: Select all

define('ANONYMOUS', 47073);
Seibertron.com
http://www.seibertron.com
The Ultimate Transformers Fansite
Locked

Return to “[3.0.x] Support Forum”