reference/session/security.xml
ccb379494533c9b7d63a81f0221231a9e526eee9
...
...
@@ -2,276 +2,777 @@
2
2
<!-- $Revision$ -->
3
3

4
4
<chapter xml:id="session.security" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
5
-
<title>Sessions and security</title>
5
+
<title>Sessions and Security</title>
6
6
<para>
7
7
External links: <link xlink:href="&url.session-fixation;">Session fixation</link>
8
8
</para>
9
9
<para>
10
-
HTTP session management is core of web security. All of mitigation
11
-
should be adopted to make sure session security. Developer should
12
-
enable/use applicable settings appropriately.
10
+
HTTP session management represents the core of web security.
11
+
All possible mitigation measures <emphasis>should</emphasis>
12
+
be adopted to ensure sessions are secured.
13
+
Developers should also enable/use applicable security measures.
13
14
</para>
14
15

15
-
<itemizedlist>
16
-
<listitem>
17
-
<simpara>
18
-
<link linkend="ini.session.cookie-lifetime">session.cookie_lifetime</link>=0.
19
-
0 have special meaning. It tells browsers not to store cookie to
20
-
permanent storage. Therefore, when browser is terminated, session
21
-
ID cookie is deleted immediately. If developer set other than 0, it may
22
-
allow other users to use the session ID. Most applications should
23
-
use "0" for this. If auto login feature is required, implement
24
-
your own secure auto login feature. Do not use session ID for it.
25
-
</simpara>
26
-
</listitem>
27
-

28
-
<listitem>
29
-
<simpara>
30
-
<link linkend="ini.session.use-cookies">session.use_cookies</link>=On and
31
-
<link linkend="ini.session.use-only-cookies">session.use_only_cookies</link>=On.
32
-
Although HTTP cookie has some problems, cookie is preferred way to
33
-
manage session ID. Use only cookies for session ID management when
34
-
it is possible. Most applications should use cookie for session
35
-
ID.
36
-
</simpara>
37
-
</listitem>
38
-

39
-
<listitem>
40
-
<simpara>
41
-
<link linkend="ini.session.use-strict-mode">session.use_strict_mode</link>=On.
42
-
This prevents session module to use uninitialized session ID. In
43
-
other word, session module only accepts valid session ID generated
44
-
by session module. It rejects session ID supplied by
45
-
users. Session ID injection could be done by cookie injection via
46
-
JavaScript permanently or temporarily. When transparent session is
47
-
enabled, session ID could be injected via query string or form
48
-
parameter. There is no reason to accept user supplied session ID,
49
-
most applications must not accept user supplied uninitialized
50
-
session ID.
51
-
</simpara>
52
-
</listitem>
53
-

54
-
<listitem>
55
-
<simpara>
56
-
<link linkend="ini.session.cookie-httponly">session.cookie_httponly</link>=On.
57
-
Disallow access to session cookie by JavaScript. This setting
58
-
prevents cookies stolen by JavaScript injection. It is possible
59
-
to use session ID as CSRF protection key, but this is not
60
-
recommended. For example, HTML source may be saved and sent to
61
-
other users. Developer should not write session ID in web pages for
62
-
better security. Almost all applications must use httponly attribute for
63
-
session ID cookie.
64
-
</simpara>
65
-
</listitem>
66
-

67
-
<listitem>
68
-
<simpara>
69
-
<link linkend="ini.session.cookie-secure">session.cookie_secure</link>=On.
70
-
Allows access to session ID cookie only when protocol is HTTPS. If
71
-
your web site is HTTPS only web site, you must enable this
72
-
setting. Use of HSTS should be considered for HTTPS only web site.
73
-
</simpara>
74
-
</listitem>
75
-

76
-
<listitem>
77
-
<simpara>
78
-
<link linkend="ini.session.gc-maxlifetime">session.gc_maxlifetime</link>=[choose smallest possible].
79
-
GC is performed by probability. This setting does not guarantee old
80
-
session deletion. Some session save handler modules do not use
81
-
this setting. Refer to session save handler documentation for
82
-
details. Although developer cannot rely on this setting, setting this
83
-
to smallest possible value is recommended. Adjust <link
84
-
linkend="ini.session.gc-probability">session.gc_probability</link>
85
-
and <link
86
-
linkend="ini.session.gc-divisor">session.gc_divisor</link> so that
87
-
obsolete sessions are deleted by appropriate frequency. If auto login
88
-
feature is required, implement your own secure auto login feature.
89
-
Do not use long life session ID for it.
90
-
</simpara>
91
-
</listitem>
92
-

93
-
<listitem>
94
-
<simpara>
95
-
<link linkend="ini.session.use-trans-sid">session.use_trans_sid</link>=Off.
96
-
Use of transparent session ID management is not prohibited. You
97
-
may use it when it is needed. However, disabling transparent
98
-
session ID management would improve general session ID security by
99
-
removing possibility of session ID injection and session ID leak.
100
-
</simpara>
101
-
</listitem>
102
-

103
-
<listitem>
104
-
<simpara>
105
-
<link linkend="ini.session.referer-check">session.referer_check</link>=[your originating URL]
106
-
When <link
107
-
linkend="ini.session.use-trans-sid">session.use_trans_sid</link>
108
-
is enabled, use of this setting is recommended if it is
109
-
possible. It reduces risk of session ID injection. If your site is
110
-
http://example.com/, set http://example.com/ to it. Note that when
111
-
HTTPS is used, browser will not send referrer header. Browser may
112
-
not send referrer header by configuration. Therefore, this setting
113
-
is not reliable security measure.
114
-
</simpara>
115
-
</listitem>
116
-

117
-
<listitem>
118
-
<simpara>
119
-
<link linkend="ini.session.cache-limiter">session.cache_limiter</link>=nocache.
120
-
Make sure HTTP contents are not cached for authenticated
121
-
session. Allow caching only when contents is not
122
-
private. Otherwise, contents may be exposed. "private" may be used
123
-
if HTTP content does not include security sensitive data. Note
124
-
that "private" may leave private data cached by shared
125
-
clients. "public" may be used only when HTTP content does not
126
-
contain any private data at all.
127
-
</simpara>
128
-
</listitem>
129
-

130
-
<listitem>
131
-
<simpara>
132
-
<link linkend="ini.session.hash-function">session.hash_function</link>="sha256".
133
-
Stronger hash function will generates stronger session
134
-
ID. Although hash collision is unlikely even with MD5 hash, developers
135
-
should use SHA-2 or later hash functions for the task. Developers may
136
-
use stronger hashes like sha384 and sha512.
137
-
</simpara>
138
-
</listitem>
139
-
</itemizedlist>
16
+
<sect1 xml:id="features.session.security.management">
17
+
<title>Session Management Basics</title>
140
18

141
-
<para>
142
-
The session module cannot guarantee that the information you store
143
-
in a session is only viewed by the user who created the session. You
144
-
need to take additional measures to actively protect the confidentiality
145
-
of the session, depending on the value associated with it.
146
-
</para>
19
+
<sect2 xml:id="features.session.security.management.basic">
20
+
<title>Session Security</title>
147
21

148
-
<para>
149
-
Assess the importance of the data carried by your sessions and
150
-
deploy additional protections -- this usually comes at a price,
151
-
reduced convenience for the user. For example, if you want to
152
-
protect users from simple social engineering tactics, you need to
153
-
enable <literal>session.use_only_cookies</literal>. In that case,
154
-
cookies must be enabled unconditionally on the user side, or
155
-
sessions will not work.
156
-
</para>
22
+
<para>
23
+
The session module can not guarantee that the information stored
24
+
in a session is only viewed by the user who created the session.
25
+
Additional measures are needed to protect the confidentiality
26
+
of the session, depending on the value associated with it.
27
+
</para>
157
28

158
-
<para>
159
-
There are several ways to leak an existing session ID to third
160
-
parties. A leaked session ID enables the third party to access all
161
-
resources which are associated with a specific ID. First, URLs
162
-
carrying session IDs. If you link to an external site, the URL
163
-
including the session id might be stored in the external site's
164
-
referrer logs. Second, a more active attacker might listen to your
165
-
network traffic. If it is not encrypted, session IDs will flow in
166
-
plain text over the network. The solution here is to implement SSL
167
-
on your server and make it mandatory for users. HSTS should be used
168
-
for this.
169
-
</para>
29
+
<para>
30
+
The importance of the data carried in the session needs to be
31
+
assessed and further protection may be deployed; this typically
32
+
comes at a price, such as reduced convenience for the user.
33
+
For example, to protect users from a simple social engineering tactic,
34
+
<link linkend="ini.session.use-only-cookies">session.use_only_cookies</link>
35
+
needs to be enabled. In that case, cookies must be enabled
36
+
unconditionally on the client side, or sessions will not work.
37
+
</para>
170
38

171
-
<para>
172
-
Since PHP 5.5.2, <link
173
-
linkend="ini.session.use-strict-mode">session.use_strict_mode</link>
174
-
is available. When it is enabled and save handler module supports
175
-
it, uninitialized session ID is rejected and new session ID is
176
-
created. This protects attack that force users to use known session
177
-
ID. Attacker may paste links or send mail that contains session
178
-
ID. e.g. http://example.com/page.php?PHPSESSID=123456789 If <link
179
-
linkend="ini.session.use-trans-sid">session.use_trans_sid</link> is
180
-
enabled, victim will start session using attacker provided session
181
-
ID. <link
182
-
linkend="ini.session.use-strict-mode">session.use_strict_mode</link>
183
-
mitigates the risk.
184
-
</para>
39
+
<para>
40
+
There are several ways to leak an existing session ID to third
41
+
parties. E.g. JavaScript injections, session IDs in URLs,
42
+
packet sniffing, physical access to the device, etc.
43
+
A leaked session ID enables the third party to access all
44
+
resources associated with a specific ID. First, URLs carrying
45
+
session IDs. If there are links to an external site or resource,
46
+
the URL including the session ID might be stored in the external
47
+
site's referrer logs. Second, a more active attacker might listen
48
+
to network traffic. If it is unencrypted, session IDs will flow
49
+
in plain text over the network. The solution is to implement
50
+
SSL/TLS on the server and make it mandatory for users.
51
+
HSTS should be used for improved security.
52
+
</para>
185
53

186
-
<para>
187
-
Even though <link
188
-
linkend="ini.session.use-strict-mode">session.use_strict_mode</link>
189
-
mitigates risk of adoptive session management, attacker can force
190
-
users to use initialized session ID which is created by
191
-
attacker. All attacker has to do is initialize session ID prior to
192
-
attack and keep it alive.
193
-
</para>
54
+
<note>
55
+
<simpara>
56
+
Even HTTPS can not protect confidential data at all times.
57
+
For example the CRIME and Beast vulnerabilities may enable an
58
+
attacker to read the data. Also, note that many networks employ
59
+
HTTPS MITM proxies for audit purposes.
60
+
Attackers may also set up such a proxy.
61
+
</simpara>
62
+
</note>
194
63

195
-
<para>
196
-
Session ID cookie could be set with domain, path, httponly, secure
197
-
attributes. There is precedence defined by browsers. By using the
198
-
precedence, attacker can set session ID that could be used
199
-
permanently. Use of <link
200
-
linkend="ini.session.use-only-cookies">session.use_only_cookies</link>
201
-
will not solve this issue. <link
202
-
linkend="ini.session.use-strict-mode">session.use_strict_mode</link>
203
-
mitigates this risk. With <link
204
-
linkend="ini.session.use-strict-mode">session.use_strict_mode</link>=On,
205
-
uninitialized session ID will not be accepted. Session module
206
-
creates new session ID always when session ID is not initialized by
207
-
session module. This could result in DoS to victim, but DoS is
208
-
better than compromised account.
209
-
</para>
64
+
</sect2>
210
65

211
-
<para>
212
-
<link
213
-
linkend="ini.session.use-strict-mode">session.use_strict_mode</link>
214
-
is good mitigation, but it is not enough mitigation for
215
-
authenticated session. Developer must use
216
-
<function>session_regenerate_id</function> for authentication.
217
-
<function>session_regenerate_id</function> must be called prior to
218
-
set authentication information to
219
-
$_SESSION. <function>session_regenerate_id</function> makes sure new
220
-
session contains authenticated information stored only in new
221
-
session. i.e. Errors during authentication process may save
222
-
authenticated flag in old session.
223
-
</para>
66
+
<sect2 xml:id="features.session.security.management.non-adaptive-session">
67
+
<title>Non-adaptive Session Management</title>
224
68

225
-
<para>
226
-
Calling <function>session_regenerate_id</function> function could
227
-
result in personal DoS like use_strict_mode=On. However, DoS is
228
-
better than compromised account. Session ID should be regenerated
229
-
when user is authenticated at least. Session ID regeneration reduces
230
-
risk of stolen session ID, thus is should be called periodically.
231
-
Developer should not rely on session ID expiration. Attackers may
232
-
access victim's session ID periodically to prevent expiration.
233
-
Developers must implement their own expiration feature for old sessions.
234
-
</para>
69
+
<para>
70
+
PHP's session manager is adaptive by default currently.
71
+
An adaptive session manager bears additional risks.
72
+
</para>
235
73

236
-
<para>
237
-
Note that <function>session_regenerate_id</function> does not delete
238
-
old session by default. Old authenticated session may be available
239
-
for use. If developer would like to prevent old authenticated session to
240
-
be used by anyone, developer must destroy session by setting
241
-
<parameter>delete_old_session</parameter> to &true;. However,
242
-
immediate old session deletion has unwanted side effect. Session
243
-
could be vanished when there are concurrent connections to web
244
-
application and/or network is unstable. Instead of deleting old
245
-
session immediately, you may set short term expiration time in
246
-
$_SESSION by yourselves. If user accesses to obsolete
247
-
session(expired session), deny access to it.
248
-
</para>
74
+
<para>
75
+
When <link linkend="ini.session.use-strict-mode">session.use_strict_mode</link> is enabled,
76
+
and the session save handler supports it,
77
+
an uninitialized session ID is rejected and a new one is created.
78
+
This prevents an attack that forces users to use a known session ID.
79
+
An attacker may paste links or send emails that contains the session ID.
80
+
E.g. <literal>http://example.com/page.php?PHPSESSID=123456789</literal> if
81
+
<link linkend="ini.session.use-trans-sid">session.use_trans_sid</link>
82
+
is enabled, the victim will start a session using the session ID provided
83
+
by the attacker.
84
+
<link linkend="ini.session.use-strict-mode">session.use_strict_mode</link>
85
+
mitigate this risk.
86
+
</para>
249
87

250
-
<para>
251
-
<link
252
-
linkend="ini.session.use-only-cookies">session.use_only_cookies</link>
253
-
and proper use of <function>session_regenerate_id</function> could
254
-
cause personal DoS. When this is the case, you may ask users to
255
-
remove cookies and warn users that there could be possible security
256
-
issues. Attackers may set malicious cookies via vulnerable web
257
-
application (i.e. JavaScript injection), vulnerable/malicious
258
-
browser plugins, etc.
259
-
</para>
88
+
<warning>
89
+
<simpara>
90
+
User defined save handlers can also support strict session mode by
91
+
implementing session ID validation. All user defined save handlers
92
+
should implement session ID validation.
93
+
</simpara>
94
+
</warning>
95
+

96
+
<para>
97
+
The session ID cookie may be set with the domain, path, httponly,
98
+
secure and, as of PHP 7.3, SameSite attributes.
99
+
<!-- Not exactly sure what the meaning here is - girgias -->
100
+
There is precedence defined by browsers.
101
+
By using the precedence, an attacker can set session ID that
102
+
could be used permanently. Use of
103
+
<link linkend="ini.session.use-only-cookies">session.use_only_cookies</link>
104
+
will not solve this issue.
105
+
<link linkend="ini.session.use-strict-mode">session.use_strict_mode</link>
106
+
mitigates this risk. With
107
+
<link linkend="ini.session.use-strict-mode">session.use_strict_mode</link>=On,
108
+
the uninitialized session ID will be refused.
109
+
</para>
110
+

111
+
<note>
112
+
<simpara>
113
+
Even though
114
+
<link linkend="ini.session.use-strict-mode">session.use_strict_mode</link>
115
+
mitigates the risk of adaptive session management, an attacker can force
116
+
users to use an initialized session ID which has been created by an attacker.
117
+
E.g. JavaScript injection.
118
+
This attack can be mitigated by this manual's recommendations.
119
+
</simpara>
120
+

121
+
<simpara>
122
+
By following this manual, developers should enable,
123
+
<link linkend="ini.session.use-strict-mode">session.use_strict_mode</link>,
124
+
use timestamp based session management, and regenerate session IDs using
125
+
<function>session_regenerate_id</function> with recommended procedures.
126
+
If developers follow all of the above, an attacker generated session ID
127
+
will eventually be deleted.
128
+
</simpara>
129
+

130
+
<simpara>
131
+
When access to an obsolete session occurs, developers should save all
132
+
active session data of the user. As this information will be relevant
133
+
for an ensuing investigation. The user should be forcefully logged out
134
+
of all sessions, i.e. require them to reauthenticate.
135
+
This prevents attackers from abusing stolen sessions.
136
+
</simpara>
137
+
</note>
138
+

139
+
<warning>
140
+
<simpara>
141
+
Access to an obsolete session does not necessarily suggest an attack.
142
+
An unstable network and/or immediate deletion of the active session
143
+
will result in legitimate users using obsolete sessions.
144
+
</simpara>
145
+
</warning>
146
+

147
+
<para>
148
+
As of PHP 7.1.0, <function>session_create_id</function> has been added.
149
+
This function may be operated to access all active sessions of a user
150
+
efficiently by prefixing the session IDs with the user ID. Enabling
151
+
<link linkend="ini.session.use-strict-mode">session.use_strict_mode</link>
152
+
is vital with this setup. Otherwise, malicious users can set
153
+
malicious session ID for other users.
154
+
</para>
155
+

156
+
<note>
157
+
<simpara>
158
+
Users prior to PHP 7.1.0 <emphasis>should</emphasis> use
159
+
<acronym>CSPRNG</acronym>, e.g. <filename>/dev/urandom</filename>, or
160
+
<function>random_bytes</function> and hash functions to generate
161
+
a new session ID. <function>session_create_id</function> has
162
+
collision detection and generates a session ID according to the
163
+
session's INI settings.
164
+
Use of <function>session_create_id</function> is preferred.
165
+
</simpara>
166
+
</note>
167
+

168
+
</sect2>
169
+

170
+
<sect2 xml:id="features.session.security.management.session-id-regeneration">
171
+
<title>Session ID Regeneration</title>
172
+

173
+
<para>
174
+
<link linkend="ini.session.use-strict-mode">session.use_strict_mode</link>
175
+
is a good mitigation, however not sufficient. Developers must equally use
176
+
<function>session_regenerate_id</function> for session security.
177
+
</para>
178
+

179
+
<para>
180
+
Session ID regeneration reduces the risk of stolen session IDs, thus
181
+
<function>session_regenerate_id</function> must be called periodically.
182
+
E.g. Regenerate the session ID every 15 minutes for security sensitive content.
183
+
Even in the case that a session ID is stolen, both the legitimate
184
+
user's and the attacker's session will expire.
185
+
In other words access by the user or the attacker will
186
+
generate an obsolete session access error.
187
+
</para>
188
+

189
+
<para>
190
+
Session IDs <emphasis>must</emphasis> be regenerated when user privileges
191
+
are elevated, such as after authenticating.
192
+
<function>session_regenerate_id</function> must be called prior to
193
+
setting the authentication information to <varname>$_SESSION</varname>.
194
+
(<function>session_regenerate_id</function> saves the current session data
195
+
automatically in order to save timestamp/etc. to the current session.)
196
+
Ensure only the new session contains the authenticated flag.
197
+
</para>
198
+

199
+
<para>
200
+
Developers <emphasis>must not</emphasis> rely on session ID expiration by
201
+
<link linkend="ini.session.gc-maxlifetime">session.gc_maxlifetime</link>.
202
+
Attackers may access a victim's session ID periodically to prevent its
203
+
expiration and keep exploiting it, including an authenticated session.
204
+
</para>
205
+

206
+
<para>
207
+
Instead, developers must implement timestamp based session data management.
208
+
</para>
209
+

210
+
<warning>
211
+
<simpara>
212
+
Although the session manager can manage timestamps transparently,
213
+
this feature is not implemented. Old session data must be kept until GC.
214
+
Simultaneously, developers must assure themselves obsolete session data
215
+
is removed. However, developers must not remove active session data immediately.
216
+
I.e. <code>session_regenerate_id(true);</code> and
217
+
<function>session_destroy</function> must never be called together for an active session.
218
+
This may sound contradictory, but this is a mandatory requirement.
219
+
</simpara>
220
+
</warning>
221
+

222
+
<para>
223
+
<function>session_regenerate_id</function> does <emphasis>not</emphasis>
224
+
delete outdated sessions by default.
225
+
Obsolete authenticated sessions may be present for use.
226
+
Developers must prevent outdated sessions to be consumed by anyone.
227
+
They must prohibit access to obsolete session data by themselves using timestamps.
228
+
</para>
229
+

230
+
<warning>
231
+
<simpara>
232
+
The sudden removal of an active session produces undesirable side effects.
233
+
Sessions can vanish when there are concurrent connections to the web
234
+
application and/or the network is unstable.
235
+
</simpara>
236
+
<simpara>
237
+
Potential malicious access is undetectable with the sudden removal of active sessions.
238
+
</simpara>
239
+
<simpara>
240
+
Instead of deleting outdated sessions immediately, developers must set a
241
+
short-term expiration time (timestamp) in <varname>$_SESSION</varname>,
242
+
and prohibit access to the session data by themselves.
243
+
</simpara>
244
+
<simpara>
245
+
Developers must not prohibit access to old session data immediately after
246
+
<function>session_regenerate_id</function>. It must be prohibited at a
247
+
later stage. E.g. a few seconds later for stable networks, like a wired network,
248
+
and a few minutes later for unstable networks such as cell phones or Wi-Fi.
249
+
</simpara>
250
+
<simpara>
251
+
If a user accesses an obsolete session (expired session), access to it should be denied.
252
+
It is also recommended to remove the authenticated status from all of the user's
253
+
sessions to as it is likely to represent an attack.
254
+
</simpara>
255
+
</warning>
256
+

257
+
<para>
258
+
Proper use of <link linkend="ini.session.use-only-cookies">session.use_only_cookies</link>
259
+
and <function>session_regenerate_id</function> can cause personal DoS with
260
+
undeletable cookies set by attackers. In this case, developers may invite users
261
+
to remove cookies and advise them they may be affected by a security issue.
262
+
Attackers may set malicious cookies via a vulnerable web application,
263
+
an exposed/vicious browser plugin, a physically compromised device, etc.
264
+
</para>
265
+

266
+
<warning>
267
+
<simpara>
268
+
Do not misunderstand the DoS risk.
269
+
<link linkend="ini.session.use-strict-mode">session.use_strict_mode</link>=On
270
+
is mandatory for general session ID security! All sites are advised to enable
271
+
<link linkend="ini.session.use-strict-mode">session.use_strict_mode</link>.
272
+
</simpara>
273
+
<simpara>
274
+
DoS can only happen when the account is under attack. A JavaScript injection
275
+
vulnerability in an application represents the most common cause.
276
+
</simpara>
277
+
</warning>
278
+

279
+
</sect2>
280
+

281
+
<sect2 xml:id="features.session.security.management.session-data-deletion">
282
+
<title>Session Data Deletion</title>
283
+

284
+
<para>
285
+
Obsolete session data must be inaccessible and deleted.
286
+
The current session module does not handle this well.
287
+
</para>
288
+

289
+
<para>
290
+
Obsolete session data should be removed as soon as possible.
291
+
However, active sessions must not be removed instantly.
292
+
To satisfy those requirements, developers must implement timestamp
293
+
based session data management by themselves.
294
+
</para>
295
+

296
+
<para>
297
+
Set and manage expiration timestamp in $_SESSION.
298
+
Prohibit access to outdated session data.
299
+
When access to obsolete session data is detected, it is advised to remove all
300
+
authenticated status from the user's sessions and force them to re-authenticate.
301
+
Access to obsolete session data can represent an attack.
302
+
To achieve this, developers must keep track of all active sessions of every user.
303
+
</para>
304
+

305
+
<note>
306
+
<simpara>
307
+
Access to an obsolete session can also happen because of an unstable network
308
+
and/or concurrent access to the website.
309
+
E.g. the server tried to set a new session ID via a cookie, but the Set-Cookie
310
+
packet may not have reached the client due to loss of connection.
311
+
One connection may issue a new session ID by <function>session_regenerate_id</function>,
312
+
but another concurrent connection may not have received the new session ID yet.
313
+
Therefore, developers must prohibit access to obsolete session at a later stage.
314
+
I.e. timestamp based session management is mandatory.
315
+
</simpara>
316
+
</note>
317
+

318
+
<para>
319
+
In summary, session data must not be destroyed with
320
+
<function>session_regenerate_id</function> nor <function>session_destroy</function>,
321
+
but timestamps must be used to control access to session data.
322
+
Let <function>session_gc</function> remove obsolete data from the session data storage.
323
+
</para>
324
+

325
+
</sect2>
326
+

327
+
<sect2 xml:id="features.session.security.management.session-locking">
328
+
<title>Session and Locking</title>
329
+

330
+
<para>
331
+
Session data is locked to avoid race conditions by default.
332
+
Locking is mandatory to keep session data consistent across requests.
333
+
</para>
334
+

335
+
<para>
336
+
However, session-locking can be abused by attackers to perform DoS attacks.
337
+
To mitigate the risk of a DoS attack by session-locking, minimize locks.
338
+
Use read only sessions when session data does not need to be updated.
339
+
Use the 'read_and_close' option with <function>session_start</function>.
340
+
<code>session_start(['read_and_close'=>1]);</code>
341
+
Close the session as soon as possible after updating $_SESSION by
342
+
using <function>session_commit</function>.
343
+
</para>
344
+

345
+
<para>
346
+
The current session module does <emphasis>not</emphasis>
347
+
detect any modification of $_SESSION when the session is inactive.
348
+
It is the developer's responsibility not to modify $_SESSION when
349
+
the session is inactive.
350
+
</para>
351
+

352
+
</sect2>
353
+

354
+
<sect2 xml:id="features.session.security.management.active-sessions">
355
+
<title>Active Sessions</title>
356
+

357
+
<para>
358
+
Developers should keep track of all active sessions for every user.
359
+
And notify them of how many active sessions, from which IP (and area),
360
+
how long it has been active, etc.
361
+
PHP does not keep track of these. Developers are supposed to do so.
362
+
</para>
363
+

364
+
<para>
365
+
Various ways to implement this exist.
366
+
One possible implementation is setting up a database that keeps track
367
+
of the required data and stores any relevant information.
368
+
Since session data is GCed, developers must take care of the GCed data
369
+
to maintain the active session database consistency.
370
+
</para>
371
+

372
+
<para>
373
+
One of the simplest implementations is "User ID prefixed session ID"
374
+
and store the required information in $_SESSION.
375
+
Many databases posses good performance for selecting string prefix.
376
+
Developers MAY use <function>session_regenerate_id</function> and
377
+
<function>session_create_id</function> for this.
378
+
</para>
379
+

380
+
<warning>
381
+
<simpara>
382
+
Never employ confidential data as a prefix.
383
+
If the user ID is confidential, consider using
384
+
<function>hash_hmac</function>.
385
+
</simpara>
386
+
</warning>
387
+

388
+
<warning>
389
+
<simpara>
390
+
Enabling <link linkend="ini.session.use-strict-mode">session.use_strict_mode</link>
391
+
is mandatory for this setup. Ensure it is enabled.
392
+
Otherwise, the active session database can be compromised.
393
+
</simpara>
394
+
</warning>
395
+

396
+
<para>
397
+
Timestamp based session management is mandatory to detect access to obsolete sessions.
398
+
When access to an obsolete session is detected, authentication flags should
399
+
be removed from all active sessions of the user.
400
+
This prevents attackers to keep exploiting stolen sessions.
401
+
</para>
402
+

403
+
</sect2>
404
+

405
+
<sect2 xml:id="features.session.security.management.session-and-autologin">
406
+
<title>Session and Auto-login</title>
407
+

408
+
<para>
409
+
Developers must not use long life session IDs for auto-login because it
410
+
increases the risk of stolen sessions.
411
+
An auto-login feature should be implemented by the developer.
412
+
</para>
413
+

414
+
<para>
415
+
Use a secure one time hash key as an auto-login key using
416
+
<function>setcookie</function>. Use a secure hash stronger than SHA-2.
417
+
E.g. SHA-256 or greater with random data from <function>random_bytes</function>
418
+
or <filename>/dev/urandom</filename>.
419
+
</para>
420
+

421
+
<para>
422
+
If the user is unauthenticated, check whether the one-time auto-login key is valid or not.
423
+
In the case it is valid, authenticate the user and set a new secure one-time hash key.
424
+
An auto-login key must only be used once, i.e. never reuse an auto-login key,
425
+
always generate a new one.
426
+
</para>
427
+

428
+
<para>
429
+
An auto-login key is a long life authentication key,
430
+
it should be protected as much as possible.
431
+
Use path/httponly/secure/SameSite cookie attributes to secure it.
432
+
I.e. never transmit the auto-login key unless required.
433
+
</para>
434
+

435
+
<para>
436
+
Developer must implement the features that disables
437
+
auto-login and removes unneeded auto-login key cookie.
438
+
</para>
439
+

440
+
</sect2>
441
+

442
+
<sect2 xml:id="features.session.security.management.csrf">
443
+
<title>CSRF (Cross-Site Request Forgeries) attacks</title>
444
+

445
+
<para>
446
+
Sessions and authentication do not protect against CSRF attacks.
447
+
Developers must implement CSRF protection by themselves.
448
+
</para>
449
+

450
+
<para>
451
+
<function>output_add_rewrite_var</function> can be used for CSRF protection.
452
+
Refer to the manual page for more details.
453
+
</para>
454
+

455
+
<note>
456
+
<simpara>
457
+
PHP prior to 7.2.0 uses the same output buffer and INI setting as trans sid.
458
+
Therefore, use of <function>output_add_rewrite_var</function>
459
+
with PHP prior to version 7.2.0 is not advised.
460
+
</simpara>
461
+
</note>
462
+

463
+
<para>
464
+
Most web application frameworks support CSRF protection.
465
+
Refer to the web application framework manual for more details.
466
+
</para>
467
+

468
+
<para>
469
+
As of PHP 7.3 the SameSite attribute for the session cookie can be set.
470
+
This is an additional measure which can mitigate CSRF vulnerabilities.
471
+
</para>
472
+
</sect2>
473
+
</sect1>
474
+

475
+
<sect1 xml:id="session.security.ini">
476
+
<title>Securing Session INI Settings</title>
477
+

478
+
<para>
479
+
By securing session related INI settings, developers can improve session security.
480
+
Some important INI settings do not have any recommended settings.
481
+
Developers are responsible for hardening session settings.
482
+
</para>
483
+

484
+
<itemizedlist>
485
+
<listitem>
486
+
<para>
487
+
<link linkend="ini.session.cookie-lifetime">session.cookie_lifetime</link>=0
488
+
</para>
489
+
<para>
490
+
<literal>0</literal> possesses a particular meaning.
491
+
It informs browsers not to store the cookie to permanent storage.
492
+
Therefore, when the browser is terminated, the session ID cookie is deleted immediately.
493
+
If developers set this other than 0, it may allow other users to use the session ID.
494
+
Most applications should use "<literal>0</literal>" for this.
495
+
</para>
496
+
<para>
497
+
If an auto-login feature is required,
498
+
developers must implement their own secure auto-login feature.
499
+
Do not use long life session IDs for this.
500
+
More information can be found above in the relevant section.
501
+
</para>
502
+
</listitem>
503
+

504
+
<listitem>
505
+
<para>
506
+
<link linkend="ini.session.use-cookies">session.use_cookies</link>=On
507
+
</para>
508
+
<para>
509
+
<link linkend="ini.session.use-only-cookies">session.use_only_cookies</link>=On
510
+
</para>
511
+
<para>
512
+
Although HTTP cookies suffer some problems,
513
+
cookies remain the preferred way to manage session IDs.
514
+
Only use cookies for session ID management when it is possible.
515
+
Most applications should use a cookie for the session ID.
516
+
</para>
517
+
<para>
518
+
If <link linkend="ini.session.use-only-cookies">session.use_only_cookies</link>=Off,
519
+
the session module will use the session ID values set by
520
+
GET or POST provided the session ID cookie is uninitialized.
521
+
</para>
522
+
</listitem>
523
+

524
+
<listitem>
525
+
<para>
526
+
<link linkend="ini.session.use-strict-mode">session.use_strict_mode</link>=On
527
+
</para>
528
+
<para>
529
+
Although, enabling
530
+
<link linkend="ini.session.use-strict-mode">session.use_strict_mode</link>
531
+
is mandatory for secure sessions. It is disabled by default.
532
+
</para>
533
+
<para>
534
+
This prevents the session module to use an uninitialized session ID.
535
+
Put differently, the session module only accepts valid session IDs
536
+
generated by the session module.
537
+
It rejects any session ID supplied by users.
538
+
</para>
539
+
<para>
540
+
Due to the cookie specification, attackers are capable to place
541
+
non-removable session ID cookies by locally setting a cookie database
542
+
or JavaScript injections.
543
+
<link linkend="ini.session.use-strict-mode">session.use_strict_mode</link>
544
+
can prevent an attacker-initialized session ID of being used.
545
+
</para>
546
+
<note>
547
+
<para>
548
+
Attackers may initialize a session ID with their device and may set
549
+
the session ID of the victim. They must keep the session ID active to abuse.
550
+
Attackers require additional steps to perform an attack in this scenario.
551
+
Therefore,
552
+
<link linkend="ini.session.use-strict-mode">session.use_strict_mode</link>
553
+
works as a mitigation.
554
+
</para>
555
+
</note>
556
+
</listitem>
557
+

558
+
<listitem>
559
+
<para>
560
+
<link linkend="ini.session.cookie-httponly">session.cookie_httponly</link>=On
561
+
</para>
562
+
<para>
563
+
Refuses access to the session cookie from JavaScript.
564
+
This setting prevents cookies snatched by a JavaScript injection.
565
+
</para>
566
+
<para>
567
+
It is possible to use a session ID as a CSRF token, but this is not recommended.
568
+
For example, HTML sources may be saved and sent to other users.
569
+
Developers should not write session IDs in web pages for better security.
570
+
Almost all applications must use the httponly attribute for the session ID cookie.
571
+
</para>
572
+
<note>
573
+
<para>
574
+
The CSRF token should be renewed periodically just like the session ID.
575
+
</para>
576
+
</note>
577
+
</listitem>
578
+

579
+
<listitem>
580
+
<para>
581
+
<link linkend="ini.session.cookie-secure">session.cookie_secure</link>=On
582
+
</para>
583
+
<para>
584
+
Allow access to the session ID cookie only when the protocol is HTTPS.
585
+
If a website is only accessible via HTTPS, it should enable this setting.
586
+
</para>
587
+
<para>
588
+
HSTS should be considered for websites accessible only via HTTPS.
589
+
</para>
590
+
</listitem>
591
+

592
+
<listitem>
593
+
<para>
594
+
<link linkend="ini.session.cookie-samesite">session.cookie_samesite</link>="Lax" or
595
+
<link linkend="ini.session.cookie-samesite">session.cookie_samesite</link>="Strict"
596
+
</para>
597
+
<para>
598
+
As of PHP 7.3 the <literal>"SameSite"</literal> attribute can be set for the session ID cookie.
599
+
This attribute is a way to mitigate CSRF (Cross Site Request Forgery) attacks.
600
+
</para>
601
+
<para>
602
+
The difference between Lax and Strict is the accessibility of the cookie in
603
+
requests originating from another registrable domain employing the HTTP GET method.
604
+
Cookies using Lax will be accessible in a GET request originated from
605
+
another registrable domain, whereas cookies using Strict will not.
606
+
</para>
607
+
</listitem>
608
+

609
+
<listitem>
610
+
<para>
611
+
<link linkend="ini.session.gc-maxlifetime">session.gc_maxlifetime</link>=[choose smallest possible]
612
+
</para>
613
+
<para>
614
+
<link linkend="ini.session.gc-maxlifetime">session.gc_maxlifetime</link>
615
+
is a setting for deleting obsolete session ID.
616
+
Reliance on this setting is <emphasis>not</emphasis> recommended.
617
+
Developers should manage the lifetime of sessions with a timestamp by themselves.
618
+
</para>
619
+
<para>
620
+
Session GC (garbage collection) is best performed by using <function>session_gc</function>.
621
+
The <function>session_gc</function> function should be executed by a task
622
+
managers. E.g. cron on UNIX like systems.
623
+
</para>
624
+
<para>
625
+
GC is performed by probability by default.
626
+
This setting does <emphasis>not</emphasis> guarantee that an outdated
627
+
session is deleted.
628
+
Although developers cannot rely on this setting,
629
+
specifying it to the smallest possible value is recommended.
630
+
Adjusting <link
631
+
linkend="ini.session.gc-probability">session.gc_probability</link>
632
+
and <link
633
+
linkend="ini.session.gc-divisor">session.gc_divisor</link> so
634
+
that obsolete sessions are deleted at an appropriate frequency.
635
+
If an auto-login feature is required, developers must implement their own
636
+
secure auto-login feature, see above for more information.
637
+
Never use long life session ID for this feature.
638
+
</para>
639
+
<note>
640
+
<para>
641
+
Some session save handler modules do not use this setting for probability
642
+
based expiration. E.g. memcached, memcache.
643
+
Refer to the session save handler documentation for details.
644
+
</para>
645
+
</note>
646
+
</listitem>
647
+

648
+
<listitem>
649
+
<para>
650
+
<link linkend="ini.session.use-trans-sid">session.use_trans_sid</link>=Off
651
+
</para>
652
+
<para>
653
+
Use of a transparent session ID management is not prohibited.
654
+
Developers may employ it when it is required.
655
+
However, disabling transparent session ID management improves the general session
656
+
ID security by eliminating the possibility of a session ID injection and/or leak.
657
+
</para>
658
+
<note>
659
+
<para>
660
+
Session ID may leak from bookmarked URLs, e-mailed URLs, saved HTML source, etc.
661
+
</para>
662
+
</note>
663
+
</listitem>
664
+

665
+
<listitem>
666
+
<para>
667
+
<link linkend="ini.session.trans-sid-tags">session.trans_sid_tags</link>=[limited tags]
668
+
</para>
669
+
<para>
670
+
(PHP 7.1.0 &gt;=) Developers should not rewrite unneeded HTML tags.
671
+
Default value should be sufficient for most usages.
672
+
Older PHP versions use
673
+
<link linkend="ini.url-rewriter.tags">url_rewriter.tags</link> instead.
674
+
</para>
675
+
</listitem>
676
+

677
+
<listitem>
678
+
<para>
679
+
<link linkend="ini.session.trans-sid-hosts">session.trans_sid_hosts</link>=[limited hosts]
680
+
</para>
681
+
<para>
682
+
(PHP 7.1.0 &gt;=) This INI defines whitelist hosts that allows trans sid rewrite.
683
+
Never add untrusted hosts.
684
+
Session module only allows <literal>$_SERVER['HTTP_HOST']</literal>
685
+
when this setting is empty.
686
+
</para>
687
+
</listitem>
688
+

689
+
<listitem>
690
+
<para>
691
+
<link linkend="ini.session.referer-check">session.referer_check</link>=[originating URL]
692
+
</para>
693
+
<para>
694
+
When <link
695
+
linkend="ini.session.use-trans-sid">session.use_trans_sid</link>
696
+
is enabled.
697
+
It reduces the risk of session ID injection.
698
+
If a website is <literal>http://example.com/</literal>,
699
+
set <literal>http://example.com/</literal> to it.
700
+
Note that with HTTPS browsers will not send the referrer header.
701
+
Browsers may not send the referrer header by configuration.
702
+
Therefore, this setting is not a reliable security measure.
703
+
Use of this setting is recommended.
704
+
</para>
705
+
</listitem>
706
+

707
+
<listitem>
708
+
<para>
709
+
<link linkend="ini.session.cache-limiter">session.cache_limiter</link>=nocache
710
+
</para>
711
+
<para>
712
+
Ensure HTTP content are uncached for authenticated sessions.
713
+
Allow caching only when the content is not private.
714
+
Otherwise, content may be exposed.
715
+
<literal>"private"</literal> may be employed if HTTP content does not
716
+
include security sensitive data.
717
+
Note that <literal>"private"</literal> may transmit private data
718
+
cached by shared clients.
719
+
<literal>"public"</literal> must only be used when HTTP content does
720
+
not contain any private data at all.
721
+
</para>
722
+
</listitem>
723
+

724
+
<listitem>
725
+
<para>
726
+
<link linkend="ini.session.sid-length">session.sid_length</link>="48"
727
+
</para>
728
+
<para>
729
+
(PHP 7.1.0 &gt;=) Longer session IDs results in stronger session IDs.
730
+
Developers should consider a session ID length of 32 characters or more.
731
+
At least 26 characters are required when
732
+
<link linkend="ini.session.sid-bits-per-character">session.sid_bits_per_character</link>="5".
733
+
</para>
734
+
</listitem>
735
+

736
+
<listitem>
737
+
<para>
738
+
<link linkend="ini.session.sid-bits-per-character">session.sid_bits_per_character</link>="6"
739
+
</para>
740
+
<para>
741
+
(PHP 7.1.0 &gt;=) The more bits there are in a session ID character,
742
+
the stronger the session ID generated by the session module is for an
743
+
identical session ID length.
744
+
</para>
745
+
</listitem>
746
+

747
+
<listitem>
748
+
<para>
749
+
<link linkend="ini.session.hash-function">session.hash_function</link>="sha256"
750
+
</para>
751
+
<para>
752
+
(PHP 7.1.0 &lt;) A stronger hash function will generate a stronger session ID.
753
+
Although hash collision is unlikely even with the MD5 hashing algorithm,
754
+
developers should use SHA-2 or a stronger hashing algorithm like sha384 and sha512.
755
+
Developers must ensure they feed a long enough
756
+
<link linkend="ini.session.entropy-length">entropy</link>
757
+
for the hashing function used.
758
+
</para>
759
+
</listitem>
760
+

761
+
<listitem>
762
+
<para>
763
+
<link linkend="ini.session.save-path">session.save_path</link>=[non world-readable directory]
764
+
</para>
765
+
<para>
766
+
If this is set to a world-readable directory, such as
767
+
<filename>/tmp</filename> (the default), other users on the
768
+
server may be able to hijack sessions by getting the list of
769
+
files in that directory.
770
+
</para>
771
+
</listitem>
772
+

773
+
</itemizedlist>
774
+
</sect1>
260
775

261
-
<para>
262
-
Developers must not use long life session ID for auto login as it
263
-
increases risk of stolen session. Auto login should be implemented
264
-
by developer. Use secure one time hash key as auto login key using
265
-
cookie. Use secure hash stronger than SHA-2. e.g. SHA-256 or greater
266
-
with random data from /dev/urandom or like. If user is not
267
-
authenticated, check the one time auto login key is valid or not. If
268
-
key is valid, authenticate user and set new secure one time hash
269
-
key. Auto login key is long lived authentication key, this key should
270
-
be protected as much as possible. Use path/httponly/secure
271
-
attributes of cookie to protect. Developer must implement feature that
272
-
disables auto login and removes unneeded auto login key cookie for
273
-
users.
274
-
</para>
275
776
</chapter>
276
777

277
778
<!-- Keep this comment at the end of the file
...
...
@@ -294,4 +795,3 @@ vim600: syn=xml fen fdm=syntax fdl=2 si
294
795
vim: et tw=78 syn=sgml
295
796
vi: ts=1 sw=1
296
797
-->
297
-

298
798