[PHP] Sessions & browser refreshing

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Ik heb een tijd terug een authenticatie systeem gemaakt dat per page-refresh de session id refreshed. het probleem is aleen dat als een gebruiker te snel op refresh ramt de browser niet optijd de nieuwe cookie geset krijgt en de session dus verloren gaat.

Dit is de hoofdklasse die de sessies afhandeld.
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
<?PHP   
    // The session cookie can only be accessed by the http protocol
    ini_set('session.cookie_httponly',1);
    // The session id is only retrieved trought the PHPSESSID cookie variable
    ini_set('session.use_only_cookies',1);
    
    class session {
        
        var $_adapter;
        var $_requestToken;
        var $_sessionToken;
        var $_isNewSession;
        var $_callBackQue;
        
        var $onValid;
        var $onRecover;
        var $onNew;
        var $onIdentityValid;
        var $onIdentityInvalid;
        
        function session($vars){
            $this->_parseVars($vars);
            
            $this->_sessionStart();

            $this->getSessionToken();
            $this->getRequestToken();

            if ( !$this->_isNewSession() ) {
                if ( !$this->validSession() ) $this->_placeInQue($this->onRecover); 
                else $this->_placeInQue($this->onValid); 
            }
            else $this->_placeInQue($this->onNew); 
            
            $oldSession = $_SESSION;
            
            $oldSessionId = session_id();
            
            session_regenerate_id();
            $newSessionId = session_id();
            
            session_id($oldSessionId);
            session_destroy();
            
            session_id($newSessionId);
            session_start();            
            
            $_SESSION = $oldSession;
            
        }
        
        function _sessionStart(){
            if ( strlen ( session_id() ) === 0 ) {
                session_start();
            }
        }
        
        function getSessionToken() {
            if ( $this->_isNewSession() ) {
                $this->_sessionToken = md5 ( $_SERVER['HTTP_USER_AGENT'] );
                $_SESSION['AUTH']['TOKEN'] = $this->_sessionToken;
            }
            else {
                $this->_sessionToken = $_SESSION['AUTH']['TOKEN'];
            }
            return $this->_sessionToken;
        }
        
        function getRequestToken() {
            if ( !$this->_requestToken ) {
                $this->_requestToken = md5 ( $_SERVER['HTTP_USER_AGENT'] );
            }
            return $this->_requestToken;
        }
        
        function _isNewSession() {
    
            if ( empty( $this->_isNewSession ) ) {
                if ( !isset ( $_SESSION['AUTH']['NEW'] ) ) {
                    $this->_isNewSession = true;
                    $_SESSION['AUTH']['NEW'] = false;
                }
                else {
                    $this->_isNewSession = false;
                }
            }
            return $this->_isNewSession;
        }
        
        function validSession() {
            if ( $this->getRequestToken() === $this->getSessionToken() ) return true;
            else return false;          
        }
        
        function _placeInQue($callback) {
            $this->_callBackQue[] = $callback;
        }
        
        function execCallbackQue() {
            foreach ( $this->_callBackQue as $callback ) {
                $this->_callFuncIfExists($callback);
            }
        }
        
        function _callFuncIfExists($function) {
            if ( function_exists ( $function ) ) call_user_func( $function );
        }
        
        function _parseVars($vars) {
            foreach ( $vars as $key => $value ) {
                $this->{$key} = $value;
            }
        }
        
        function forgetMe() {
            setcookie(session_name(), session_id(), time()-42000, '/');
            session_destroy();
        }
        
        function validate($adapter) {
            $this->_adapter = $adapter;
            if ( !$this->_adapter->validate() ) {
                $this->_placeInQue($this->onIdentityInvalid);
            }
            else {
                $this->_placeInQue($this->onIdentityValid);
            }
        }
    }
?>


De adapter klasse is alleen implementatie logic, deze implementeerd een getIdentity method die een array met username en password terug geeft en een validate method die zoals de naam zegt true of false geeft.

Ik heb een packet sniffer tussen mij en de webserver geplaatst om de php session id's op te vangen en de sessionid gaat inderdaad fout als ik te snel refresh.

Heeft iemand hier ook ervaring mee of een workaround?

Acties:
  • 0 Henk 'm!

  • Voutloos
  • Registratie: Januari 2002
  • Niet online
Maar waarom moet die session dan steeds vervangen worden? Je probeert nu een probleem (welk?) op met een verkeerde methode op de verkeerde plek op te lossen. ;)

{signature}


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
ik wil gewoon dat de phpsessid variable vervangen word per request. Welke verkeerde methode gebruik ik?

Acties:
  • 0 Henk 'm!

  • T-MOB
  • Registratie: Maart 2001
  • Nu online
Voutloos vraagt waarom je dat wil, wat wil je bereiken?

Regeren is vooruitschuiven


Acties:
  • 0 Henk 'm!

  • Voutloos
  • Registratie: Januari 2002
  • Niet online
'Gewoon' is geen antwoord op mijn vraag. Vertel me maar welk veiligheidsprobleem (neem ik aan) je specifiek wil oplossen en waarom dit volgens jou de beste of enige methode is.

{signature}


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Excuus had de vraag niet goed gelezen. Ik wilde testen of ik zelf een mooie oplossing voor session prediction kon programeren. Ik heb dus op de achtergrond de random functie van php op een wat krachtigere Random number generator aangesloten.

Verder word ook de user-agent gecontroleerd.

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Okee ik heb de oplossing gevonden:

Dit was de responseheader van de server:
HTTP:
1
2
3
4
5
6
7
8
9
10
11
HTTP/1.1 200 OK
Date: Thu, 03 Apr 2008 10:53:49 GMT
Server: Apache/2.2.6 (FreeBSD) mod_ssl/2.2.6 OpenSSL/0.9.7e-p1 DAV/2
X-Powered-By: PHP/5.2.5
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Set-Cookie: PHPSESSID=kqqn6dba7c72edlfo9vincbja2; path=/; HttpOnly
Set-Cookie: PHPSESSID=kqqn6dba7c72edlfo9vincbja2; path=/; HttpOnly
Content-Type: text/html; charset=utf8
Content-Length: 5256


Zoals je ziet werd de set-cookie tweemaal verstuurd waardoor in sommige gevallen er geen cookie geset werd op een of andere manier.

Verandering aan de code:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
            $oldSession = $_SESSION;
            
            $oldSessionId = session_id();
            
            session_regenerate_id();
            $newSessionId = session_id();
            
            session_id($oldSessionId);
            session_destroy();
            
            session_id($newSessionId);
            session_start();            
            
            $_SESSION = $oldSession;


word:

PHP:
1
            session_regenerate_id();


De functie session_regenerate_id veranderd al de session id dus eigen code was overbodig.

Acties:
  • 0 Henk 'm!

Verwijderd

Wordt het php script gekilled voordat de de sessie-cookie is geset? Dan is dit mogelijk de oplossing: http://nl.php.net/ignore_user_abort

Acties:
  • 0 Henk 'm!

  • Voutloos
  • Registratie: Januari 2002
  • Niet online
Verwijderd schreef op donderdag 03 april 2008 @ 12:57:
De functie session_regenerate_id veranderd al de session id dus eigen code was overbodig.
Klopt, en er is zelfs een hippe parameter welke je op true kan zetten. :P

Maar goed, deze functie elke keer aanroepen is meestal overkill. Om session fixation tegen te gaan hoef je enkel deze functie te gebruiken tijdens kritieke acties, zoals bijvoorbeeld inloggen. Bijv: een sessie id is reeds bekend voor de anonieme gebruiker en zodra deze inlogt wordt er een andere sessie aangehangen. Op die wijze kan een aanvaller geen constructie maken waar hij jou een sessie id geeft/aansmeert, waar jij vervolgens mee inlogt en welke de aanvaller vervolgens kan gebruiken om zelf ingelogd te zijn.

En die controle op user agent voegt niet zo heel veel toe, want die is te eenvoudig na te doen. Een optie om een sessie aan een ip adres koppelen is bijvoorbeeld al een stuk sterker.

{signature}


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Voutloos schreef op donderdag 03 april 2008 @ 13:20:
En die controle op user agent voegt niet zo heel veel toe, want die is te eenvoudig na te doen. Een optie om een sessie aan een ip adres koppelen is bijvoorbeeld al een stuk sterker.
Dan krijg je gedonder met proxies. Tuurlijk voorkom je het zo niet maar het legt de drempel wel hoger, de hacker moet tussen het slachtoffer en de server kunnen afluisteren naar de user-agent header wil hij een goede replay attack lanceren.

[ Voor 22% gewijzigd door Verwijderd op 03-04-2008 13:24 ]


Acties:
  • 0 Henk 'm!

  • Voutloos
  • Registratie: Januari 2002
  • Niet online
Uiteraard, vandaar dat ik het als optie noemde. Zie het inlogscherm van dit forum. ;) Als je maar weet dat UA niet heilig is.
Verwijderd schreef op donderdag 03 april 2008 @ 13:22:
Tuurlijk voorkom je het zo niet maar het legt de drempel wel hoger, de hacker moet tussen het slachtoffer en de server kunnen afluisteren naar de user-agent header wil hij een goede replay attack lanceren.
Of hij gokt op de meest gebruikte browser en maakt daarmee alsnog een forse kans. Maar het kan geen kwaad richting de reguliere gebruikers, dus van mij mag je oa op deze manier de lat (een paar millimeter) hoger leggen.

En dit is geen replay attack. :P

[ Voor 70% gewijzigd door Voutloos op 03-04-2008 13:27 ]

{signature}

Pagina: 1