防止会话劫持
Posted
技术标签:
【中文标题】防止会话劫持【英文标题】:Preventing session hijacking 【发布时间】:2012-08-27 08:06:18 【问题描述】:如何防止多个客户端使用相同的会话 ID?我问这个是因为我想添加一个额外的安全层来防止我的网站上的会话劫持。如果黑客以某种方式找出另一个用户的会话 ID 并使用该 SID 发出请求,我如何检测到服务器上存在共享单个 SID 的不同客户端然后拒绝劫持尝试?
编辑
经过仔细考虑,我接受了 Gumbo 的回答,因为我已经意识到由于 无状态 HTTP 协议的限制,我所要求的是不可能的。我忘记了可能是 HTTP 最基本的原理是什么,现在想想这个问题似乎有点琐碎。
让我详细说明我的意思:
用户 A 在 example.com 上登录后,会获得一些随机会话 ID,为简单起见,将其设为“abc123”。此会话 ID 作为 cookie 存储在客户端,并通过服务器端会话进行验证,以确保登录的用户在从一个网页移动到另一个网页时保持登录状态。如果 HTTP 不是无状态的,那么这个 cookie 当然不需要存在。因此,如果用户 B 窃取了用户 A 的 SID,并在他的计算机上创建了一个值为“abc123”的 cookie,那么他将成功劫持用户 A 的会话,但服务器根本无法合法地识别用户 B 的会话。请求与用户 A 的请求有任何不同,因此服务器没有理由拒绝任何请求。即使我们要列出服务器上已经处于活动状态的会话并尝试查看是否有人正在访问已经处于活动状态的会话,我们如何确定是另一个用户非法访问该会话而不是同一用户谁已经使用会话 ID 登录,但只是尝试用它发出另一个请求(即导航到不同的网页)。我们不能。检查用户代理?可以被欺骗 - 但作为纵深防御措施还是不错的。 IP地址?可以出于合法原因进行更改 - 但我建议检查 IP 的前两个八位字节之类的东西,而不是根本不检查 IP 地址,因为即使是数据计划网络上的用户出于完全合法的原因不断更改 IP通常只会更改其 IP 的最后两个八位字节。
总而言之,正是无状态 HTTP 谴责我们永远无法完全保护我们的网站免受会话劫持,但良好做法(如 Gumbo 提供的做法)足以防止绝大多数会话攻击.因此,试图通过拒绝同一 SID 的多个请求来保护会话不被劫持是非常可笑的,并且会破坏会话的全部目的。
【问题讨论】:
好吧!检查 IP 的前两个八位字节也无效。使用相同互联网服务的不同人可能具有相同的前两个八位位组,尽管他们总体上具有不同的 IP 地址。 前两个八位字节也可以合法地改变 - 例如在一个大型组织中,其中有多个通过不同 ISP 的互联网网关。 【参考方案1】:不幸的是,没有有效的方法可以明确地识别出来自攻击者的请求,而不是真正的请求。因为大多数反措施检查的属性,如 IP 地址或用户代理特性,要么不可靠(IP 地址可能在多个请求之间更改),要么很容易伪造(例如 User-Agent 请求标头),因此可能会产生不需要的误报(即真正的用户切换 IP 地址)或误报(即攻击者能够成功伪造具有相同 User-Agent 的请求)。
这就是为什么防止会话劫持的最佳方法是确保攻击者无法找到其他用户的会话 ID。这意味着您应该设计您的应用程序及其会话管理(1)攻击者无法通过使用足够的熵来猜测有效的会话 ID,以及(2)攻击者没有其他方法可以通过已知攻击获得有效的会话 ID /漏洞,如嗅探网络通信、跨站点脚本、通过Referer泄漏等。
也就是说,你应该:
使用足够的随机输入来生成会话 ID(请参阅 session.entropy_file、session.entropy_length 和 session.hash_function) 在传输过程中使用 HTTPS 保护会话 ID 将会话 ID 存储在 cookie 中而不是 URL 中,以避免通过 Referer 泄漏(参见 session.use_only_cookies) 使用HttpOnly
和Secure
属性设置cookie 以禁止通过javascript 访问(以防XSS 漏洞)并禁止通过不安全通道传输(参见session.cookie_httponly 和session.cookie_secure)
除此之外,您还应该重新生成会话 ID,同时在某些会话状态更改(例如登录后确认真实性或更改授权/权限)后使旧 ID 无效(请参阅session_regenerate_id
function),您还可以定期执行此操作以减少成功的会话劫持攻击的时间跨度。
【讨论】:
+1 我同意。我还要提到会话 ID 必须过期,并且 /dev/urandom 应该用作 entropy_file。 (blog.ptsecurity.com/2012/08/not-so-random-numbers-take-two.html)。 Session Riding 也就是 CSRF 也是一个问题。 我不明白。如果所有会话信息都存储在服务器上,怎么可能无法检索存储在自己服务器上的数据?我看过 php 的会话处理程序,但我不认为它完成了我正在寻找的东西,也许我错了? @Rook 我知道 Gumbo 的建议。最重要的是,我只想了解 PHP 是否具有检索所有活动会话的机制,如果没有,为什么?这在理论上似乎是可行的,因为 PHP 会话是服务器端的,所以必须有充分的理由不存在这样的机制,因为它对网站的安全性有巨大的好处。谢谢。 @AnanduMDas 但是您需要解密加密的 HTTP 消息才能读取 cookie。 Ini 指令session.entropy_file
、session.entropy_length
、session.hash_function
是removed as of PHP 7.1。【参考方案2】:
我们可以这样做吗?
在数据库中存储会话 ID。 还要存储该会话 ID 的 Ip 地址和 HTTP_USER_AGENT。 现在,当请求到达包含该匹配会话 id 的服务器时,请在脚本中检查它来自哪个代理和 ip。
可以通过为会话创建通用函数或类来使此基础工作,以便在处理每个请求之前对其进行验证。几乎不需要几微秒。但是,如果许多用户正在访问您的站点,并且您拥有庞大的会话数据库,那么这可能是一个很小的性能问题。但是,与其他方法相比,它肯定会非常安全,例如 => 使用再生会话。
在重新生成会话 ID 时,会话劫持的可能性再次很小。
假设,用户的会话 id 被复制,并且该用户有一段时间没有工作或处于活动状态,并且没有向具有旧会话 id 的服务器发出请求重新生成新的。然后,如果会话 id 被劫持,黑客将使用该会话 id 并向具有该 id 的服务器发出请求,然后服务器将以重新生成的会话 id 进行响应,以便黑客可以继续使用服务。实际用户将不再能够操作,因为他不知道重新生成的 id 是什么,以及请求中要传递的请求会话 id 是什么。完全消失了。
如果我在某处错了,请纠正我。
【讨论】:
【参考方案3】:针对会话劫持有许多标准防御措施。其中之一是将每个会话与单个 IP 地址匹配。
Other schemes 可以使用从以下位置生成的 HMAC:
客户端IP的网络地址 客户端发送的用户代理头 SID 存储在服务器上的密钥仅使用 IP 的网络地址的原因是,如果用户位于公共代理后面,在这种情况下,他们的 IP 地址可以随着每次请求而更改,但网络地址保持不变。
当然,为了真正安全,您真的应该对所有请求强制使用 SSL,这样 SID 就不会被潜在的攻击者截获。但并非所有网站都这样做(::cough:: Stack Overflow ::cough::)。
【讨论】:
ip 地址是不切实际的,检查用户代理是一个笑话,尤其是如果它存储在一个 cookie 值中,所以如果他有会话令牌,攻击者就知道 UA 是什么(但无论如何他应该知道如果他知道 cookie 的值)。你没有提到 cookie 标志。请阅读秋葵的答案。也不要自己构建会话处理程序,PHP的会话处理程序比这个更好。 hmac 不是一种加密方法。此外,如果会话 id 使用 XSS 或 OWASP A9 违规被盗,则攻击者还将拥有用户代理。 hmac 表示“散列消息验证码”,散列!= 加密,验证不同于保密,通常两者都需要。另外,我非常不喜欢您的会话处理程序。秋葵有正确的答案。 永远不要将散列函数与加密函数混淆,这可能是识别非密码学家的最佳方法。如果您不相信我,请尝试发帖到crypto.stackexchange.com。此外,您不能依赖攻击者控制的变量来实施访问控制。就像你建议有一个 cookie 变量,上面写着is_hacker=false
。
欺骗hmac?你到底在说什么?这就是我所说的:addons.mozilla.org/en-US/firefox/addon/user-agent-switcher 你不是在提议一个安全系统,因为你依赖于一个攻击者控制的变量,该变量攻击者总是知道。如果您有会话 ID,您将总是拥有令人难以置信的可预测用户代理。所以请删除这个糟糕的帖子,永远不要向任何人推荐这个系统!【参考方案4】:
会话劫持是一种严重的威胁,它必须通过使用安全套接字层来处理涉及事务的高级应用程序,或者使用简单的技术,如使用 cookie、会话超时和重新生成 id 等,如上所述。 互联网诞生时,HTTP 通信被设计为无状态的;也就是说,两个实体之间的连接仅存在于将请求发送到服务器所需的短暂时间段内,并将结果响应传递回客户端。 以下是黑客劫持会话的几种方法
网络窃听 不知情的暴露 转发、代理和网络钓鱼 反向代理始终推荐 SSL 安全套接字层 使用 cookies 在脚本开始时遵循 ini_set() 指令,以覆盖 php.ini 中的任何全局设置:
ini_set( 'session.use_only_cookies', TRUE );
ini_set( 'session.use_trans_sid', FALSE );
使用会话超时和会话重新生成 ID
<?php
// regenerate session on successful login
if ( !empty( $_POST['password'] ) && $_POST['password'] === $password )
// if authenticated, generate a new random session ID
session_regenerate_id();
// set session to authenticated
$_SESSION['auth'] = TRUE;
// redirect to make the new session ID live
header( 'Location: ' . $_SERVER['SCRIPT_NAME'] );
// take some action
?>
【讨论】:
【参考方案5】:在我看来,您可以在用户登录时将会话 ID 存储在数据库中,并在登录前检查每个人是否相同。在用户注销时删除您存储在数据库中的相同会话 ID。您可以轻松找到每个用户的会话 ID,否则我可以帮助您。
【讨论】:
在数据库中存储会话 id 会削弱会话。攻击者可以通过 sql 注入窃取它并登录,而无需破坏密码哈希。使用 php 的会话处理程序,不要自己滚动。 @Rook,我查看了 PHP 的会话处理程序,但我不确定如何使用它来解决我的问题。如果您知道如何实现 PHP 的会话处理程序以拒绝多个 SID,请将其作为答案发布。 @hesson Gumbo 的回答很棒。您使用其他人使用的保护系统。此外,请确保您的系统没有 XSS 缺陷和 owasp a9 违规,毕竟这是导致会话受损的最常见的两个缺陷。 @Rook,PHP 的会话处理程序支持数据库存储。 @Rook:如果您的站点中存在 SQL 注入漏洞,那么您已经遇到了严重的问题。解决方案不是将 SID 移出数据库(一个完全合理的放置位置),而是保护您的 SQL 注入漏洞——除非您建议安全站点根本不应该使用 SQL 数据库.【参考方案6】:其中一个简单的实现可以通过在数据库中创建一个表来完成,作为登录用户,然后在登录时,使用用户名和他的 SID 更新该表,这将防止其他用户以相同用户身份登录,现在在登出,只需运行一个简单的查询,它会删除数据库中的登录数据,这也可以用于一次跟踪您网站上的登录用户。
【讨论】:
这是一个不同问题的解决方案。这有助于防止单个用户从多个客户端登录。问题在于如何防止多个人冒充同一个用户和客户。【参考方案7】:显然,当您在浏览器中设置会话 cookie 时,该 cookie 会在请求中发送。现在,当请求到来时,服务器将检查数据库中的会话 ID 并授予访问权限。为了防止只有存储代理和 ip 很重要,以便在检查服务器之前确保会话访问被授予唯一的客户端,而不是可以被劫持的唯一会话 ID。
【讨论】:
【参考方案8】:我不太了解编码部分。所以我可以告诉你一个算法来做到这一点。如果用户从 LAN 网络嗅探会话 ID(假设用户和攻击者在同一个 LAN 中),则设置 SSL 之类的东西,或将会话 cookie 设置为安全和 httpOnly 将不起作用。
因此,您可以做的是,一旦用户成功登录应用程序,为 Web 应用程序的每个页面设置唯一令牌,并在服务器端对此进行跟踪。这样,如果有效用户发送访问特定页面的请求,该页面的令牌也会发送到服务器端。由于令牌对于特定会话的用户是唯一的,因此即使攻击者可以获得会话 ID,他也无法劫持用户会话,因为他无法向服务器提供有效令牌。
【讨论】:
【参考方案9】:@Anandu M Das:
我相信您可能指的是会话令牌与每个会话 ID 的使用。该站点可以解释令牌与会话的使用:
https://blog.whitehatsec.com/tag/session-token/
虽然会话令牌很容易受到 XSS 攻击的破坏,但这并不意味着它们永远不应该被使用。我的意思是让我们面对现实吧,如果服务器上的安全漏洞会损害某些东西,那不是方法的错,而是引入该漏洞的程序员的错(强调 Hesson 和 Rook 的观点)。
如果您遵循适当的安全约定和实践并保护您的站点免受 SQL 注入和 XSS 的攻击,并要求所有会话都通过 HTTPS 进行管理,那么您可以通过使用存储在内部的服务器端令牌轻松管理来自 CSRF 的潜在攻击会话,并在每次用户对其会话进行操作时更新(例如提交 $_POST)。此外,切勿将会话或其内容存储在 url 中,无论您认为它们的编码如何。
当您的用户的安全性至关重要时(应该如此),使用会话令牌将允许提供更好或更高级的功能,而不会影响他们的会话安全性。
【讨论】:
以上是关于防止会话劫持的主要内容,如果未能解决你的问题,请参考以下文章