random_string() 默认不安全,因基于 mt_rand(),应改用 random_bytes() 或 Security::get_random_bytes() 生成密码级随机字符串。

random_string() 函数默认行为容易踩坑
它不返回密码级安全随机数,底层用的是 mt_rand(),不是 random_bytes() 或 crypto_rand()。这意味着在生成重置令牌、API密钥等敏感场景下,直接调用 random_string() 有被预测风险。
常见错误现象:本地开发时一切正常,上线后某些高并发请求下出现重复 token;或者安全扫描工具报“弱随机性”。
- 默认类型是
'alnum'(大小写字母 + 数字),长度默认 8 —— 这对 session ID 明显不够 - 不支持指定字符集,比如不能直接生成「不含 0/O/l/1」的易读码
- CodeIgniter 3 和 4 的
random_string()行为一致,但 CI4 中已建议迁移到Security类的get_random_bytes()
怎么生成真正安全的随机字符串(CI3/CI4 都适用)
绕过 random_string(),直接用 PHP 原生安全函数再做编码处理更可控。
使用场景:密码重置链接、临时访问凭证、JWT secret 初始化。
- CI3 用户可直接写:
$bytes = random_bytes(32);<br>return bin2hex($bytes);
- CI4 用户优先用:
$this->security->get_random_bytes(32);
,它内部已封装random_bytes()并处理异常 - 若需 base64 编码(更短):
rtrim(str_replace(['+', '/', '='], ['', '', ''], base64_encode(random_bytes(24))), ' ')
,注意去掉填充符和换行
想兼容旧逻辑但提升长度和字符范围?自己封装一个
别改框架源码,新建一个 helper 函数,复用 random_string() 的逻辑骨架,但替换随机源。
参数差异:保留 $type 和 $len 接口,但底层用 random_int() 替代 mt_rand()。
- 示例实现(CI3 放入
application/helpers/my_string_helper.php):function secure_random_string($type = 'alnum', $len = 8)<br>{<br> $pool = [];<br> if ($type === 'alnum') {<br> $pool = array_merge(range('a', 'z'), range('A', 'Z'), range('0', '9'));<br> } elseif ($type === 'numeric') {<br> $pool = range('0', '9');<br> }<br> $str = '';<br> for ($i = 0; $i < $len; $i++) {<br> $str .= $pool[random_int(0, count($pool) - 1)];<br> }<br> return $str;<br>} - 注意:必须启用
random_int()(PHP 7.0+),否则会 fatal error;CI3 默认最低要求 PHP 5.6,所以部署前先确认版本 - 这个函数不处理 Unicode,也不防碰撞,仅比原生
random_string()更难预测
生成“用户友好”随机码(比如邀请码)要额外过滤
直接用 random_string('alnum', 6) 可能产出 "O0l1I" 这种让用户崩溃的组合。
性能影响很小,但漏掉这步会导致客服量上升。
- 推荐字符池:
array_diff(range('a', 'z'), ['l', 'i', 'o']) + array_diff(range('A', 'Z'), ['I', 'O']) + range('2', '9') - 不要用正则全局替换(如
str_replace(['0','O','l'], '', $s)),可能把长度缩得太短 - CI4 中可结合
fake()(Faker library)生成语义化短码,但属于外部依赖,非核心方案
实际用的时候,先问清楚这个随机码是给机器看还是给人看、有没有并发唯一性要求、生命周期多长——这些决定了该用 random_bytes()、random_int() 还是简单 mt_rand()。很多人卡在第一步判断上。










