Sessions
PHP Manual

会话和安全

外部链接:» 会话固定

HTTP 会话管理是 web 应用安全的核心内容, 要采用尽可能的手段来确保会话安全。 开发人员应该合理的启用或使用可接受的设置。

会话模块无法保证存储到会话中的数据仅能被会话创建者可见。 如果要保护会话的完整性, 你需要进行一些额外的工作。 至于如何保护会话,取决于你在会话中所存储的数据。

要保护会话中的数据,通常有额外的成本, 并且有可能影响用户使用的便利性。 例如,要想防范简单的社会工程学方式的攻击, 你需要启用 session.use_only_cookies。 这样一来, 用户需要无条件的接受 cookie, 否则会话功能将无法正常工作。

有几种方式可以将会话 ID 泄露给第三方。 会话 ID 的泄露会导致 第三方可以访问该会话 ID 所关联的所有资源。 如果从你的站点链接到外部站点, 在 URL 中所携带的会话 ID 可能会被外部站点的 “referrer”日志记录。 其次,更加主动的攻击者会尝试监听你的网络通信, 明文传输的会话 ID 可能会被攻击者从网络层面窃取。 对于这种场景的解决方案是在服务器使用 SSL 通信, 并且强制用户使用 SSL 方式访问你的服务。

自 PHP 5.5.2 开始,可以使用 session.use_strict_mode 设置项。当启用该设置项,并且会话保存管理器能够支持此设置项的话, 它会拒绝未经初始化的会话 ID 并且返回一个新创建的会话 ID。 通过强制用户使用新的会话 ID,可以避免遭受攻击。 如果启用了 session.use_trans_sid 设置项,攻击者可以发送包含会话 ID 的 URL 给受害者, 例如:http://example.com/page.php?PHPSESSID=123456789, 那么受害者将会使用攻击者提供的会话 ID 开始会话。 session.use_strict_mode 设置项可以降低这样的风险。

虽然 session.use_strict_mode 设置项可以降低风险, 攻击者依然可以使用自己创建的、已经经过初始化的会话 ID 来欺骗受害人。 只是攻击者需要在发起攻击之前初始化会话 ID 并且要保持这个会话处于活跃状态。

可以对会话 ID cookie 设置 domain,path,httponly,secure 等属性, 但是浏览器中有优先级定义, 攻击者可以利用这个特点设置可以永久使用的会话 ID。 使用 session.use_only_cookies 设置项无法解决此问题。session.use_strict_mode 设置项可以降低风险,当 session.use_strict_mode 为 “On”时,服务器将拒绝未经初始化的会话 ID, 而是返回一个新创建的会话 ID。 这可能会导致受害者面临 DoS 攻击,但是总好过账号被盗取。

session.use_strict_mode 设置项可以缓解这种情况, 但是对于已经经过认证的会话,它就有些力不从心了。 开发人员必须使用 session_regenerate_id() 来进行认证, 并且还需要在向 $_SESSION 中存储认证信息之前调用 session_regenerate_id() 函数。 session_regenerate_id() 可以确保仅在新会话中存储认证后的信息。 例如,如果在认证过程中发生错误, 可能会在旧的会话中保存认证通过的标识。

和 use_strict_mode=On 类似,使用session_regenerate_id() 函数 也可能导致 DoS 攻击(从个人角度来看),但是总好过账号被盗取。 至少应该在用户通过认证之后为其重新生成新的会话 ID。 重新生成会话 ID 可以降低被窃取的风险, 所以应该定期重新生成会话 ID。 开发人员不应依赖会话过期, 因为攻击者可以通过定期使用受害者会话 ID 发起访问以保持会话活跃。 开发人员必须自行实现针对过期会话的处理。

需要提醒的是,默认情况下,session_regenerate_id() 函数并不会删除旧的会话。 对用户而言,原有的已认证的会话可能仍然可用。 如果开发人员需要阻止其他人使用原有的已认证会话, 需要设置 delete_old_session 参数为 TRUE。 但是立即删除旧的会话可能会带来其他影响, 比如在并发访问或者网络不稳定的情况下, 可能会导致会话无效。(译注:意指浏览器携带旧的会话 ID 发起了并发的请求,如果在第一个被服务器接受和处理的请求中删除了旧的会话数据,那么后续的请求将会产生会话无效的问题) 可以在 $_SESSION 中设置一个很短的过期时间来代替直接删除旧的会话, 并且拒绝用户访问旧的会话(过期的会话)。

session.use_only_cookiessession_regenerate_id() 联合使用, 在某些情况下可能导致针对个人的 DoS 攻击。 如果发生这种情况, 你可以告知用户清除浏览器的 cookie 并且警告用户可能存在安全隐患。 攻击者可以利用 web 应用的弱点(例如,JavaScript 注入) 或恶意的浏览器插件生成恶意的 cookie。

开发人员一定不要使用长生命周期会话 ID 来实现自动登录的功能, 因为这样会使会话很容易被窃取。 开发人员需要自行实现自动登录的功能, 可以使用比 SHA-2 更安全的散列算法, 例如 SHA-256 或者更高, 并且包含从 /dev/urandom 产生随机数据。 如果用户尚未认证通过,就检查一次性自动登录密钥是否有效。 如果密钥有效,那么对用户进行认证,并且设置新的、安全的散列值。 自动登录密钥的生存周期比认证密钥的更长, 所以要竭尽所能来保护自动登录密钥的安全。 至于 cookie,可以使用 path/httponly/secure 等属性来进行保护。 同时,开发人员还必须为用户提供禁用自动登录以及移除不再使用的自动登录密钥 cookie 的功能。


Sessions
PHP Manual