4

最近几天我一直在想它,但我读了一些关于如何使 PHP 会话更安全的文章。几乎所有这些文章都说您需要在会话中使用额外的盐保存用户代理。像这样的东西:

$fingerprint = md5('SECRET-SALT'.$_SERVER['HTTP_USER_AGENT']);

盐会使攻击者更难劫持或任何会话。但是为什么每次检查时都要加盐:

md5('SECRET-SALT'.$_SERVER['HTTP_USER_AGENT']) == $_SESSION [ 'fingerprint' ]

那么为什么盐会让它更安全,因为攻击者仍然只需要用户代理(相对而言是一小组不同的用户代理)和 sessionid?

可能是我忽略了一些小东西,但无法弄清楚,让我抓狂哈哈

谢谢!

4

9 回答 9

7

建议加盐的原因很简单。一般来说,当你创建这个“指纹”时——如果你只使用一个数据项,它的数据集有限,那么外部黑客就更容易生成它,并劫持会话。

在上面的示例中,是的,如果攻击者同时拥有“指纹”和用户代理,那么他们将能够劫持会话。

添加盐只会使攻击者更难生成指纹,这是“如果他们只有一条信息,那么最后一条信息将变得无用”的情况

我建议您添加更多内容,例如,在 vBulletin(我曾经从事的一个项目)中,使用以下代码生成会话 ID 哈希(与指纹基本相同)。

define('SESSION_IDHASH', md5($_SERVER['HTTP_USER_AGENT'] . $this->fetch_substr_ip($registry->alt_ip))); // this should *never* change during a session

此外,会话哈希是使用生成的

md5(uniqid(microtime(), true));

这些都在尝试识别会话时被检查

因此,要劫持会话,此人需要知道以下内容

  • 创建会话时服务器上的时间(准确)
  • 用户浏览器代理字符串
  • 用户的 IP 地址

他们还必须欺骗 IP 地址(或至少前 2/3 个八位字节)才能做到这一点。

如果他们实际上已经设法获得了上述信息,那么他们很可能能够以其他方式进行攻击,而不仅仅是会话劫持。

vBulletin 实际上并没有使用“盐”本身,但是,在你上面的例子中,盐只是增加了有限量的熵,总是最好找到尽可能多的熵。

例如,在我目前正在用 python 编写的东西中,我生成了一个散列以用于 XSRF 保护。以下是我使用的。

    self.key = sha1(
        self.user.username +
        self.user.password +
        settings.SECRET_KEY +
        strftime("%a, %d %b %Y %H:%M:%S +0000", gmtime())
    ).hexdigest()

它需要用户的用户名和密码、当前时间和预设的盐来生成它。由于盐和时间,这对于攻击者来说很难生成(不过,请注意,这只是因为一旦使用它就会改变,随着时间的推移,某人不需要太多如果它没有改变,则为特定用户破解它)

于 2009-03-05T21:47:34.690 回答
4

如果我理解正确,您想防止猜测会话 ID 的远程攻击者劫持会话?

如果不是这种情况,那么你就严重超出了你的深度 - 可以窥探流量的攻击者也可以模仿用户代理,并且获得对会话存储的访问权限的攻击者无论如何都会让你得到控制。

如果您存储用户代理字符串以将会话“锁定”到当前用户代理,那么散列它真的没有意义 - 完整用户代理字符串上的字符串比较更快(然后散列然后比较)并且不会更多在存储方面昂贵。

我不相信存储用户代理能提供足够的差异化——更好的办法是在会话开始时生成一个更大的 ID(具有更多位)(可能是 sha1 当前时间戳+用户名+用户代理+某些东西),然后将其存储在 cookie 和会话中,并在每个附加请求中匹配它。这不会对攻击向量有太大的改变(您仍然需要猜测一些数字),但是通过大量增加攻击的难度,很容易显着增加成功攻击必须猜测的位数。

更新:

其他答案顺便提到的但对于加盐哈希很重要的一点:如果您希望攻击者可以访问您存储的哈希而不是您的代码,然后以某种方式使用它来利用攻击,那么加盐您的哈希才有意义.

这对于长时间存储的密码很有意义,通常在众所周知的位置,并且由难以定位的代码使用。

这对您的用例没有意义,因为:

  1. 该信息仅在会话正在进行时(超时之前)才有效,这很少超过几个小时,之后 - 即使他们获得了存储并解码了所有内容 - 会话也无法被劫持,因为它已经结束。
  2. 通常,如果攻击者能够及时访问您的会话存储,他们就可以访问您的纯文本 PHP 代码并且可以看到您的 salt。
  3. 除非您将会话存储在完全不合理的位置(例如 S3 存储桶),否则与许多其他更有用的攻击相比,哈希窃取攻击的可能性要小得多。

简而言之:不要浪费时间编写会话验证代码——PHP 内置的会话管理已经足够安全了。

于 2009-03-05T21:50:15.073 回答
3

如果您在自己的服务器上,加密会话变量是没有意义的,因为它们不会离开服务器。请参阅Linead回答用户登录时我需要在 php 会话中存储什么?了解更多信息。如果您在共享服务器中,您可能需要加密除会话 ID 之外的每个会话变量,因为它们存储在所有邻居正在使用的同一 Web 服务器可以读取的临时文件中。

无论如何,如果您真的担心安全性,您最好使用自己的(虚拟或非虚拟)服务器,这样危险只会来自您的服务器外部。

您的会话风险的一些示例:

  • 您的服务器在 URL 中发送会话 ID,您的用户点击 badguys.com 的链接他们将在服务器变量中获取引用者(完整的 URL,包括您的会话 ID)、浏览器和用户的 IP 地址。如果您不检查 IP,或者您的用户使用开放代理,他们只需安装相同的浏览器版本,粘贴 URL,就可以完成。
  • 用户去公共电脑,登录,然后离开而不关闭他的会话(嘿,他毕竟是人)。行中的下一个人打开浏览器,检查历史记录并找到一个打开的会话。呸。

因此,按照我通常的偏好,您可以采取一些措施:

  1. 不要在 URL 中发送会话 ID;session.use_only_cookies在 PHP 中启用。缺点:用户需要启用 cookie。
    • 在危险操作(更改密码、下订单...)时,再次要求用户输入密码。您也可以定期进行。缺点:烦人。
    • 超时会话快。缺点:在大多数网站中,这会迫使用户经常登录,让他们很恼火。
    • 使用 SSL(避免“中间人”攻击的唯一方法)。缺点:慢。愚蠢的浏览器消息。服务器上需要 SSL。
    • 检查IP。缺点:对使用公共代理的访问者无效。烦人的动态IP。
    • 检查用户代理(浏览器)。缺点:几乎没用,UA 容易获得且难以模仿。

(我理所当然地认为您已经为最大安全性配置了 PHP)。

一些更极端的措施:

  • 保持服务器和浏览器之间的永久连接,例如使用 Java 小程序。没有连接,没有会话。缺点:用户需要 Java、ActiveX 或任何你使用的东西。会话通过浏览器关闭(这可能很好)。不适用于非常慢的连接。服务器负载较高。你需要打开端口,有一个专门的小程序服务器。
  • 相同,但使用异步请求(例如 AJAX)非常频繁地刷新会话,并且超时时间很短。或刷新隐藏的 IFRAME。缺点:用户需要 JavaScript。不适用于非常慢的连接。服务器负载较高。
  • 相同,但重新加载整个页面。缺点:用户需要 JavaScript。阅读页面时自动重新加载非常烦人。

在某些极端情况下,您可以忘记会话并改用 Apache 身份验证。最简单的解决方案,但有很多限制。

于 2009-08-22T02:37:17.650 回答
1

由于指纹存储在服务器端,因此您不需要使用加盐哈希。“正常”散列足以减少数据。

于 2009-03-05T20:54:20.387 回答
1

我认为加盐你的指纹有一个目的。如果一个坏人掌握了你的会话数据库(天知道为什么)但没有掌握你的代码,他就无法通过尝试常见的用户代理来“猜测”你的指纹识别方法。

于 2009-10-20T13:04:19.757 回答
0

请记住,如果您这样做,如果他们升级浏览器,您将强制人们再次登录。这可以,但只要确保这是您的意图。

Using the user's remote address is not without problems either. Many people use the same computer from different locations. Mobile devices, laptops being used at home and work, laptops being used at Wifi hotspots and so on. IMHO it's a bad idea to use IP address in such a way that a new IP address requires a login unless you're dealing with highly sensitive information such as online banking. Is that the case?

What are you concerned about? External attack? Or in a shared host situation that someone can read your session information?

If it's the latter, the solution is simple: just don't store anything sensitive in the session. Anything sensitive should be stored in the database.

在创建秘密盐方面,您需要使用不可猜测的东西。我会选择在创建用户时创建的随机字符串之类的东西。如有必要,每次会话无效时重新创建它。

至于什么会让它更安全,你自己说过:用户代理字符串是有限的(不到一百个可能会覆盖 99.99% 的用户)。盐只是增加了可能性的数量。话虽如此,如果您在所有会话中使用相同的盐,那么用蛮力发现它只是时间问题。

于 2009-03-05T21:31:09.440 回答
0

我这样做也是为了部分保护免受会话模拟攻击。您还需要包括 IP 地址。

请记住,当客户端的浏览器自动更新用户代理更改时,您会认为他的会话已被劫持;)

于 2009-03-05T20:52:36.677 回答
0

好的,例如我正在使用以下虚构代码:

<?php

// The sessionid cookie is now a certain hash
if ( array_key_exists ( $_COOKIE [ 'sessionid' ] ) )
{
    // Get the session from database
    $db_sessid = $pdo -> getStuff ( 'session_database', $_COOKIE [ 'sessionid' ] );

    if ( $db_sessid !== null && $db_sessid [ 'fingerprint' ] == sha1 ( 'SOMESALT' . $_SERVER [ 'HTTP_USER_AGENT' ] ) )
    {
        set_cookie ( ... ); // New sessionid and write also to DB

        // User is now logged in, execute some user stuff
    }
    else
    {
        // Session doesn't exist, or the fingerprint does not match
    }
}

现在攻击者只需要 sessionid,它在 cookie(随 HTTP 标头发送)和用户代理中。那么添加盐还有什么意义呢?

在我看来,检查 IP 也不是一个好选择,一些提供商或代理会在每个请求中更改它们。

到目前为止感谢(-:

于 2009-03-06T17:46:34.557 回答
-2

在满足所有安全参数后,您允许 cookie 仅设置一个 cookie,如果不满足参数,则 cokkie 将永远不会设置得很好,但如果 cookie 有一个可见的参数,那么会发生什么。同样,如果条件从未满足,则会议将不会被满足。这就是你真正想要的。记住检查满足条件通过 cookie 提供会话和查看数据的方式记住 cokkie 坐在客户端浏览器上问候 stelios

于 2020-02-08T21:59:45.303 回答