PHP中的长随机字符串生成器

3

有没有办法在PHP中生成一个长字符串(例如280个字符)而不必使用一个循环遍历280次的for循环?我需要它来创建自定义会话ID。

在我看来,PHPSESSID不够安全,因为它太短并且不够随机。我知道Facebook和Twitter使用长会话ID(分别为150、550个字符)。

可能有一个选项可以使用不同字符串(如PHPSESSID、主机、User-Agent等)的MD5字符串或Bcrypt加密,但我不确定这是否是正确的方法。


4
为什么不使用 for 循环?只需使用字符数组,然后在循环中引用它们,如下所示:for ($i = 0; $i < 280; $i++) $buffer .= $characters[rand(0, $charactersLength)]; - h2ooooooo
3
循环有什么问题吗?如果想要减少循环次数,可以将几个哈希值合并。 - Shomz
循环没有问题,只是会使用一些内存,在访问量较高的网站上,这可能会稍微减慢加载时间。 - Andrei Stalbe
如果您不想使用for循环,您可以使用while循环。 - Billy Moon
我不想过于直言,但如果您的网站因为一个简单的循环迭代280次而变慢,那么您就有严重的问题了。在大多数现代硬件上,我们说的是100微秒左右...快速基准测试 - ircmaxell
4个回答

11
如果你提出这样的问题,那可能意味着你对密码学或安全一无所知。试图生成“长随机字符串”,因为“PHPSESSID不够安全”会导致您进行自定义且不安全的实现。
生成随机字符串是不可能的,至少在您当前的硬件上是如此:您可能会近似一个公平的伪随机生成器,但那只对教育目的有用。
PHP的Session ID生成算法相当有效;如果您认为它不够安全,则很可能会浪费时间使其更好。如果您想要最大的安全性,您可能需要使用不同的身份验证机制(例如使用客户端证书)。
如果像Twitter、Facebook或其他类似流量的网站使用较长的会话ID,可能不是因为它更安全(某种程度上来说也是),而是为了避免冲突。
最后,如果你想要一个更长的会话ID而又不想编写自己的算法,你应该使用以下PHP配置指令: session.hash_function 可以使用任何PHP已知的哈希算法。
你还可以使用 session.bits_per_characters 来缩短或延长字符串。请注意,如果这样做,字符串可能会更长或更短,但数据保持不变 - 只是以不同的方式表示(16进制、32进制等)。
额外信息:
您还可以通过使用自定义源(文件)并设置种子的长度来增加熵:
ini_set("session.hash_function", "sha512");
ini_set("session.bits_per_charater", 4); // 4 means hex
ini_set("session.entropy_file", "/dev/urandom");
ini_set("session.entropy_length", "512");

1
“PHPSESSID不够安全”与我的技能无关,而且你也不是评判的人。PHPSESSID的弱点并不是我发现的,而是在网络上广泛讨论的问题,但无论如何,感谢您抽出时间与我们分享您的想法和经验。 - Andrei Stalbe
1
我并不“评判”你的全局技能,我只是根据你的问题做出了一些假设。请不要生气。话虽如此,我已经删除了“技能”这个词,但它仍然适用。 - Boris Guéry
我并不因为你说的话而感到冒犯,因为我确实没有使用过cryptography,而我正在开发的应用程序需要更高的安全性。所以,我发布了这个问题,想知道别人对此有什么看法,最常见的方法是什么,我可以使用一个loop来生成一个字符串,并将其与用户User-Agentmd5连接起来,但不确定是否正确。 - Andrei Stalbe
1
@AndreiStalbe:这个答案以及PaulDixon提供的答案都清楚地表明,内置的PHP会话生成器非常好。会话劫持的可能性相当低,您甚至可以通过提供更好/更大的随机数据来进一步降低这些可能性。 - Alix Axel
谢谢你们的回答,真的帮助我决定了该走哪条路。 - Andrei Stalbe
这是正确的答案。最好的建议是关于将session.entropy_file设置为/dev/urandom。这是唯一可以将实际熵增加到可接受水平的方法。当您将其留空时,@AndreiStalbe所指示的问题会发生,php实际上使用rand()。但不,您不需要做任何花哨的事情。总的来说,永远不要以Facebook或Twitter作为您应该做的示例,它们有大多数开发人员只能梦想解决的问题(和专家来解决)。简单地说“但他们做x”并没有什么帮助... - ircmaxell

5

它可以是十六进制吗?

bin2hex(mcrypt_create_iv(140, MCRYPT_DEV_URANDOM));

如果您可以访问hash_pbkdf2()

hash_pbkdf2('sha256', PHPSESSID, mt_rand(), 1, 280, false);

1
这可能适用于他 bin2hex(mcrypt_create_iv(140, MCRYPT_DEV_URANDOM)) - Baba
1
哈希函数(如bcryptPBKDF2)被设计成需要大量的时间,这对于哈希密码而言是有利的,因为你需要很长时间才能找出原始密码。但如果要生成一个随机字符串,它完全不适合,所得到的ID将不会更加唯一或不可预测。第一种方法使用mcrypt_create_iv()最适合这项工作。 - martinstoeckli
@martinstoeckli:PBKDF2通过拉伸密钥(在我的示例中为2048次)来消耗时间。如果需要,您可以将其设置为非常低的值。 - Alix Axel
如果您不想进行迭代并将迭代次数设置为1,则可以直接调用sha256。这就像编写一个for循环,当您知道它仅运行一次时。迭代不会改善结果,只会让服务器变得繁忙。 - @Alix Axel - martinstoeckli
@martinstoeckli:不是这样的。1. 直接调用 sha256 永远不会产生 280 字节的字符串,而 PBKDF2 会。2. 迭代实际上会改善结果(从安全角度来看)- 虽然我认为这与 OP 的目标无关,这也是我更改它的原因。 - Alix Axel
@martinstoeckli:请参考http://www.php.net/manual/en/function.hash-hmac.php#109260,了解PBKDF2算法的实现。 - Alix Axel

4
您会发现,“长”会话ID中并非所有位都是纯随机的——它们可能提供附加信息以使应用程序能够快速提取关键信息。

默认情况下,PHP会话ID还不错,可以通过提供额外的熵(例如来自/dev/urandom)来改善。

请查看php源代码中的ext/session/session.c中的php_session_create_id。

这是它的流程:

  • 获取当前时间
  • 获得远程IP地址
  • 使用当前时间的秒和微秒以及IP地址构建一个字符串
  • 将其输入已配置的会话哈希函数(MD5或SHA1)
  • 如果配置了,则从熵文件中输入一些额外的随机性
  • 生成最终哈希值
因此,获取重复的或预测会话ID相当困难。

很抱歉我不能有两个正确答案来检查你的,但是谢谢你的解释。+1。 - Andrei Stalbe

-2

创建一个长字符串并随机打乱它。

$string = 'asdfhdfiadfshsdfDSGFADSFDSFDSFER524353452345';
$new_string = shuffle($string);

3
Shuffle使用的是rand()函数,这显然对于根据OP的要求不够随机。此外,这不会创建一个随机字符串,而是将某个字符串以“随机”的顺序排列。 - BudwiseЯ

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接