dongsuo0517 2014-07-01 17:13
浏览 190

在PHP中为URL生成随机字符

I have answered with my own implementation (below), where I'd appreciate if you could check the maths and logic, but I realise there are other possibilities as well.


I'm trying to generate 32 random characters to be used in a registration URL.

The new account is partially created by a member of staff (setting the name/email), and a plain text email is sent to the new user so they can confirm their email address and set their password.

Trying to keep to [A-Za-z0-9] characters, I believe this creates a base 62 system, taking just under 6 bits to store... which is just over 190 bits of entropy? or 190.53428193238?

As this is a security feature, I don't believe uniqid() alone is a good idea, as this is based on the current microtime.

And I don't believe using encryption or hashing of the users ID or email address is a good solution either (collisions, low entropy, and presumably secured by a single key).

  • 写回答

1条回答 默认 最新

  • du94414 2014-07-01 17:13
    关注

    This works, with the PHP 7.0 random_bytes() function:

    <?php
    
    function random_key($length, $safe = false) {
    
        if ($safe !== false) {
            $bad_words = array_map('trim', file('/path/to/bad-words.txt', FILE_IGNORE_NEW_LINES));
        } else {
            $bad_words = NULL;
        }
    
        $j = 0;
    
        do {
    
            $bytes = (ceil($length / 4) * 3); // Must be divisible by 3, otherwise base64 encoding introduces padding characters, and the last character biases towards "0 4 8 A E I M Q U Y c g k o s w".
            $bytes = ($bytes * 2); // Get even more, because some characters will be dropped.
    
            $key = random_bytes($bytes);
            $key = base64_encode($key);
            $key = str_replace(array('0', 'O', 'I', 'l', '/', '+'), '', $key); // Make URL safe (base58), and drop similar looking characters (no substitutions, as we don't want to bias certain characters)
            $key = substr($key, 0, $length);
    
            if (preg_match('/[^a-zA-Z0-9]/', $key)) {
                exit_with_error('Invalid characters detected in key "' . $key . '"');
            }
    
            $valid = (strlen($key) == $length);
    
            if ($bad_words) {
                foreach ($bad_words as $bad_word) {
                    if (stripos($key, $bad_word) !== false) {
                        $valid = false;
                        break;
                    }
                }
            }
    
            if ($valid) {
                return $key;
            }
    
        } while ($j++ < 10);
    
        exit_with_error('Cannot generate a safe key after 10 attempts.');
    
    }
    
    ?>
    

    This code shows how the base64_encode() function can biases to certain characters:

    <?php
    
    $characters = [];
    
    for ($k = 0; $k < 500000; $k++) {
    
        $key = base64_encode(random_bytes(32)); // 32 bytes results in "=" padding; try changing to 30 to fix.
    
        foreach (str_split($key) as $c) {
            if (!isset($characters[$c])) {
                $characters[$c] = 0;
            }
            $characters[$c]++;
        }
    
    }
    
    $characters = array_filter($characters, function($value) {
            return ($value > 343750); // ((((33/3)*4)*500000)/64) = 343750, everything else is about ~327000
        });
    
    ksort($characters, SORT_STRING);
    
    print_r($characters);
    
    ?>
    
    评论

报告相同问题?

悬赏问题

  • ¥30 VMware 云桌面水印如何添加
  • ¥15 用ns3仿真出5G核心网网元
  • ¥15 matlab答疑 关于海上风电的爬坡事件检测
  • ¥88 python部署量化回测异常问题
  • ¥30 酬劳2w元求合作写文章
  • ¥15 在现有系统基础上增加功能
  • ¥15 远程桌面文档内容复制粘贴,格式会变化
  • ¥15 这种微信登录授权 谁可以做啊
  • ¥15 请问我该如何添加自己的数据去运行蚁群算法代码
  • ¥20 用HslCommunication 连接欧姆龙 plc有时会连接失败。报异常为“未知错误”