我试图了解有关PHP会话修复和劫持以及如何防止这些问题的更多信息。我一直在Chris Shiflett的网站上阅读以下两篇文章:

会话固定
会话劫持

但是,我不确定我是否了解事物正确。
为了帮助防止会话固定,在成功登录某人后足以致电session_regenerate_id(true);吗?我想我理解正确。
他还谈到了使用通过$_GET在URL中传递的令牌来防止会话劫持。究竟该怎么做?我猜想有人登录时会生成他们的令牌并将其存储在会话变量中,然后在每个页面上将该会话变量与$_GET变量的值进行比较?
是否需要更改此令牌?每个会话或每个页面加载仅一次吗?
还有一种防止劫持而不必在URL中传递值的好方法吗?这样会容易得多。

评论

也许您可以将链接添加到找到这些建议的页面。

#1 楼

好的,有两个单独但相关的问题,每个问题的处理方式都不相同。

会话修复

这是攻击者在此处为用户明确设置会话的会话标识符的地方。通常,在PHP中,可以通过给他们一个类似http://www.example.com/index...?session_name=sessionid的URL来完成。一旦攻击者将URL提供给客户端,攻击就与会话劫持攻击相同。

有几种方法可以防止会话固定(全部完成):


session.use_trans_sid = 0文件中设置php.ini。这将告诉PHP不要在URL中包含标识符,也不要读取标识符的URL。
session.use_only_cookies = 1文件中设置php.ini。这将告诉PHP永远不要使用带有会话标识符的URL。

每当会话状态改变时,都重新生成会话ID。这意味着以下任何一项:


用户身份验证
在会话中存储敏感信息
更改会话的任何内容
等...



会话劫持

这是攻击者保留会话标识符并能够发送请求的方式,就像他们是该用户一样。这意味着,由于攻击者具有标识符,因此就服务器而言,它们几乎与有效用户没有区别。

您不能直接防止会话劫持。但是,您可以采取措施使其变得非常困难和难以使用。


使用强大的会话哈希标识符:session.hash_function中的php.ini。如果PHP <5.3,则将SHA1设置为session.hash_function = 1。如果PHP> = 5.3,请将其设置为session.hash_function = sha256session.hash_function = sha512
发送一个强哈希值:session.hash_bits_per_character中的php.ini。将此设置为session.hash_bits_per_character = 5。虽然这不会使破解变得更加困难,但在攻击者尝试猜测会话标识符时,确实有所作为。该ID将更短,但使用更多字符。
session.entropy_file文件中使用session.entropy_lengthphp.ini设置附加熵。将前者设置为session.entropy_file = /dev/urandom,将后者设置为将从熵文件中读取的字节数,例如session.entropy_length = 256
从默认的PHPSESSID更改会话名称。这是通过在调用session_name()之前使用自己的标识符名称作为第一个参数调用session_start来实现的。
如果您真的很偏执,也可以旋转会话名称,但是请注意,如果更改此名称(例如,取决于时间),所有会话将自动失效。但是根据您的用例,可能是一个选择...
经常旋转您的会话标识符。我不会对每个请求都执行此操作(除非您确实需要这种安全级别),而是以随机间隔进行。您希望经常更改此设置,因为如果攻击者确实劫持了会话,则您不希望他们能够使用它太长时间。
$_SERVER['HTTP_USER_AGENT']中的用户代理包含在会话中。基本上,当会话开始时,将其存储在$_SESSION['user_agent']之类的东西中。然后,在每个后续请求上检查其是否匹配。请注意,这可能是伪造的,因此不是100%可靠的,但是总比没有好。
在会话中包括来自$_SERVER['REMOTE_ADDR']的用户IP地址。基本上,当会话开始时,将其存储在$_SESSION['remote_ip']之类的东西中。对于某些为其用户使用多个IP地址的ISP(例如曾经使用过的AOL),这可能会出现问题。但是,如果使用它,它将更加安全。攻击者伪造IP地址的唯一方法是在真实用户和您之间的某个时候破坏网络。而且,如果它们危害了网络,那么它们所做的工作远比劫持(例如MITM攻击等)还要糟糕。
在会话中以及您经常增加和比较的浏览器端添加令牌。基本上,对于每个请求,请在服务器端执行$_SESSION['counter']++。还可以在浏览器端的JS中执行某些操作(使用本地存储)。然后,当您发送请求时,只需简单地获取令牌的现时值,并验证服务器上的现时值相同。这样,由于攻击者将没有确切的计数器,因此您应该能够检测到被劫持的会话,或者如果攻击者没有,您将有2个系统传输相同的计数并可以辨别出其中一个是伪造的。这不适用于所有应用程序,但这是解决此问题的一种方法。

两者的说明

Session Fixing和Hijacking之间的区别仅在于如何会话标识符被泄露。在固定中,将标识符设置为攻击者事先知道的值。在“劫持”中,它是被用户猜测或被盗的。否则,一旦标识符遭到破坏,两者的效果将是相同的。

会话ID的重新生成

每当使用session_regenerate_id重新生成会话标识符时,都应删除旧会话。这对于核心会话处理程序是透明的。但是,某些使用session_set_save_handler()的自定义会话处理程序不会执行此操作,因此容易受到旧会话标识符的攻击。如果使用的是自定义会话处理程序,请确保跟踪打开的标识符,如果保存的标识符与保存的标识符不同,请在旧标识符上显式删除(或更改)标识符。

使用默认的会话处理程序,只需调用session_regenerate_id(true)就可以了。这将为您删除旧的会话信息。旧的ID不再有效,如果攻击者(或与此有关的任何其他人)尝试使用它,它将导致创建新的会话。不过请谨慎使用自定义会话处理程序。...

销毁会话

如果要销毁会话(例如,注销时),请确保彻底销毁它。这包括取消设置cookie。使用session_destroy

function destroySession() {
    $params = session_get_cookie_params();
    setcookie(session_name(), '', time() - 42000,
        $params["path"], $params["domain"],
        $params["secure"], $params["httponly"]
    );
    session_destroy();
}


评论


每个字符使用5位而不是4位不会以任何方式改变“强度”(在这种情况下,“强度”意味着什么)。但是,尽管您的观点总体上是可取的,但它们缺少一些重要的细节。例如,与旧会话ID关联的会话发生了什么,或者在具有旧会话ID的会话无效后应如何处理。

–浓汤
2011-02-22 17:29



@battal:不,这就是重点。 session_regenerate_id不会使仍然与旧ID相关联的会话无效;仅当delete_old_session参数设置为true时,会话才会被破坏。但是,如果攻击者启动了此ID重新生成怎么办?

–浓汤
2011-02-22 18:05



我不同意每次更改会话变量时的会话重新生成,仅应在登录/注销时完成。同样,检查用户代理是没有意义的,并且检查REMOTE_ADDR是有问题的。我想添加的一件事是session.entropy_file = / dev / urandom。事实证明,PHP的内部熵生成非常弱,并且/ dev / random或/ dev / uranom提供的熵池是在没有硬件rng的情况下在Web服务器上获得的最佳性能。

–rook
2011-2-22在18:30



另外,您应该添加session.cookie_httponly和session.cookie_secure。第一个有助于阻止xss(但它并不完美)。第二个是停止OWASP A9的最佳方法。

–rook
2011-2-22在18:34

不明白这样一个好答案,但却缺少最重要的内容:使用SSL / HTTPS。计数器增量是问题的根源,彼此之间很快就会有多个请求,用户刷新页面两次或点击提交按钮两次。如今,所有移动用户以及不断变化的IP都存在IP地址解决方案的问题。您可以看一下IP的第一组,但它仍然在麻烦。最好的办法是首先避免使用SSL / HTTPS发现会话ID。

– Sanne
13年1月1日在15:15

#2 楼

两种会话攻击都具有相同的目标:获得对另一个用户的合法会话的访问权限。但是攻击媒介是不同的:


在会话固定攻击中,攻击者已经可以访问有效会话,并试图迫使受害者使用此特定会话。
在会话劫持攻击中,攻击者试图获取受害者会话的ID以使用其会话。

在两种攻击中,会话ID都是这些攻击所关注的敏感数据。因此,对于读访问(会话劫持)和写访问(会话固定)都需要保护会话ID。

通过HTTPS保护敏感数据的一般规则在这种情况下适用也一样此外,您应该执行以下操作:

为防止会话固定攻击,请确保:仅从cookie(设置session.use_only_cookies设置为true),并仅在可能的情况下使其用于HTTPS(将session.cookie_secure设置为true);您可以同时使用session_set_cookie_params

要防止会话劫持攻击,请确保:


cookie中的会话ID仅可由服务器读取(将session.cookie_httponly设置为true
由于PHP的随机数生成器具有已知的弱点,因此使用了附加的熵源(请参阅session.entropy_file)。许多安全公告建议至少使用128位的熵长度(请参见session.entropy_length)。
使用了强大的加密哈希函数(请参见session.hash_function);充其量是像Whirlpool这样的计算量大的哈希函数,例如比MD5慢五倍,因此仅允许与MD5相反的哈希操作数量的五分之一。

要防止这两种会话攻击,请确保:


只接受您的应用程序启动的会话。您可以通过在启动客户端特定信息时为会话添加指纹来实现此目的。您可以使用User-Agent ID,但不要使用远程IP地址或请求之间可能更改的任何其他信息。
在尝试进行身份验证后使用session_regenerate_id(true)更改会话ID(仅在成功时才使用true)或更改特权并破坏旧会话。 (如果要保留与旧ID相关联的会话,请确保在重新生成ID之前使用$_SESSION存储对session_write_close的所有更改;否则,只有具有新ID的会话才会受到这些更改的影响。)
正确的会话到期实现(请参阅如何在30分钟后使PHP会话到期?)。


评论


很棒的帖子,尤其是最后一节。

–马蒂斯
2011年5月29日上午9:37

#3 楼

您提到的令牌是“ nonce”(编号)-一次使用过的数字。它们不一定必须只使用一次,但是使用时间越长,被捕获并用于劫持会话的几率就越高。

随机数的另一个缺点是,很难构建一个使用它们的系统,并允许以相同的形式存在多个并行窗口。例如用户在论坛上打开两个窗口,然后开始处理两个帖子:

window 'A' loads first and gets nonce 'P'
window 'B' loads second and gets nonce 'Q'


如果您无法跟踪多个窗口,则只能存储一个随机数-窗口B / Q的随机数。然后,当用户从窗口A提交帖子并传递随机数“ P”时,系统将拒绝该帖子为P != Q

评论


那么,这与会话固定有什么关系?

–rook
2011-2-22在17:00

特别是在同时使用许多AJAX请求的领域中,他有道理。

–DanielG
2012年4月18日14:40在

#4 楼

我没有阅读Shiflett的文章,但我认为您误会了一些内容。

默认情况下,只要客户端不接受cookie,PHP都会在URL中传递会话令牌。否则,在最常见的情况下,会话令牌以cookie的形式存储。

这意味着,如果将会话令牌放入URL,PHP将识别该令牌并随后尝试使用它。会话固定发生在某人创建会话,然后通过打开包含会话令牌的URL诱骗另一个用户共享同一会话时。如果用户以某种方式进行身份验证,那么恶意用户便会知道经过身份验证的会话令牌,这些会话令牌可能具有不同的特权。

我确定Shiflett解释说,通常要做的是每次用户权限更改时,都会重新生成一个不同的令牌。

评论


除此之外,请确保销毁任何先前打开的会话,因为它们在现有用户权限下仍然有效。

– corrodedmonkee
2011-2-22在17:20

#5 楼

是的,您可以通过在登录后重新生成会话ID来防止会话固定。这样,如果攻击者将不知道新认证的会话的cookie值。完全解决问题的另一种方法是在运行时配置中设置session.use_only_cookies=True。攻击者无法在另一个域的上下文中设置cookie的值。会话固定依赖于将cookie值作为GET或POST发送。