veiligheid van $_SESSION variables
Voor het inloggen op mijn site maak ik gebruik van een PHP session.
Als de variabele $_SESSION['usr_userid'] is ingesteld, ben je ingelogd en heb je dus toegang tot extra pagina's.
Hoe veilig is zo'n systeem? Is het makkelijk te kraken en hoe zou ik het veiliger kunnen maken?
Graag wat tips.
Bedankt!
Het gevaar ligt er in dat iemand de SESSION_ID mogelijk kan kopieren, en in aan zijn eigen browser kan toevoegen als cookie. Wanneer deze persoon nu naar jou website gaat, denkt PHP dat het dezelfde bezoeker betreft, omdat deze alleen de SESSION_ID als referentie heeft.
Deze 'feature' noemen we 'session hijacking'.
Wat te doen:
Wat ik standaard doe is o.a. het IP adres & user agent van de gebruiker koppelen aan de betreffende sessie. Wanneer óf het IP, óf de user agent veranderd, reset ik de sessie. Nadeel van deze aanpak is dat iemand met een wisselend IP adres mogelijk opnieuw moet inloggen.
Hier wat PHP code die je inspiratie kan bieden:
Code (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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
<?php
// Define urls & paths
define('ROOT_URL', 'http://www.domainname.tld/';
define('ROOT_PATH', dirname(__FILE__) . '/');
define('SESSION_PATH', ROOT_PATH . 'sessions/');
// Update session path
session_save_path(SESSION_PATH);
// Validate & start session
function __session_start()
{
$sSessionId = __session_start_id();
session_id($sSessionId);
session_start();
// Validate session
if(isset($_SESSION['session']))
{
if($_SESSION['session']['REMOTE_ADDR'] && (strcmp($_SESSION['session']['REMOTE_ADDR'], $_SERVER['REMOTE_ADDR']) !== 0)) // IP has changed during session
{
session_write_close();
$sSessionId = __session_start_id(false); // Force a new ID
session_id($sSessionId);
session_start();
$_SESSION['session'] = array();
$_SESSION['session']['ROOT_URL'] = ROOT_URL;
$_SESSION['session']['REMOTE_ADDR'] = false; // No IP/SESSION lock
$_SESSION['session']['HTTP_USER_AGENT'] = (isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '');
$_SESSION['session']['HTTP_X_FORWARDED_FOR'] = (isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : '');
die('<p>Your IP has changed during your session! As a protection against <a href="http://en.wikipedia.org/wiki/Session_hijacking" target="_blank">session hijacking</a> your session data is erased!</p><p>Your session is no longer chained to your IP, so it can support multiple IP addresses from now on.</p><p><a href="' . escapeHtml(ROOT_URL) . '">Please continue</a></p>');
}
elseif((isset($_GET['core']['session']) && (strcasecmp($_GET['core']['session'], 'reset') === 0)) || (strcmp($_SESSION['session']['ROOT_URL'], ROOT_URL) !== 0) || (strcmp($_SESSION['session']['HTTP_USER_AGENT'], (isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '')) !== 0) || (strcmp($_SESSION['session']['HTTP_X_FORWARDED_FOR'], (isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : '')) !== 0))
{
session_write_close();
$sSessionId = __session_start_id(false); // Force a new ID
session_id($sSessionId);
session_start();
$_SESSION['session'] = array();
$_SESSION['session']['ROOT_URL'] = ROOT_URL;
$_SESSION['session']['REMOTE_ADDR'] = $_SERVER['REMOTE_ADDR'];
$_SESSION['session']['HTTP_USER_AGENT'] = (isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '');
$_SESSION['session']['HTTP_X_FORWARDED_FOR'] = (isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : '');
}
}
else
{
$_SESSION['session'] = array();
$_SESSION['session']['ROOT_URL'] = ROOT_URL;
$_SESSION['session']['REMOTE_ADDR'] = $_SERVER['REMOTE_ADDR'];
$_SESSION['session']['HTTP_USER_AGENT'] = (isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '');
$_SESSION['session']['HTTP_X_FORWARDED_FOR'] = (isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : '');
}
}
// Lookup session id (or generate a new one)
function __session_start_id($bRestoreSession = true)
{
$sSessionName = session_name();
do
{
$sSessionId = randomCode(64, false, true); // Generate unique ID, hexadecimal
}
while(file_exists(session_save_path() . '/sess_' . $sSessionId));
if($bRestoreSession) // Try to restore session
{
if(isset($_GET[$sSessionName]))
{
if(preg_match('/^[0-9a-fA-F]{64,64}$/', $_GET[$sSessionName]))
{
$sSessionId = $_GET[$sSessionName];
}
else
{
unset($_GET[$sSessionName]);
}
}
if(isset($_COOKIE[$sSessionName]))
{
if(preg_match('/^[0-9a-fA-F]{64,64}$/', $_COOKIE[$sSessionName]))
{
$sSessionId = $_COOKIE[$sSessionName];
}
else
{
unset($_COOKIE[$sSessionName]);
}
}
}
else
{
unset($_GET[$sSessionName]);
unset($_COOKIE[$sSessionName]);
}
return $sSessionId;
}
// Create a random code with N digits.
function randomCode($iLength = 64, $bUserFriendly = false, $bHex = false)
{
if($bUserFriendly)
{
/*
Some fonts use (almost) the same symbols for 'i', 'l' and 'one', same goes for 'o' and 'zero'.
That's why we removed these characters from the characterlist (UPPERCASE + lowercase).
*/
if($bHex)
{
$aCharacters = array('a', 'b', 'c', 'd', 'c', 'd', 'e', 'f', 'A', 'B', 'C', 'D', 'E', 'F', '2', '3', '4', '5', '6', '7', '8', '9');
}
else
{
$aCharacters = array('a', 'b', 'c', 'd', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '2', '3', '4', '5', '6', '7', '8', '9');
}
}
else
{
if($bHex)
{
$aCharacters = array('a', 'b', 'c', 'd', 'c', 'd', 'e', 'f', 'A', 'B', 'C', 'D', 'E', 'F', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9');
}
else
{
$aCharacters = array('a', 'b', 'c', 'd', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9');
}
}
$sResult = '';
for($i = 0; $i < $iLength; $i++) // (62 ^ [$digits] mogelijke codes)
{
$sResult .= $aCharacters[rand(0, sizeof($aCharacters) - 1)];
}
return $sResult;
}
?>
// Define urls & paths
define('ROOT_URL', 'http://www.domainname.tld/';
define('ROOT_PATH', dirname(__FILE__) . '/');
define('SESSION_PATH', ROOT_PATH . 'sessions/');
// Update session path
session_save_path(SESSION_PATH);
// Validate & start session
function __session_start()
{
$sSessionId = __session_start_id();
session_id($sSessionId);
session_start();
// Validate session
if(isset($_SESSION['session']))
{
if($_SESSION['session']['REMOTE_ADDR'] && (strcmp($_SESSION['session']['REMOTE_ADDR'], $_SERVER['REMOTE_ADDR']) !== 0)) // IP has changed during session
{
session_write_close();
$sSessionId = __session_start_id(false); // Force a new ID
session_id($sSessionId);
session_start();
$_SESSION['session'] = array();
$_SESSION['session']['ROOT_URL'] = ROOT_URL;
$_SESSION['session']['REMOTE_ADDR'] = false; // No IP/SESSION lock
$_SESSION['session']['HTTP_USER_AGENT'] = (isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '');
$_SESSION['session']['HTTP_X_FORWARDED_FOR'] = (isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : '');
die('<p>Your IP has changed during your session! As a protection against <a href="http://en.wikipedia.org/wiki/Session_hijacking" target="_blank">session hijacking</a> your session data is erased!</p><p>Your session is no longer chained to your IP, so it can support multiple IP addresses from now on.</p><p><a href="' . escapeHtml(ROOT_URL) . '">Please continue</a></p>');
}
elseif((isset($_GET['core']['session']) && (strcasecmp($_GET['core']['session'], 'reset') === 0)) || (strcmp($_SESSION['session']['ROOT_URL'], ROOT_URL) !== 0) || (strcmp($_SESSION['session']['HTTP_USER_AGENT'], (isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '')) !== 0) || (strcmp($_SESSION['session']['HTTP_X_FORWARDED_FOR'], (isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : '')) !== 0))
{
session_write_close();
$sSessionId = __session_start_id(false); // Force a new ID
session_id($sSessionId);
session_start();
$_SESSION['session'] = array();
$_SESSION['session']['ROOT_URL'] = ROOT_URL;
$_SESSION['session']['REMOTE_ADDR'] = $_SERVER['REMOTE_ADDR'];
$_SESSION['session']['HTTP_USER_AGENT'] = (isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '');
$_SESSION['session']['HTTP_X_FORWARDED_FOR'] = (isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : '');
}
}
else
{
$_SESSION['session'] = array();
$_SESSION['session']['ROOT_URL'] = ROOT_URL;
$_SESSION['session']['REMOTE_ADDR'] = $_SERVER['REMOTE_ADDR'];
$_SESSION['session']['HTTP_USER_AGENT'] = (isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '');
$_SESSION['session']['HTTP_X_FORWARDED_FOR'] = (isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : '');
}
}
// Lookup session id (or generate a new one)
function __session_start_id($bRestoreSession = true)
{
$sSessionName = session_name();
do
{
$sSessionId = randomCode(64, false, true); // Generate unique ID, hexadecimal
}
while(file_exists(session_save_path() . '/sess_' . $sSessionId));
if($bRestoreSession) // Try to restore session
{
if(isset($_GET[$sSessionName]))
{
if(preg_match('/^[0-9a-fA-F]{64,64}$/', $_GET[$sSessionName]))
{
$sSessionId = $_GET[$sSessionName];
}
else
{
unset($_GET[$sSessionName]);
}
}
if(isset($_COOKIE[$sSessionName]))
{
if(preg_match('/^[0-9a-fA-F]{64,64}$/', $_COOKIE[$sSessionName]))
{
$sSessionId = $_COOKIE[$sSessionName];
}
else
{
unset($_COOKIE[$sSessionName]);
}
}
}
else
{
unset($_GET[$sSessionName]);
unset($_COOKIE[$sSessionName]);
}
return $sSessionId;
}
// Create a random code with N digits.
function randomCode($iLength = 64, $bUserFriendly = false, $bHex = false)
{
if($bUserFriendly)
{
/*
Some fonts use (almost) the same symbols for 'i', 'l' and 'one', same goes for 'o' and 'zero'.
That's why we removed these characters from the characterlist (UPPERCASE + lowercase).
*/
if($bHex)
{
$aCharacters = array('a', 'b', 'c', 'd', 'c', 'd', 'e', 'f', 'A', 'B', 'C', 'D', 'E', 'F', '2', '3', '4', '5', '6', '7', '8', '9');
}
else
{
$aCharacters = array('a', 'b', 'c', 'd', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '2', '3', '4', '5', '6', '7', '8', '9');
}
}
else
{
if($bHex)
{
$aCharacters = array('a', 'b', 'c', 'd', 'c', 'd', 'e', 'f', 'A', 'B', 'C', 'D', 'E', 'F', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9');
}
else
{
$aCharacters = array('a', 'b', 'c', 'd', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9');
}
}
$sResult = '';
for($i = 0; $i < $iLength; $i++) // (62 ^ [$digits] mogelijke codes)
{
$sResult .= $aCharacters[rand(0, sizeof($aCharacters) - 1)];
}
return $sResult;
}
?>
Gewijzigd op 01/01/1970 01:00:00 door Martijn Wieringa
Zijn er verder nog problemen waar ik rekening mee moet houden?
@Pholeron; bedankt, die methode gebruik ik zelf ook maar die user agent is nog een goede toevoeging :)
Graag gedaan :)