会话(Session)固定
会话安全是一个复杂的话题,会话经常是攻击的目标也没有什么奇怪的。多数会话攻击都是通过攻击者模拟另外一个用户发送数据实现的。
对于攻击者决定性的信息是会话标识,任何伪装的攻击都需要这个。有三个方法获得合法的会话标识:
预测
劫持
固定
预测依赖猜测合法的会话标识。根据 PHP 的会话原理,会话标识是相当随机的,这不大可能是薄弱环节。
劫持一个合法的会话标识是很普通的会话攻击,并且有很多类似的方法。因为会话标识通常都通过 cookie 或者 GET 变量传递,不同之处就在于攻击操作或者传输过程。虽然有一部分浏览器在保持 cookie 上存在缺陷,例如 Internet Explorer,但是比起 GET 来说 cookie 不是那么容易暴露。因此对于允许使用 cookie 的用户,应当使用 cookie 作为传递会话标识更加安全的方法。
固定是最简单的获得合法会话标识的方法。虽然它并不是非常难以防范,但是如果会话机制除了使用 session_start() 外没有其他方法的话,风险也是存在的。
使用下面的脚本 session.php 来演示会话固定:
<?php session_start(); if (!isset($_SESSION['visits'])) { $_SESSION['visits'] = 1; } else { $_SESSION['visits']++; } echo $_SESSION['visits']; ?> <?php session_start(); if (!isset($_SESSION['visits'])) { $_SESSION['visits'] = 1; } else { $_SESSION['visits']++; } echo $_SESSION['visits']; ?> |
在第一次访问这个页面之后,应当在屏幕上看到输出的内容 1。在接下来的访问中,这个值应会增加,用以计算访问页面的次数。
为了实现会话固定,首先要确认没有已经存在的会话标识(可能要删除 cookie),然后访问这个 URL 并在其后添加 ?PHPSESSID=1234。接下来使用完全不同的浏览器(或者干脆使用不同的计算机)访问这个 URL 并在其后也添加 ?PHPSESSID=1234。 读者可能已经注意到在这次访问中没有输出 1,而是继续了刚才的会话。
这是怎么发生的?多数会话固定攻击仅仅使用一个连接或者协议级的重定向让用户访问远程站点上含有会话标识的 URL。如果两个网站相当类似的话,用户可能无法留意到。由于攻击者确定了会话标识,这是已知的,这就可以实现如会话劫持这样的攻击。
这样简单的攻击是非常容易防范的。如果一个活动的会话中用户没有提供存在的会话标识,则重新生成这个标识:
<?php session_start(); if (!isset($_SESSION['initiated'])) { session_regenerate_id(); $_SESSION['initiated'] = true; } ?> |
这个简单防范的问题在于攻击者可以仅仅初始化一个有着指定会话标识的会话,然后使用这个标识来实现攻击。
防范这种攻击,首先应当考虑,会话劫持只有在用户登录或者有较高权限时才有实际用途。所以,当权限发生变更时重新生成会话标识(例如,修改了用户名或密码),可以有效去除成功的会话固定攻击的风险。