【问题标题】:Session hash does size matter?会话哈希大小是否重要?
【发布时间】:2011-03-06 14:08:46
【问题描述】:

在选择正确的算法用于会话哈希时,大小是否重要。

我最近阅读了这个article,它建议使用漩涡为会话 ID 创建一个哈希。 Whirlpool 生成一个 128 字符的哈希字符串,这个是不是太大了?

计划是将会话哈希存储在数据库中。使用 64 个字符字段 (sha256)、96 个字符字段 (sha384) 或 128 个字符字段 (whirlpool) 之间有很大区别吗?惠而浦最初提出的论点之一是速度与其他算法的对比,但从速度结果来看 sha384 并不算太差。

可以选择截断散列以使其小于 128 个字符。

我确实修改了原始代码 sn-p,以允许根据需要更改算法。

更新:有一些关于字符串被散列的讨论,所以我已经包含了代码。


function generateUniqueId($maxLength = null) {
    $entropy = '';

    // try ssl first
    if (function_exists('openssl_random_pseudo_bytes')) {
        $entropy = openssl_random_pseudo_bytes(64, $strong);
        // skip ssl since it wasn't using the strong algo
        if($strong !== true) {
            $entropy = '';
        }
    }

    // add some basic mt_rand/uniqid combo
    $entropy .= uniqid(mt_rand(), true);

    // try to read from the windows RNG
    if (class_exists('COM')) {
        try {
            $com = new COM('CAPICOM.Utilities.1');
            $entropy .= base64_decode($com->GetRandom(64, 0));
        } catch (Exception $ex) {
        }
    }

    // try to read from the unix RNG
    if (is_readable('/dev/urandom')) {
        $h = fopen('/dev/urandom', 'rb');
        $entropy .= fread($h, 64);
        fclose($h);
    }

    // create hash
    $hash = hash('whirlpool', $entropy);
    // truncate hash if max length imposed
    if ($maxLength) {
        return substr($hash, 0, $maxLength);
    }
    return $hash;
}

【问题讨论】:

  • 不管她告诉你什么,尺寸很重要!说真的,所有这些都非常与他们今天的存储介质相比,如果你有大量的会话(数百万),更长的哈希使得冲突更少 可能,但已经非常、非常非常不太可能。
  • 我认为她只是想让我振作起来,但是是的,我不希望处理数百万次会话。我主要关心的是索引以及 DBMS 如何处理这么大的字符字段。

标签: php algorithm session hash sessionid


【解决方案1】:

创建散列所花费的时间并不重要,只要您的数据库被正确索引,存储方法也不应该是主要因素。

但是,每次都必须将哈希值与客户端的请求一起传输,通常作为 cookie 进行传输。大型 cookie 可以为每个请求增加少量额外时间。请参阅Yahoo!'s page performance best practices 了解更多信息。较小的 cookie,因此较小的散列,有好处。

总体而言,大型散列函数可能不合理。由于它们的范围有限,好的旧 md5 和 sha1 可能只是作为会话令牌背后的来源。

【讨论】:

  • 所存储的哈希值可以持续数小时到数周。出于一次性使用令牌的目的,将使用较小的哈希值。
  • 如果您的 session 哈希值持续数周,则说明您的 GC 已损坏和/或您有疯狂的用户。边缘情况。
  • 哈希值可能会持续数周,因为用户首选项存储在数据库中并链接到存储在 cookie 中的哈希值,cookie 的有效期可能短至 24 小时——尽管 cookie 通常是设置为自上次访问后 21 天到期。在此期间,可能有数千名用户访问过该站点。顺便说一句,当我提到会话时,我指的不是由 PHP 设置的会话,它通常在浏览器关闭时过期。我希望这可以消除任何混淆。
  • 您为什么要这样做,而不是将首选项附加到用户登录并提示用户登录?
  • 因为并非所有偏好都要求用户登录或注册。
【解决方案2】:

是的,大小很重要。

如果太短,您可能会发生碰撞。您还可以让攻击者通过暴力攻击找到其他人的会话。

太长没那么重要,但是会话 ID 的每个字节都必须随着每个请求从浏览器传输到服务器,所以如果你真的在优化事情,你可能不想要一个太长的 ID。

不过,您不必使用哈希算法的所有位 - 没有什么可以阻止您使用 Whirlpool 之类的东西,然后只使用前 128 位(十六进制的 32 个字符)。实际上,128 位也是一个很好的长度下限。

不过,正如埃里克森所指出的,使用散列有点奇怪。除非您的输入熵至少与您使用的 ID 长度一样多,否则您很容易受到猜测哈希输入的攻击。

【讨论】:

  • 如果我只取前 32 个字符,那么继续使用 md5 是否有意义?我这样说是因为截断漩涡散列不会增加冲突的机会,因为前 32 个字符的可能引擎盖在任意数量的散列中相同都高于 md5。做出这个假设是因为 md5 本身生成 32 个字符的十六进制,而不是来自漩涡散列的 128 个字符。在这方面我可能完全不感兴趣。
  • 哈希中的“弱点”有两个不同的原因。有哈希本身的构造,还有哈希的长度。 MD5 在第一次计数时被反复破坏,但 128 位仍然是一个足够大的搜索空间,使得通过蛮力查找冲突变得不切实际。对于任何安全散列,您可以获取它的任意子集,并且它将与相同长度的任何其他子集一样好。如果一个大散列的子串比一个较短散列的完整输出弱,那意味着大散列被破坏了,因为它的输出部分是可预测的。
【解决方案3】:

当我尝试阅读该文章时超时,但我想不出使用哈希作为会话标识符的充分理由。会话标识符应该是不可预测的;鉴于文章的标题,听起来作者承认了这一原则。那么,为什么不使用加密随机数生成器来生成会话标识符呢?

哈希接受输入,如果输入是可预测的,那么哈希也是可预测的,这很糟糕。

【讨论】:

  • 我已经更新了我的原始帖子以包含如何生成哈希输入的代码。
【解决方案4】:

SHA1 或 MD5 可能足以满足您的需求。在实践中,发生碰撞的可能性很小,很可能永远不会发生。

不过,最终这一切都取决于您所需的安全级别。还要记住,更长的哈希计算成本更高,并且需要更多的存储空间。

【讨论】:

    猜你喜欢
    • 2015-11-27
    • 1970-01-01
    • 2015-04-24
    • 1970-01-01
    • 1970-01-01
    • 2013-12-21
    • 2011-02-07
    • 2019-02-05
    相关资源
    最近更新 更多