密码生成器
生成强随机密码,支持自定义长度和字符集
什么是密码生成器?
密码生成器用于创建随机字符串,作为用户账户、API 密钥、数据库凭据和加密密钥的密码。与人工选择的密码不同,生成的密码取自所有可能字符组合的完整空间,能有效抵御字典攻击和基于模式的猜测。本工具直接在浏览器中使用内置的加密随机数生成器,在线生成强随机密码。
密码强度取决于两个因素:长度和字符多样性。一个包含大写字母、小写字母、数字和符号的20位密码大约具有131比特的熵。在这一级别,即使攻击者每秒尝试一万亿次猜测,穷举所有组合所需的时间也将超过宇宙的年龄。计算方法很直接:熵 = 长度 × log2(字符集大小)。
NIST SP 800-63B 等标准建议密码长度至少为8个字符,且验证方不应设置长度上限,并不鼓励强制组合规则(如要求恰好包含一个符号),而是推荐使用更长的密码短语。对于机器间通信凭据和服务账户,在大多数安全框架和合规要求中,从完整字符集中随机生成20个或更多字符已是公认的基准。
为什么使用密码生成器?
人类并不擅长生成随机数。我们会重复使用密码、选择字典词汇、用可预测的模式替换字母(如用@代替a、用3代替e),并倾向于使用较短的字符串。密码生成器能从根本上消除这种人为偏差。
密码生成器使用场景
密码熵参考
熵衡量密码的不可预测性,计算方式为 log2(字符集大小 ^ 长度)。熵越高,攻击者需要搜索的可能组合就越多。NIST 和 OWASP 建议高安全性应用至少达到80比特的熵。
| 长度 | 字符集 | 熵 | 暴力破解时间 |
|---|---|---|---|
| 8 | lower + digits | ~41 bits | Minutes to hours |
| 12 | lower + upper + digits | ~71 bits | Centuries (offline) |
| 16 | all character sets | ~105 bits | Beyond brute-force |
| 20 | all character sets | ~131 bits | Beyond brute-force |
| 32 | all character sets | ~210 bits | Beyond brute-force |
| 64 | all character sets | ~419 bits | Beyond brute-force |
破解时间假设每秒猜测1万亿次(使用现代GPU进行离线攻击)。有频率限制的在线攻击速度要慢几个数量级。
CSPRNG 与 Math.random() 的密码生成对比
随机性来源与密码长度同样重要。使用可预测随机数生成器生成的密码,可能被了解算法和种子状态的攻击者重建。本工具使用 crypto.getRandomValues(),这是内置于每个现代浏览器中的密码学安全伪随机数生成器(CSPRNG)。
代码示例
在不同编程语言中以编程方式生成密码。以下所有示例均使用密码学安全的随机源,而非 Math.random() 或同等的弱伪随机数生成器。
// Generate a random password in the browser or Node.js 19+
function generatePassword(length = 20) {
const charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*'
const values = new Uint32Array(length)
crypto.getRandomValues(values)
return Array.from(values, v => charset[v % charset.length]).join('')
}
console.log(generatePassword()) // → "kR7!mZp$Xw2&nLq9@Yf3"
console.log(generatePassword(32)) // → "Hd4%tNx!Qw8#mKp2Rv6&Zj0*Ls3Yb7@"import secrets
import string
def generate_password(length: int = 20) -> str:
"""Generate a cryptographically secure random password."""
alphabet = string.ascii_letters + string.digits + string.punctuation
return ''.join(secrets.choice(alphabet) for _ in range(length))
# Single password
print(generate_password()) # → "kR7!mZp$Xw2&nLq9@Yf3"
# Batch of 5 passwords
for _ in range(5):
print(generate_password(24))
# Ensure at least one char from each category
def generate_strong(length: int = 20) -> str:
required = [
secrets.choice(string.ascii_uppercase),
secrets.choice(string.ascii_lowercase),
secrets.choice(string.digits),
secrets.choice(string.punctuation),
]
remaining = length - len(required)
alphabet = string.ascii_letters + string.digits + string.punctuation
all_chars = required + [secrets.choice(alphabet) for _ in range(remaining)]
secrets.SystemRandom().shuffle(all_chars)
return ''.join(all_chars)# OpenSSL — generate 32 random bytes, base64-encode openssl rand -base64 32 # → "x7Kp2mNqR4wZ8vLs1Yb0Hd6tFj3Xc9Ga5eUi+Wo=" # /dev/urandom with tr — alphanumeric + symbols, 20 chars tr -dc 'A-Za-z0-9!@#$%^&*' < /dev/urandom | head -c 20; echo # → "kR7!mZp$Xw2&nLq9@Yf3" # pwgen (install: apt install pwgen / brew install pwgen) pwgen -sy 20 5 # Generates 5 passwords, 20 chars each, with symbols
package main
import (
"crypto/rand"
"fmt"
"math/big"
)
func generatePassword(length int) (string, error) {
charset := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()"
result := make([]byte, length)
for i := range result {
idx, err := rand.Int(rand.Reader, big.NewInt(int64(len(charset))))
if err != nil {
return "", err
}
result[i] = charset[idx.Int64()]
}
return string(result), nil
}
func main() {
pwd, _ := generatePassword(20)
fmt.Println(pwd) // → "kR7!mZp$Xw2&nLq9@Yf3"
}