我正在编写一个简单的网站,允许用户登录,填写提交到数据库的表单,然后注销。为了管理会话,我使用了 TreeHouse 在以下页面上描述的会话管理器:http: //blog.teamtreehouse.com/how-to-create-bulletproof-sessions
为了防止劫持,客户端的 IP 地址和用户代理存储在会话变量中,并与每个页面上这些属性的服务器值进行比较。如果它们不匹配,则假定会话已被劫持并被重置。
该实现似乎在我的本地机器上运行没有任何问题,但是当我将它上传到服务器时,每次页面刷新都会导致 preventHijacking() 函数返回 false(这意味着它认为会话已被劫持)。但是,如果我在该函数中回显任何文本,问题就会神秘地消失,整个事情都会按我的预期工作(除了现在显示在我的表单上方的回显文本位:P)。
我不知道为什么会这样,我不知道如何解决它。会话管理器代码如下。在每个页面的开头,我使用它来启动会话,然后每个页面简单地使用或设置它需要的任何变量。如果有人能建议为什么函数总是返回 false 除非它回显文本,并且可能建议我需要进行哪些修改以使其以预期的方式运行,我将非常感激。
<?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;
}
}
?>