NYCPHP Meetup

NYPHP.org

[nycphp-talk] Experts help needed (Sessions)

Dan Cech dcech at phpwerx.net
Tue Aug 2 09:32:52 EDT 2005


Joseph,

Your code is tied into all kinds of knots, you need to strip out all the 
extra cruft and get it working right before you add all the features for 
user icons etc, or even better add them in a subclass.

Now, the reason your IP checking is not working is this:

In your init() function you set:

$this->_ip = $_SERVER['REMOTE_ADDR'];

then you call CheckIp() which tests:

strcmp($this->_ip,$_SERVER['REMOTE_ADDR'])

Of course this will always be true.

You need to do your IP checking in or after the read function, not 
before, because until it is read you don't know the previous IP.

On a side note IP checking isn't a great security measure because it 
will cause problems for anyone whose IP is likely to change during a 
session, such as AOL users, etc.

Dan

Joseph Crawford wrote:
> Guys,
> 
> I have the following code in use however people can easilly hijack sessions 
> i am not sure why but when a session is hijacked the IP address in the 
> database changes, yet the session values are retained. Here is the code.
> 
> 
> 
> <?php
> 
> class session
> {
> /* Define the mysql table you wish to use with
> this class, this table MUST exist. */
> private $table = "sessions";
> private $_db;
> private $_page;
> private $_sess_id;
> private $_ip;
> private $_browser;
> private $_browserList;
> private $_os;
> private $_osList;
> static private $_type;
> private $_typeIcon;
> 
> 
> public function __construct(Database $db) {
> $this->_db = $db;
> 
> $this->_browserList = array('offbyone' => 'ob1.gif', '3b_web' => '3b.gif', 
> 'getrig' => 'get.gif', 'webtv' => 'webtv.gif', 'aol' => 'aol.gif', 'opera' 
> => 'opera.gif', 'netposit' => 'netp.gif', 'ibrowse' => 'ibrowse.gif', 
> 'abrowse' => 'abrowse.gif', 'firefox' => 'firefox.gif', 'firebird' => '
> firebird.gif', 'phoenix' => 'firebird.gif', 'omniweb' => 'omni.gif', 
> 'safari' => 'safari.gif', 'camino' => 'camino.gif', 'chimera' => 'camino.gif', 
> 'konqueror' => 'konq.gif', 'icab' => 'icab.gif', 'dillo' => 'dillo.gif', 
> 'epiphany' => 'epiph.gif', 'oregano' => 'oregano.gif', 'k-meleon' => '
> kmel.gif', 'webcapture' => 'webcap.gif', 'galeon' => 'galeon.gif', 'lynx' => 
> 'lynx.gif', 'netscape' => 'netscape.gif', 'entergy' => 'entergy.gif', 'msie' 
> => 'ie.gif', 'mozilla' => 'moz.gif');
> $this->_osList = array('linspire' => 'linspire.gif', 'lindows' => '
> linspire.gif', 'beos' => 'beos.gif', 'skyos' => 'skyos.gif', 'atheos' => '
> athe.gif', 'palmos' => 'palm.gif', 'nokia' => 'nokia.gif', 'blackberry' => '
> blackb.gif', 'zeta' => 'zeta.gif', 'irix' => 'irix.gif', 'risc' => '
> riscos.gif', 'os/2' => 'os2.gif', 'amigaos' => 'amiga.gif', 'freebsd' => '
> fbsd.gif', 'netbsd' => 'nbsd.gif', 'sunos' => 'solaris.gif', 'solaris' => '
> solaris.gif', 'os x' => 'osx.gif', 'osx' => 'osx.gif', 'darwin' => 'osx.gif', 
> 'macintosh' => 'macintosh.gif', 'mac_' => 'macintosh.gif', 'qnx' => 'qnx.gif', 
> 'linux' => 'linux.gif', 'unix' => 'unix.gif', 'x11' => 'x11.gif', 'windows' 
> => 'windows.gif', 'win95' => 'windows.gif', 'win98' => 'windows.gif', 
> 'winnt' => 'windows.gif');
> self::setType();
> }
> 
> private function init() {
> if(!isset($this->_sess_id)) $this->_sess_id = session_id();
> $this->_page = $_SERVER['REQUEST_URI'];
> if(!isset($this->_ip)) $this->_ip = $_SERVER['REMOTE_ADDR'];
> if(!isset($this->_typeIcon)) $this->setUserIcon();
> if(!isset($this->_browser)) $this->setUserBrowser();
> if(!isset($this->_os)) $this->setUserOS();
> 
> $this->CheckIP();
> }
> 
> public function open($path, $name) {
> 
> return TRUE;
> }
> 
> /* Close session */
> public function close() {
> /* This is used for a manual call of the
> session gc function */
> $this->gc(0);
> return TRUE;
> }
> 
> /* Read session data from database */
> public function read($ses_id) {
> 
> $session_sql = "SELECT * FROM " . $this->table
> . " WHERE ses_id = '$ses_id'";
> 
> $session_res = $this->_db->Query($session_sql);
> if (!$session_res) {
> return '';
> }
> 
> $session_num = $this->_db->NumRows($session_res);
> if ($session_num > 0) {
> $session_row = $this->_db->FetchArray($session_res);
> $ses_data = $session_row["ses_value"];
> return $ses_data;
> } else {
> return '';
> }
> }
> 
> /* Write new data to database */
> public function write($ses_id, $data) {
> $this->init();
> $session_sql = "
> INSERT INTO "
> .$this->table." (ses_id, type, typeicon, ses_time, ses_start, page, ip, 
> browser, os, ses_value)
> VALUES 
> ('".$ses_id."', '".self::$_type."', '".$this->_typeIcon."', ".time().", 
> ".time().", '".$this->_page."', '".$this->_ip."', '".$this->_browser."', 
> '".$this->_os."', '".$data."') 
> ON DUPLICATE KEY UPDATE 
> type='".self::$_type."', typeicon='".$this->_typeIcon."', 
> ses_time=".time().", page='".$this->_page."', ses_value='".$data."'";
> $session_res = $this->_db->Query($session_sql);
> if (!$session_res) return FALSE;
> else return TRUE;
> 
> }
> 
> /* Destroy session record in database */
> public function destroy($ses_id) {
> $session_sql = "DELETE FROM " . $this->table
> . " WHERE ses_id = '$ses_id'";
> 
> $session_res = $this->_db->Query($session_sql);
> if (!$session_res) return FALSE;
> else return TRUE;
> }
> 
> /* Garbage collection, deletes old sessions */
> public function gc($life) {
> $ses_life = strtotime("-5 minutes");
> 
> $session_sql = "DELETE FROM " . $this->table
> . " WHERE ses_time < $ses_life";
> 
> $session_res = $this->_db->Query($session_sql);
> 
> 
> if (!$session_res) return FALSE;
> else return TRUE;
> }
> 
> private function CheckIP() {
> echo '<br>'.$this->_ip.'<br>';
> echo $_SERVER['REMOTE_ADDR'];
> if( strcmp($this->_ip, $_SERVER['REMOTE_ADDR']) ) {
> echo 'YOU HAVE HIJACKED A SESSION, SESSION DESTROYED!';
> $sess_sql = "DELETE FROM ".$this->table." WHERE 
> ses_id='".$this->_sess_id."'";
> $this->_db->Query($sess_sql);
> session_destroy();
> }
> }
> 
> private function setUserIcon() {
> switch(self::$_type) {
> case 'AD':
> $this->_typeIcon .= 'images/icons/user/admin.png';
> break;
> case 'CL':
> $this->_typeIcon .= 'images/icons/user/client.png';
> break;
> case 'CO':
> $this->_typeIcon .= 'images/icons/user/contractor.png';
> break;
> default:
> $this->_typeIcon .= 'images/icons/user/guest.png';
> }
> }
> 
> private function setUserBrowser() {
> foreach ($this->_browserList as $browser => $img) {
> if(stristr($_SERVER['HTTP_USER_AGENT'], $browser)) {
> $this->_browser .= 'images/icons/browser/'.$img;
> break;
> }
> }
> }
> 
> private function setUserOS() {
> foreach ($this->_osList as $os => $img) {
> if(stristr($_SERVER['HTTP_USER_AGENT'], $os)) {
> $this->_os .= 'images/icons/os/'.$img;
> break;
> }
> }
> }
> 
> static public function setType( $type = 'GU' ) {
> $type = substr($type, 0, 2);
> if(isset($type) && is_string($type) && strlen($type) == 2) self::$_type = 
> strtoupper($type);
> }
> }
> ?>
> 
> you can see that you can hijack a session by going to this page
> 
> http://codebowl.homelinux.net:8001/csaf/test.php?PHPSESSID=0615292083a9ea7010f1fe935597751e
> 
> you can also use a browser to open the page and create a session, then open 
> a different browser like IE or Firefox (but not the same browser) and hijack 
> your own session, as i have the page printing the session id so you can get 
> it.
> 
> I am not sure why when a session is hijacked the IP in the database is 
> updated, this should not be the case. The SQL query i have in my write 
> method should not do anything but insert or update if it exists.
> 
> Any help i would really appreciate. I like the flexibility of sessions in 
> the database but i dont like the idea of how easy it is to hijack the 
> session without the system noticing and destroying it.
> 
> 
> 
> ------------------------------------------------------------------------
> 
> _______________________________________________
> New York PHP Talk Mailing List
> AMP Technology
> Supporting Apache, MySQL and PHP
> http://lists.nyphp.org/mailman/listinfo/talk
> http://www.nyphp.org




More information about the talk mailing list