PHP会话变量有多安全?

55
我有一个登录脚本,它会根据“用户”表中的数据验证用户名/密码。此外,我还有一个“角色”表,用于指定给定用户的访问级别。假设我正在使用安全的登录脚本,那么仅在成功登录后对“角色”表执行附加查询以发现用户的授权级别并将其存储到会话变量中是否存在任何安全漏洞?然后,在任何具有混合权限的页面上,我可以简单地查询会话变量以发现已登录用户的授权级别。

谢谢。

4个回答

78

会话(Session)比 Cookie 更加安全。但是,有可能窃取会话并且黑客将完全访问该会话中的任何内容。一些避免这种情况的方法包括 IP 检查(效果相当好,但是很低端,因此仅凭它本身不可靠)和使用 nonce。通常情况下,使用一个每个页面的“令牌”来进行 nonce 验证,以便每个页面检查上一页的 nonce 是否匹配其存储的令牌。

在任何一种安全检查方式中,都会降低可用性。如果使用 IP 检查,而用户位于内部网络防火墙后面(或其他造成这种情况的情形),该用户将不得不在每次丢失 IP 时重新进行身份验证。使用 nonce 时,你可能会遇到“点击返回按钮将导致此页面崩溃”的状况。

但是对于 Cookie,黑客可以通过相当简单的 XSS 技术窃取会话。如果将用户的会话 ID 存储为 Cookie,则他们也容易受到攻击。因此,即使只有能够进行服务器级别黑客攻击的人才能渗透会话(这需要更高级的方法和通常需要某种特权,如果你的服务器安全性良好),你仍然需要在每个脚本请求时进行一些额外的验证。不应同时使用 Cookie 和 AJAX,因为这会使得窃取 Cookie 后完全访问更加容易,因为您的 ajax 请求可能无法在每个请求中进行安全检查。例如,如果页面使用 nonce,但页面从未重新加载,则脚本可能仅检查是否匹配。如果 Cookie 保存了身份验证方法,我就可以使用窃取的 Cookie 和 AJAX 漏洞来恶意攻击。


29
需要注意的是,PHP将会话ID存储为一个cookie。 - Michael Mior
6
关于一次性数字码的维基文章比较简单,但有不错的链接:http://en.wikipedia.org/wiki/Cryptographic_nonce 。据我理解,它的基本思想就像一个令牌,但只能使用一次(只用一次的号码)。每个页面请求都会检查上一个数字码并创建一个新的数字码。因此,如果我尝试对您的密码进行暴力破解攻击,我只有一次机会,因为在第二轮中数字码不匹配。如果我窃取了会话和该页面的数字码,我可以不断地发出请求并更新数字码,直到您发出请求并扰乱数字码匹配。因为它会看到我的请求和我的数字码,然后更新... - Anthony
@michaelmior:我非常确定那是事实,但最近对细节感到困惑。或者让我重新表述一下:我害怕那是真的,但希望它不必成为真相。 - Anthony
1
@Anthony 如果您也为 AJAX 请求重新生成会话 ID,则无法利用“漏洞”。 - Pacerier
2
@Pacerier - 两年过去了,我和AJAX都有了很大的进步。现在我尽可能在每个层面上实现相同的安全技术,就像你所建议的那样。当时我不知道的一个功能是能够在每个请求上重置会话ID。这不仅减少了被盗用会话ID cookie的风险,而且每个请求都会执行,因此ajax和标准请求都可以获得相同的安全性好处(以及潜在的漏洞)。 - Anthony
显示剩余3条评论

18

只有在您的服务器上执行的脚本才能访问_SESSION数组。如果您定义了会话cookie的范围,甚至可以将其限制在特定目录中。除了您之外,其他人获取该会话数据的唯一方式是将一些PHP代码注入到您的页面中。

至于您使用的系统,这是可以接受的,也是一种节省数据库调用的好方法,但请记住,它需要用户注销并重新登录以应用任何授权更改。因此,如果您想锁定一个帐户而该用户已经登录,则无法实现。


14

需要注意的是,在 Apache 中,PHP $_SESSION 超全局变量可以在虚拟主机之间进行访问。考虑以下情况:

  • 您的服务器托管了两个域名,example.com 和 instance.org。PHP 会话存储在受限于域名的 cookie 中。
  • 用户登录 example.com 并收到一个会话 ID。Example.com 设置一些会话变量(这些变量存储在服务器上,而不是 cookie 中)。
  • 第三方在传输期间截获 cookie 并将其传递给 instance.org。现在,instance.org 可以访问 example.com 的会话变量。

当你控制服务器上的所有虚拟主机时,这并不是什么大问题,但如果你在共享的机器上,这就是个问题。


1
你知道如何限制每个虚拟主机只有一个超级全局变量吗?如果可以的话。 - JRsz
@JRsz,您可以通过php.ini或session_save_path()函数(http://php.net/manual/en/function.session-save-path.php)更改存储会话的目录。 - SandroMarques

3
如果您依赖于存储在会话变量中的值来确定角色,则会失去更改DB中的值并反映在用户当前会话中的能力。如果您看一下Zend Framework,就会清楚地区分身份验证和授权,并在手册中强烈警告仅在会话中存储最少量的数据(即“是的,他是第37个用户,他登录了”)。
至于“安全性” - 除非您使用共享主机,否则无需担心。在正确配置的共享主机上,它们也应该相对安全。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接