-
Notifications
You must be signed in to change notification settings - Fork 102
/
session-regenerate-id.xml
218 lines (193 loc) · 6.86 KB
/
session-regenerate-id.xml
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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision$ -->
<!-- EN-Revision: a0ae28d3bc85f927c22649ebd9a590b921534b7d Maintainer: yuanyuqiang Status: ready -->
<!-- CREDITS: mowangjuanzi -->
<refentry xmlns="http://docbook.org/ns/docbook" xml:id="function.session-regenerate-id">
<refnamediv>
<refname>session_regenerate_id</refname>
<refpurpose>
使用新生成的会话 ID 更新现有会话 ID
</refpurpose>
</refnamediv>
<refsect1 role="description">
&reftitle.description;
<methodsynopsis>
<type>bool</type><methodname>session_regenerate_id</methodname>
<methodparam choice="opt"><type>bool</type><parameter>delete_old_session</parameter><initializer>&false;</initializer></methodparam>
</methodsynopsis>
<para>
<function>session_regenerate_id</function>
在不修改当前会话中数据的前提下使用新的 ID 替换原有会话 ID。
</para>
<para>
如果启用了 <link linkend="ini.session.use-trans-sid">session.use_trans_sid</link> 选项,
那么必须在调用 <function>session_regenerate_id</function> 函数之后开始进行输出工作,
否则会导致使用原有的会话 ID。
</para>
<warning>
<para>
当前的 session_regenerate_id 并没有很好的处理在诸如移动数据网络和 WiFi 网络不稳定的场景。
因此,调用 session_regenerate_id 函数
可能会导致会话丢失。
</para>
<para>
你不应该直接销毁旧的会话所关联的数据,
而是应该使用时间戳机制来控制对于已经失效的会话 ID 的访问。
否则,可能会在并发访问的场景下导致会话数据不一致、
会话丢失等情况,甚至可能引发客户端(浏览器)创建很多无用的会话 ID。
但是,另外一方面来讲,立即删除会话中的数据
可以防止会话劫持攻击。
</para>
</warning>
</refsect1>
<refsect1 role="parameters">
&reftitle.parameters;
<para>
<variablelist>
<varlistentry>
<term><parameter>delete_old_session</parameter></term>
<listitem>
<para>
是否删除原 ID 所关联的会话存储文件。
如果你需要避免会话并发访问冲突,那么不应该立即删除会话中的数据。
如果你需要防止会话劫持攻击,那么可以立即删除会话数据。
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</refsect1>
<refsect1 role="returnvalues">
&reftitle.returnvalues;
<para>
&return.success;
</para>
</refsect1>
<refsect1 role="examples">
&reftitle.examples;
<para>
<example>
<title>A <function>session_regenerate_id</function> 示例</title>
<programlisting role="php">
<![CDATA[
<?php
// 注意:下列不是完整的代码,只是一个示例
session_start();
// 检查会话被销毁的时间戳
if (isset($_SESSION['destroyed'])
&& $_SESSION['destroyed'] < time() - 300) {
// 通常不会发生这种情况。如果发生,那么可能是由于不稳定的网络状况或者被攻击导致的
// 移除用户会话中的认证信息
remove_all_authentication_flag_from_active_sessions($_SESSION['userid']);
throw(new DestroyedSessionAccessException);
}
$old_sessionid = session_id();
// 设置会话销毁时间戳
$_SESSION['destroyed'] = time(); // session_regenerate_id() 保存旧会话数据
// 如果直接调用 session_regenerate_id() 函数可能会导致会话丢失的情况,
// 参见下面的示例
session_regenerate_id();
// 新创建的会话不需要时间戳
unset($_SESSION['destroyed']);
$new_sessionid = session_id();
echo "Old Session: $old_sessionid<br />";
echo "New Session: $new_sessionid<br />";
print_r($_SESSION);
?>
]]>
</programlisting>
</example>
</para>
<para>
当前的会话模块未能很好的处理在网络不稳定的时候导致会话丢失的场景。
你需要自行管理会话 ID 避免调用 session_regenerate_id 导致会话丢失。
</para>
<para>
<example>
<title>Avoiding lost session by <function>session_regenerate_id</function></title>
<programlisting role="php">
<![CDATA[
<?php
// 注意:下列不是完整的代码,只是一个示例
// my_session_start() 和 my_session_regenerate_id()
// 函数可以避免在网络不稳定的情况下导致会话丢失的问题。
// 并且还可以避免用户会话被攻击者利用
function my_session_start() {
session_start();
if (isset($_SESSION['destroyed'])) {
if ($_SESSION['destroyed'] < time()-300) {
// 通常不会发生这种情况。如果发生,那么可能是由于不稳定的网络状况或者被攻击导致的
// 移除用户会话中的认证信息
remove_all_authentication_flag_from_active_sessions($_SESSION['userid']);
throw(new DestroyedSessionAccessException);
}
if (isset($_SESSION['new_session_id'])) {
// 尚未完全过期,可能是由于网络不稳定引起的。
// 尝试再次设置正确的会话 ID cookie。
// 注意:如果你需要移除认证标记,那么不要尝试再次设置会话 ID。
session_commit();
session_id($_SESSION['new_session_id']);
// 现在有了新的会话 ID 了。
session_start();
return;
}
}
}
function my_session_regenerate_id() {
// 如果由于不稳定的网络导致没有创建会话 ID,
// 那么就创建一个
$new_session_id = session_create_id();
$_SESSION['new_session_id'] = $new_session_id;
// 设置销毁时间戳
$_SESSION['destroyed'] = time();
// 保存并关闭会话
session_commit();
// 使用新的会话 ID 开始会话
session_id($new_session_id);
ini_set('session.use_strict_mode', 0);
session_start();
ini_set('session.use_strict_mode', 1);
// 新的会话不需要这 2 个数据了
unset($_SESSION['destroyed']);
unset($_SESSION['new_session_id']);
}
?>
]]>
</programlisting>
</example>
</para>
</refsect1>
<refsect1 role="seealso">
&reftitle.seealso;
<para>
<simplelist>
<member><function>session_id</function></member>
<member><function>session_create_id</function></member>
<member><function>session_start</function></member>
<member><function>session_destroy</function></member>
<member><function>session_reset</function></member>
<member><function>session_name</function></member>
</simplelist>
</para>
</refsect1>
</refentry>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
indent-tabs-mode:nil
sgml-parent-document:nil
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->