如何在PHP中生成唯一的不可猜测的激活链接

时间:2014-01-02 22:03:59

标签: php mysql security

我整天都在阅读有关该主题的文章,但我不确定如何继续。

我有一个MySQL用户表,其主键为UUID_SHORT()值和一个电子邮件字段,这也是唯一的。我需要能够生成一个始终唯一的,不可猜测的ID,以便在激活URL中使用。像这样:

http://example.com/activate.php?id=tKd32f

阅读此问题后:How to code a URL shortener?

我已经实现了一个base58编码方法,我试图使用代表用户的UUID_SHORT()值,由MySQL服务器生成。

<?php
function base58_encode($num, $alphabet) 
{                           
    $base_count = strlen($alphabet);
    $alphabet =  str_split($alphabet);
    echo "base_count: " . $base_count . "<br>";
    $encoded = '';
    while ($num >= $base_count) 
    {
        $div = $num/$base_count;
        echo "div: " . $div . "<br>";
        $mod = ($num-($base_count*intval($div)));
        echo "mod: " . $mod . "<br>";
        echo "alphabet[$mod]: " . $alphabet[$mod] . "<br>";                             
        $encoded = $alphabet[$mod] . $encoded;
        echo "encoded: " . $encoded . "<br>";
        $num = intval($div);
        echo "num: " . $num . "<br>";
        echo "------------------------------<br>";
    }

    if ($num) $encoded = $alphabet[$num] . $encoded;

    return $encoded;
}

$alphabet = "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ";
echo "WORKS => " . base58_encode(3707787591, $alphabet) . "<br><br>"; // some random number
echo "DOES NOT WORK => " . base58_encode(23298059492392988, $alphabet); // one of the unique IDs in my database
?>

如果我使用10位数字,它可以工作。但是如果我使用较长的UUID_SHORT值,我会得到一个未定义的偏移量错误,因为$ num = intval($ div)在其param太大时返回一个负数。我似乎无法弄清楚原因,但似乎与:http://ca1.php.net/intval

有关

我的问题:

  1. 这甚至是正确的方法吗?我应该使用UUID_SHORT值来生成激活码还是太可猜测?如果我在MySQL服务器上多次执行SELECT UUID_SHORT(),你可以看到这个值增加1(这让我担心)。

  2. 如果这个base58_encode是正确的方法,我该如何解决这个错误?如何获得更短的激活码,与goo.gl的url缩短服务不同。他们是如何做到的呢?我找不到明确的答案。

  3. 我应该使用更多的内容吗? How to generate a secure activation string in php? 但是,这会生成一个非常长的ID。在我的情况下并不是真的有必要,它会产生更丑陋的激活URL。

  4. 我计划在一段时间后使我的网址过期,但ID必须始终是唯一的(理想情况下,足够短)。我也不需要稍后解码该值,因为我将唯一生成的ID映射到数据库中的用户ID。这里最好的方法是什么?

    感谢您的时间。

1 个答案:

答案 0 :(得分:1)

这是一个建议:

制作表格的网址

www.example.com/?code=XXXXX-YYYYY-ZZZZZ

其中

  • XXXXX是数据库中客户的唯一标识符

  • YYYYY是种子的小数部分,种子的另一部分存储在针对XXXXX的数据库中(YYYYY 存储)

  • ZZZZZ是XXXXXX的sha512哈希的随机段,以及存储在数据库中的段的起点和终点的完整种子。

  • 作为数据库中用于身份验证的最后一个字段(即计算标识符的第5个字段),有一个用于使链接过期的时间戳。

示例:

请求网址。

调用

uniqid()并将其分配给XXXXX(即13个字符)

让种子成为另一个uniqid("", true)的sha512哈希,并选择前5个字符作为YYYYY,将余数分配给数据库。

让ZZZZZ成为hash("sha512", SEED . XXXXX)的第8-15个字符,在数据库中存储8和15。 (随机选择8和15,ofc。)

将时间存储在数据库中。

通过电子邮件发送结果网址。

<强>讨论:

由于XXXXX创建时带有uniqid()和一个很难猜测黑客的点,因此轻微安全,但几乎100%独特。

由于种子未完全存储,但是需要验证ZZZZZ,因此实现了更高的安全性,但由于仅存储了子串,因此与使用较长的身份验证方案相比,可能更容易生成冲突

5个存储的元素形成了一种关键,可以通过一个不易逆转的多步骤过程来验证用户,因此知道该方法在破解方案时没有给予太多帮助(如果有的话)。 / p>

假设在链接失效之前只允许有限数量的猜测。

100%安全 - 没有什么依赖于点击的简单链接,其中链接包含验证所需的所有内容将永远是完全安全的,但它将使其具有相当大的挑战性黑客在允许的时间内实现黑客攻击(取决于您允许链接有效的时间长度)。

我希望这有帮助!