dongxiao3694 2013-09-05 16:56
浏览 62

PHP Session认为除非执行回声,否则它将被劫持

I'm writing a simple website which allows a user to login, fill out a form which is submitted to a database and then log out. In order to manage the session, I used the session manager which is described by TreeHouse on the following page: http://blog.teamtreehouse.com/how-to-create-bulletproof-sessions

In order to protect against hijacking, the client's IP address and user agent are stored in the session variable and compared to the server's values for these properties on each page. If they don't match, then it is assumed that the session has been hijacked and it is reset.

The implementation seems to work on my local machine without any issues, but when I uploaded it to the server, each page refresh causes the preventHijacking() function to return false (meaning it believes the session has been hijacked). However, if I echo any text within that function, the problem mysteriously disappears and the whole thing works as I expect it to (except for the bit of echoed text which is now displayed above my form :P).

I haven't a clue why this would be the case and I can't figure out how to fix it. The session manager code is below. At the start of each page, I use this to start the session and then each page simply uses or sets whatever variables it requires. If anyone could suggest why the function always returns false unless it echoes text and perhaps suggest what modification I need to make so that it will behave in the expected manner, I'd really appreciate it.

<?php
class SessionManager {

  protected static $timeout = 600; // Time before automatic logout for the session

  static function sessionStart($name, $limit=0, $path='/', $domain=null, $secure=null) {
    // Set the cookie name before we start
    session_name($name.'_Session');

    // Set the domain to default to the current domain
    $domain = isset($domain)? $domain : $_SERVER['SERVER_NAME'];

    // Set the default secure value to whether the site is being accessed with SSL
    $https = isset($secure)? $secure : isset($_SERVER['HTTPS']);

    // Set the cookie settings and start the session
    session_set_cookie_params($limit, $path, $domain, $secure, True);
    session_start();

    // Make sure the session hasn't expired and destroy it if it has
    if(self::validateSession()) {

      // Check to see if the session is new or a hijacking attempt     
      if(!self::preventHijacking()) {      
        // Reset session data and regenerate ID
        $_SESSION=array();
        $_SESSION['IPaddress'] = $_SERVER['REMOTE_ADDR'];
        $_SESSION['userAgent'] = $_SERVER['HTTP_USER_AGENT'];
        self::regenerateSession();

        // Give a 5% chance of the session ID changing on any request
      } else if (rand(1, 100) <= 5) {
        self::regenerateSession();
      }

      $_SESSION['LAST_ACTIVITY'] = time();
    } else {
      $_SESSION = array();
      session_destroy();
      session_start();
    }
  }

  static function preventHijacking() {
    if(!isset($_SESSION['IPaddress']) || !isset($_SESSION['userAgent'])) {
      return false;
    }

    if($_SESSION['IPaddress'] != $_SERVER['REMOTE_ADDR']) {
      return false;
    }

    if($_SESSION['userAgent'] != $_SERVER['HTTP_USER_AGENT']) {
      return false;
    }

    return true;
  }

  static function regenerateSession() {

    // If this session is obsolete, it means that there already is a new id
    if(isset($_SESSION['OBSOLETE']) && $_SESSION['OBSOLETE'] === True) {
      return;
    }

    // Set current session to expire in 10 seconds
    $_SESSION['OBSOLETE'] = True;
    $_SESSION['EXPIRES'] = time() + 10;

    // Create new session without destroying the old one
    session_regenerate_id(false);

    // Grab current session ID and close both sessions to allow other scripts to use them
    $newSession = session_id();
    session_write_close();

    // Set session ID to the new one and start it back up again
    session_id($newSession);
    session_start();

    // Now we unset the obsolete and expiration values for the session we want to keep
    unset($_SESSION['OBSOLETE']);
    unset($_SESSION['EXPIRES']);
  }

  static protected function validateSession() {
    // Check if something went wrong
    if(isset($_SESSION['OBSOLETE']) && !isset($_SESSION['EXPIRES'])) {
      return false;
    }

    // Test if this is an old session which has expired
    if(isset($_SESSION['EXPIRES']) && $_SESSION['EXPIRES'] < time()) {
      return false;
    }

    // Check if the user's login has timed out
    if(isset($_SESSION['LAST_ACTIVITY']) && (time() - $_SESSION['LAST_ACTIVITY']) > self::$timeout) {
      return false;
    }

    return true;
  }
}
?>
  • 写回答

1条回答 默认 最新

  • dsjklb0205 2013-09-05 17:22
    关注

    I could be way out here (it's been a while) but that sounds like the buffer containing the headers isn't being flushed for some reason. Providing body would force them to be flushed, so maybe not providing the body doesn't flush?

    Try putting ob_end_flush(); in there before you return. That may fix it.

    评论

报告相同问题?

悬赏问题

  • ¥15 基于卷积神经网络的声纹识别
  • ¥15 Python中的request,如何使用ssr节点,通过代理requests网页。本人在泰国,需要用大陆ip才能玩网页游戏,合法合规。
  • ¥100 为什么这个恒流源电路不能恒流?
  • ¥15 有偿求跨组件数据流路径图
  • ¥15 写一个方法checkPerson,入参实体类Person,出参布尔值
  • ¥15 我想咨询一下路面纹理三维点云数据处理的一些问题,上传的坐标文件里是怎么对无序点进行编号的,以及xy坐标在处理的时候是进行整体模型分片处理的吗
  • ¥15 CSAPPattacklab
  • ¥15 一直显示正在等待HID—ISP
  • ¥15 Python turtle 画图
  • ¥15 stm32开发clion时遇到的编译问题