diff options
Diffstat (limited to 'Zotlabs/Web')
-rw-r--r-- | Zotlabs/Web/Session.php | 160 | ||||
-rw-r--r-- | Zotlabs/Web/SessionHandler.php | 88 |
2 files changed, 248 insertions, 0 deletions
diff --git a/Zotlabs/Web/Session.php b/Zotlabs/Web/Session.php new file mode 100644 index 000000000..55536fdc7 --- /dev/null +++ b/Zotlabs/Web/Session.php @@ -0,0 +1,160 @@ +<?php + +namespace Zotlabs\Web; + +/** + * + * @brief This file includes session related functions. + * + * Session management functions. These provide database storage of PHP + * session info. + */ + + +class Session { + + private static $handler = null; + private static $session_started = false; + + function init() { + + $gc_probability = 50; + + ini_set('session.gc_probability', $gc_probability); + ini_set('session.use_only_cookies', 1); + ini_set('session.cookie_httponly', 1); + + /* + * Set our session storage functions. + */ + + $handler = new \Zotlabs\Web\SessionHandler(); + self::$handler = $handler; + + $x = session_set_save_handler($handler,true); + if(! $x) + logger('Session save handler initialisation failed.',LOGGER_NORMAL,LOG_ERR); + + // Force cookies to be secure (https only) if this site is SSL enabled. + // Must be done before session_start(). + + $arr = session_get_cookie_params(); + session_set_cookie_params( + ((isset($arr['lifetime'])) ? $arr['lifetime'] : 0), + ((isset($arr['path'])) ? $arr['path'] : '/'), + ((isset($arr['domain'])) ? $arr['domain'] : App::get_hostname()), + ((isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on') ? true : false), + ((isset($arr['httponly'])) ? $arr['httponly'] : true) + ); + } + + function start() { + session_start(); + self::$session_started = true; + } + + /** + * @brief Resets the current session. + * + * @return void + */ + + function nuke() { + self::new_cookie(0); // 0 means delete on browser exit + if($_SESSION && count($_SESSION)) { + foreach($_SESSION as $k => $v) { + unset($_SESSION[$k]); + } + } + } + + function new_cookie($xtime) { + + $newxtime = (($xtime> 0) ? (time() + $xtime) : 0); + + $old_sid = session_id(); + + if(self::$handler && self::$session_started) { + session_regenerate_id(true); + + // force SessionHandler record creation with the new session_id + // which occurs as a side effect of read() + + self::$handler->read(session_id()); + } + else + logger('no session handler'); + + if (x($_COOKIE, 'jsAvailable')) { + setcookie('jsAvailable', $_COOKIE['jsAvailable'], $newxtime); + } + setcookie(session_name(),session_id(),$newxtime); + + $arr = array('expire' => $xtime); + call_hooks('new_cookie', $arr); + + } + + function extend_cookie() { + + // if there's a long-term cookie, extend it + + $xtime = (($_SESSION['remember_me']) ? (60 * 60 * 24 * 365) : 0 ); + + if($xtime) + setcookie(session_name(),session_id(),(time() + $xtime)); + $arr = array('expire' => $xtime); + call_hooks('extend_cookie', $arr); + + } + + + function return_check() { + + // check a returning visitor against IP changes. + // If the change results in being blocked from re-entry with the current cookie + // nuke the session and logout. + // Returning at all indicates the session is still valid. + + // first check if we're enforcing that sessions can't change IP address + // @todo what to do with IPv6 addresses + + if($_SESSION['addr'] && $_SESSION['addr'] != $_SERVER['REMOTE_ADDR']) { + logger('SECURITY: Session IP address changed: ' . $_SESSION['addr'] . ' != ' . $_SERVER['REMOTE_ADDR']); + + $partial1 = substr($_SESSION['addr'], 0, strrpos($_SESSION['addr'], '.')); + $partial2 = substr($_SERVER['REMOTE_ADDR'], 0, strrpos($_SERVER['REMOTE_ADDR'], '.')); + + $paranoia = intval(get_pconfig($_SESSION['uid'], 'system', 'paranoia')); + + if(! $paranoia) + $paranoia = intval(get_config('system', 'paranoia')); + + switch($paranoia) { + case 0: + // no IP checking + break; + case 2: + // check 2 octets + $partial1 = substr($partial1, 0, strrpos($partial1, '.')); + $partial2 = substr($partial2, 0, strrpos($partial2, '.')); + if($partial1 == $partial2) + break; + case 1: + // check 3 octets + if($partial1 == $partial2) + break; + case 3: + default: + // check any difference at all + logger('Session address changed. Paranoid setting in effect, blocking session. ' + . $_SESSION['addr'] . ' != ' . $_SERVER['REMOTE_ADDR']); + self::nuke(); + goaway(z_root()); + break; + } + } + return true; + } + +} diff --git a/Zotlabs/Web/SessionHandler.php b/Zotlabs/Web/SessionHandler.php new file mode 100644 index 000000000..6980a6408 --- /dev/null +++ b/Zotlabs/Web/SessionHandler.php @@ -0,0 +1,88 @@ +<?php + +namespace Zotlabs\Web; + + +class SessionHandler implements \SessionHandlerInterface { + + + function open ($s, $n) { + return true; + } + + // IMPORTANT: if we read the session and it doesn't exist, create an empty record. + // We rely on this due to differing PHP implementation of session_regenerate_id() + // some which call read explicitly and some that do not. So we call it explicitly + // just after sid regeneration to force a record to exist. + + function read ($id) { + + if($id) { + $r = q("SELECT `data` FROM `session` WHERE `sid`= '%s'", dbesc($id)); + + if($r) { + return $r[0]['data']; + } + else { + q("INSERT INTO `session` (sid, expire) values ('%s', '%s')", + dbesc($id), + dbesc(time() + 300) + ); + } + } + + return ''; + } + + + function write ($id, $data) { + + if(! $id || ! $data) { + return false; + } + + // Unless we authenticate somehow, only keep a session for 5 minutes + // The viewer can extend this by performing any web action using the + // original cookie, but this allows us to cleanup the hundreds or + // thousands of empty sessions left around from web crawlers which are + // assigned cookies on each page that they never use. + + $expire = time() + 300; + + if($_SESSION) { + if(array_key_exists('remember_me',$_SESSION) && intval($_SESSION['remember_me'])) + $expire = time() + (60 * 60 * 24 * 365); + elseif(local_channel()) + $expire = time() + (60 * 60 * 24 * 3); + elseif(remote_channel()) + $expire = time() + (60 * 60 * 24 * 1); + } + + q("UPDATE `session` + SET `data` = '%s', `expire` = '%s' WHERE `sid` = '%s'", + dbesc($data), + dbesc($expire), + dbesc($id) + ); + + return true; + } + + + function close() { + return true; + } + + + function destroy ($id) { + q("DELETE FROM `session` WHERE `sid` = '%s'", dbesc($id)); + return true; + } + + + function gc($expire) { + q("DELETE FROM session WHERE expire < %d", dbesc(time())); + return true; + } + +} |