PHP会话修复/劫持

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

  • 会话固定
  • 会话劫持

但是,我不确定我是否正确地理解事情。

为了防止会话固定,只需调用session_regenerate_id(true)即可​​; 成功logging某人后? 我想我理解正确。

他还谈到使用通过$ _GET在URL中传递的令牌来防止会话劫持。 这将如何完成? 我在猜测什么时候有人login你生成他们的令牌并将其存储在一个会话variables,然后在每个页面上,你会比较该会话variables$ _GETvariables的值?

这个令牌是否需要在每个会话或每个页面加载中只更改一次?

他们也是防止劫持而不必在URL中传递价值的好方法吗? 这将是更容易。

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

会话固定

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

有几种方法可以防止会话固定(全部都是这样):

  • 在你的php.ini文件中设置session.use_trans_sid = 0 。 这将告诉PHP不要在URL中包含标识符,也不要读取标识符的URL。

  • 在你的php.ini文件中设置session.use_only_cookies = 1 。 这将告诉PHP从不使用具有会话标识符的URL。

  • 在会话状态发生变化时重新生成会话ID。 这意味着以下任何一项:

    • 用户authentication
    • 在会话中存储敏感信息
    • 改变会议的任何事情
    • 等等…

会话劫持

这是攻击者获取会话标识符的地方,并且能够发送请求,就好像它们是该用户一样。 这意味着,由于攻击者具有标识符,它们与服务器的有效用户几乎没有区别。

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

  • php.ini使用强大的会话哈希标识符: session.hash_function 。 如果PHP <5.3,则将其设置为SHA1的session.hash_function = 1 。 如果PHP> = 5.3,则将其设置为session.hash_function = sha256session.hash_function = sha512

  • php.ini发送一个强大的散列: session.hash_bits_per_character 。 将其设置为session.hash_bits_per_character = 5 。 虽然这并没有使其更难破解,但是当攻击者试图猜测会话标识符时它确实有所帮助。 ID会更短,但使用更多的字符。

  • php.ini文件中用session.entropy_filesession.entropy_length设置一个额外的熵。 将前者设置为session.entropy_file = /dev/urandom ,将后者设置为将从熵文件读取的字节数,例如session.entropy_length = 256

  • 从默认的PHPSESSID更改会话的名称。 这是通过在调用session_name()之前调用带有您自己的标识符名称的session_name()作为第一个参数来完成的。

  • 如果你真的偏执,你也可以旋转会话名称,但是要注意,如果你改变这个(例如,如果你依赖于时间),所有会话将自动失效。 但取决于你的使用情况,这可能是一个select…

  • 经常旋转你的会话标识符。 我不会这样做每一个请求(除非你真的需要这样的安全级别),而是在一个随机的时间间隔。 你想经常改变这个,因为如果攻击者劫持了一个会话,你不希望他们能够使用它太久。

  • 在会话中包含来自$_SERVER['HTTP_USER_AGENT']的用户代理 。 基本上,当会话开始时,将其存储在$_SESSION['user_agent'] 。 然后,在每个后续请求检查它匹配。 请注意,这可能是伪造的,所以它不是100%可靠的,但总比不好。

  • 在会话中包含$_SERVER['REMOTE_ADDR']的用户IP地址 。 基本上,当会话开始时,将其存储在$_SESSION['remote_ip'] 。 某些ISP为其用户使用多个IP地址(例如AOL曾经这样做)可能会造成问题。 但是,如果你使用它,它会更安全。 攻击者伪造IP地址的唯一方法是在真实用户和您之间的某个时间点对networking进行攻击。 如果他们妥协networking,他们可以做比劫持(如MITM攻击等)更糟糕的。

  • 在会话中和浏览器端添加一个令牌,用于增加和比较。 基本上,每个请求在服务器端做$_SESSION['counter']++ 。 在浏览器端也做一些JS操作(使用本地存储)。 然后,在发送请求时,只需取一个令牌的随机数,并validation服务器上的随机数是否相同。 通过这样做,您应该能够检测到被劫持的会话,因为攻击者没有确切的计数器,或者如果他们确实有两个系统传输相同的计数,并且可以告诉一个人是伪造的。 这不适用于所有应用程序,而是解决问题的一种方法。

关于这两个的说明

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

会话ID重新生成

每当使用session_regenerate_id重新生成会话标识符时,都应删除旧会话。 核心会话处理程序透明地发生这种情况。 但是,一些使用session_set_save_handler()自定义会话处理程序不会执行此操作,并且会对旧会话标识符进行攻击。 确保您使用的是自定义会话处理程序,并跟踪所打开的标识符,如果与您保存的标识符不同,则显式删除(或更改)旧标识符。

使用默认的会话处理程序,只要调用session_regenerate_id(true) 。 这将为您删除旧的会话信息。 旧ID不再有效,如果攻击者(或其他任何人)试图使用旧ID,将导致创build新会话。 虽然自定义会话处理程序请小心….

销毁会话

如果你要销毁会话(例如注销),请确保彻底销毁它。 这包括取消设置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(); } 

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

  • 会话固定攻击中 ,攻击者已经有权访问一个有效的会话,并试图强制受害者使用这个特定的会话。

  • 会话劫持攻击中 ,攻击者试图获取受害者会话的ID来使用他/她的会话。

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

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

要防止会话固定攻击,请确保:

  • 会话ID只能从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 ) 许多安全build议表明至less有128位熵长度(参见session.entropy_length
  • 使用了强大的encryption散列函数(请参阅session.hash_function ); 最好是像惠而浦这样的计算成本很高的散列函数 ,比MD5慢5倍,因此只允许与MD5相反的散列运算的五分之一。

为了防止两次会话攻击,请确保:

  • 只接受你的应用程序启动的会话。 您可以通过指定客户特定信息启动会话来完成此操作。 您可以使用用户代理 ID,但不要使用远程IP地址或可能在请求之间更改的任何其他信息。
  • 在身份validation尝试后使用session_regenerate_id(true)更改会话ID(仅在成功时为true )或更改特权并销毁旧会话。 (如果要保留与旧ID相关联的会话,请确保重新生成ID 之前使用session_write_close存储$_SESSION任何更改;否则只有具有新ID的会话才会受到这些更改的影响。
  • 使用适当的会话到期实现(请参阅30分钟后如何过期PHP会话? )。

您提到的令牌是“随机数” – 使用一次。 他们不一定只能使用一次,但是他们使用的时间越长,可以捕获并用于劫持会话的几率就越高。

随机的另一个缺点是build立一个使用它们的系统是非常困难的,并且允许在同一个窗体上有多个并行的窗口。 例如,用户在论坛上打开两个窗口,并开始在两个post上工作:

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

如果您无法跟踪多个窗口,则只会存储一个随机数 – 即窗口B / Q的随机数。 当用户从窗口A提交他们的post并通过随机数'P'时,系统将拒绝该post为P != Q

我没有读Shiflett的文章,但是我认为你误解了一些东西。

默认情况下,只要客户端不接受cookie,PHP就会在URL中传递会话标记。 在最常见的情况下,会话令牌存储为cookie。

这意味着如果您在URL中放置会话标记,PHP将会识别它并尝试随后使用它。 当某人创build一个会话,然后通过打开一个包含会话标记的URL来诱骗另一个用户共享同一个会话时,会话固定就会发生。 如果用户以某种方式进行身份validation,那么恶意用户就会知道经过身份validation的会话令牌,而这个身份validation会拥有不同的权限。

正如我相信Shiflett解释的那样,通常情况下,每当用户的权限改变时,重新生成一个不同的标记。

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