【问题标题】:How to generate unguessable "tiny url" based on an id?如何根据 id 生成不可猜测的“小 url”?
【发布时间】:2011-03-26 13:44:30
【问题描述】:

我有兴趣创建像链接这样的小 url。我的想法是简单地为每个发布的长 url 存储一个递增的标识符,然后将此 id 转换为它的 base 36 变体,如下所示:

$tinyurl = base_convert($id, 10, 36)

这里的问题是结果是可以猜测的,虽然很难猜测下一个 url 会是什么,同时仍然很短(很小)。例如。 atm 如果我的上一个 tinyurl 是 a1,下一个将是 a2。这对我来说是件坏事。

那么,我如何确保生成的小 url 不是那么容易猜到但仍然很短?

【问题讨论】:

    标签: php url-shortener tinyurl base36


    【解决方案1】:

    Hashids 是一个开源库,可从一个或多个数字生成短、唯一、非连续、类似 YouTube 的 ID。您可以将其视为一种混淆数字的算法

    它将像 347 这样的数字转换成像 "yr8" 这样的字符串,或者像 [27, 986] 这样的数组转换成 "3kTMd"。您还可以将这些 id 解码回来。这对于将多个参数捆绑到一个或仅将它们用作短 UID 很有用。

    您不想向用户公开您的数据库ids时使用它。

    它允许自定义字母和盐,所以 id 只对你来说是唯一的。

    增量输入被破坏以保持不可猜测。

    没有冲突,因为该方法基于整数到十六进制的转换。

    编写它的目的是将创建的 ID 放置在可见的位置,例如 URL。因此,该算法避免了生成最常见的英语诅咒词。

    代码示例

    $hashids = new Hashids();
    $id = $hashids->encode(1, 2, 3); // o2fXhV
    $numbers = $hashids->decode($id); // [1, 2, 3]
    

    【讨论】:

      【解决方案2】:

      我最终创建了一个标识符的 md5 总和,使用它的前 4 个字母数字,如果这是重复的,只需增加长度直到它不再是重复的。

      function idToTinyurl($id) {
          $md5 = md5($id);
          for ($i = 4; $i < strlen($md5); $i++) {
              $possibleTinyurl = substr($md5, 0, $i);
              $res = mysql_query("SELECT id FROM tabke WHERE tinyurl='".$possibleTinyurl."' LIMIT 1");
              if (mysql_num_rows($res) == 0) return $possibleTinyurl;
          }
          return $md5;
      }
      

      接受 relet 的回答,因为它引导我采用此策略。

      【讨论】:

        【解决方案3】:

        另一种方法是设置 URL 的最大字符数(假设它是 n)。然后,您可以选择一个介于 1 和 n! 之间的随机数,这将是您的排列数。

        在哪个新 URL 上,您将增加 id 并使用排列编号来关联将要使用的实际 id。最后,您将对您的 URL 进行 base 32(或其他)编码。这将是完全随机且完全可逆的。

        【讨论】:

        • 虽然通过这种方式重复 ID 是可能的,所以你必须检查它并在重复时再次增加。
        【解决方案4】:

        您要求的是在减少信息(在数据库中指向它们的索引的 URL)和人为增加信息(在您的序列中创建漏洞)之间取得平衡。

        你必须决定两者对你有多重要。另一个问题是您是否只是不希望顺序 URL 是可猜测的,或者让它们足够随机以使猜测 any 有效 URL 变得困难。

        基本上,您想声明 N 个有效 id 中的 n 个。选择N更小可以使URL更短,并且使n更小以生成难以猜测的URL。将 n 和 N 变大,以便在使用较短的 URL 时生成更多的 URL。

        要分配 id,您可以使用任何类型的随机生成器或哈希函数,并将其限制在您的目标范围 N。如果检测到冲突,请选择下一个随机值。如果您已达到 n 个唯一 ID 的计数,则必须增加 ID 集的范围(n 和 N)。

        【讨论】:

        • 关于你的最后一段。我认为他想要一个可以反转的值,即他想要一个单射函数。
        • 不,他想要一个不可猜测的函数,真的。 ;) 因为无论如何他都必须将 URL 存储在数据库中,所以他可以使用随机数作为索引。实现逆转。
        • 正确,不必是单射的。
        【解决方案5】:

        如果你想要一个单射函数,你可以使用任何形式的加密。例如:

        <?php
        $key = "my secret";
        $enc = mcrypt_ecb (MCRYPT_3DES, $key, "42", MCRYPT_ENCRYPT);
        $f = unpack("H*", $enc);
        $value = reset($f);
        var_dump($value); //string(16) "1399e6a37a6e9870"
        

        反转:

        $rf = pack("H*", $value);
        $dec = rtrim(mcrypt_ecb (MCRYPT_3DES, $key, $rf, MCRYPT_DECRYPT), "\x00");
        var_dump($dec); //string(2) "42"
        

        这不会给你一个以 32 为底的数字;它将为您提供每个字节转换为基数 16 的加密数据(即,转换是全局的)。如果您确实需要,您可以使用任何支持大整数的库轻松地将其转换为以 10 为底,然后以 32 为底。

        【讨论】:

        • 请记住,生成的网址必须很短(1399e6a37a6e9870 太长)。
        • @Tom 好吧,他可以将其转换为 base 64 左右并获得(我认为)11 个字符。或使用
        【解决方案6】:

        您可以预先定义 4 个字符的代码(所有可能的组合),然后将该列表随机化,并以此随机顺序将其存储在数据表中。当您想要一个新值时,只需从顶部抓取第一个并将其从列表中删除即可。它速度快,无需即时计算,并保证最终用户的伪随机性。

        【讨论】:

        • 我应该指出,这正是我为 URL 缩短器所做的,开始时有点痛苦。有很多可能的组合,这意味着您从一个庞大的数据库文件开始,以实现这样一个简单的概念。
        • @relet 你到底指的是什么?数量有限且无法增加的事实?如果是这样,那么一旦您开始用完 4 个字符的代码,然后计算所有 5 个字符的代码并将其插入到您的队列表中。
        【解决方案7】:

        尝试将 $id 与某个值进行异或,例如$id ^ 46418 - 并且要转换回您的原始 ID,您只需再次执行相同的 Xor,即 $mungedId ^ 46418。将它与你的 base_convert 堆叠在一起,也许在结果字符串中交换一些字符,猜测 URL 会变得非常棘手。

        【讨论】:

        • 对于一个稍微坚定的黑客来说,肯定是 - 对于 Joe Public,不是那么多。
        【解决方案8】:

        这真的很便宜,但如果用户不知道它正在发生,那么它就不是那么容易猜到了,而是用 2 或 3 个随机数字/字母对实际 id 进行前缀和后缀。

        如果我看到 9d2a1me3,我不会猜到 dm2a2dq2 是系列中的下一个。

        【讨论】:

          【解决方案9】:

          我只是 crc32 网址

          $url = 'http://www.google.com';
          $tinyurl = hash('crc32', $url ); // db85f073
          

          缺点:常量 8 字符长标识符

          【讨论】:

          • 我喜欢这个主意,但是 8 个字符的代码有点问题 - 现在使用 URL 缩短器,每个字符都很重要,8 个字符有点高。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2020-01-21
          • 2013-08-21
          • 2019-07-14
          • 2012-09-16
          • 1970-01-01
          • 2020-02-18
          • 1970-01-01
          相关资源
          最近更新 更多