crypto/rand.read() 是生成安全随机字节的唯一可靠入口,直接从操作系统熵池读取不可预测字节,需预分配缓冲区、检查错误、避免小块调用,并用rand.int(rand.reader, max)生成安全整数。

crypto/rand.Read() 是生成安全随机字节的唯一可靠入口
你要生成密码、token、AES密钥或 salt,crypto/rand.Read() 就是标准答案。它不依赖种子、不维护状态、不暴露内部逻辑,直接从操作系统熵池(Linux 的 /dev/urandom,Windows 的 BCryptGenRandom)读取不可预测字节。
常见错误是绕开 Read() 自己拼:比如用 math/rand.Intn(256) 循环填 byte slice,或者拿 crypto/rand.Read() 返回的字节再手动转 int——这既多余又容易出错(如切片长度不够导致 panic 或偏差)。
-
buf := make([]byte, 32)必须提前分配好长度,Read()不会帮你扩容 - 必须检查返回的
err:虽然 Linux/macOS 下极少失败,但在容器或 Windows 环境中可能返回io.EOF或io.ErrUnexpectedEOF - 不要多次小块调用:
Read(buf)一次填满比循环调用Read([]byte{0})效率高得多,也更少触发系统调用
rand.Int(rand.Reader, max) 是生成安全整数的正确方式
crypto/rand 包本身没有 Intn() 这类便捷函数,但你可以用 math/big 提供的 rand.Int() ——注意第一个参数传的是 crypto/rand.Reader,不是 math/rand.Rand 实例。
典型误用是写成 math/rand.Intn(100) 或 rand.New(rand.NewSource(...)).Intn(100),哪怕只用于生成验证码,只要它要防撞库,就属于安全场景,不能用。
在 Golang 中使用 samber/hot 进行内存缓存,支持 LRU、LFU、TinyLFU、W‑TinyLFU、S3FIFO、ARC、TwoQueue、SIEVE、FIFO 等淘汰算法,提供 TTL、缓存加载器及分片功能。
- 示例:生成 [0, 99] 内的安全随机整数
max := big.NewInt(100)<br>n, err := rand.Int(rand.Reader, max)
- 别自己用
binary.BigEndian.Uint64(buf)强转再取模:256 % 100 有偏差,且 buf 长度不足时会 panic -
rand.Reader是全局变量,线程安全,可直接使用,无需额外封装
math/rand 只能用在明确非安全场景
math/rand 不是 bug,它是设计成可复现的:默认种子固定,rand.Intn(10) 每次运行都一样。这适合单元测试、图形噪声、游戏抽卡——前提是“被猜中”不会导致账户被盗。
一旦你发现代码里有 time.Now().UnixNano() 做种子、或在 goroutine 里反复 rand.New(...),就要警惕:高并发下多个实例可能拿到相同时间戳,导致重复随机值。
- Go 1.20+ 正确初始化方式:
r := rand.New(rand.NewSource(time.Now().UnixNano())),不是rand.Seed() - 包级函数(如
rand.Intn())共享全局*rand.Rand,高并发时会成为 mutex 瓶颈,压测可见runtime.futex占比飙升 - 如果只是打乱 slice 顺序或生成 mock ID,
math/rand足够快;换成crypto/rand反而拖慢性能,还可能在低熵环境卡住
生成随机字符串时字符集偏差比长度更重要
很多人只关注“32位 token”,却忽略字符映射是否均匀。直接对 crypto/rand 输出的字节做 % 62(对应 0–9a–zA–Z)会导致某些字符概率略高——因为 256 ÷ 62 余 24,最后 24 个值会被丢进前 24 个字符里。
官方推荐做法是拒绝采样(rejection sampling):只接受 [0, 247] 范围内的字节(248 = 62 × 4),超出就丢弃重读。平均只需约 1.1 次读取就能得一个有效字符,性能影响可忽略。
- 别用
fmt.Sprintf("%x", buf):十六进制膨胀率 100%,且字符集窄 - URL 安全字符串优先用
encoding/base64.RawURLEncoding.EncodeToString(buf),不是base64.StdEncoding(含+和/) - 不要手写字符表拼接逻辑,先确保字节安全,再映射;源头不安全,后面再长也没用
crypto/rand 多花几纳秒,也别让 math/rand 少写一行代码埋下漏洞。golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










