密码安全是一个系统属性,而不是字符数徽章。随机生成的密码仍可能因钓鱼、恶意软件、日志、复用、恢复流程或服务泄露而暴露。本文讨论熵值假设、CSPRNG 无偏采样、密码管理器、MFA 和事件响应,不把任何长度或工具写成安全保证。

目录

核心要点

  • 熵值取决于模型L × log₂(N) 只是均匀独立字符采样的理论上限,不是人类密码的实测值。
  • 长度有帮助但并非充分条件:唯一随机密码或独立抽取的词组优于可预测的复杂度模式。
  • CSPRNG 还要无偏采样:安全随机源仍可能被取模偏差、日志、剪贴板或复用削弱。
  • 避免常见密码:不要使用容易猜测的单词、短语或个人信息
  • 使用密码管理器:安全存储和管理所有密码
  • 启用多因素认证:为重要账户添加额外的安全层

不要把现有密码粘贴到生成器或“强度检测器”中。只生成新密码,通过可信流程传递,并存储在密码管理器中。

密码安全基础

什么是密码安全?

密码安全是指保护密码免受未授权访问和破解的实践和技术。一个安全的密码应该难以猜测或破解,同时对用户来说易于使用和记忆(或通过密码管理器安全存储)。

常见密码攻击方式

  1. 暴力破解:尝试所有可能的字符组合
  2. 字典攻击:使用常见单词、短语和密码列表
  3. 彩虹表攻击:使用预计算的哈希值表快速查找密码
  4. 社会工程学:通过欺骗获取密码
  5. 钓鱼攻击:伪装成可信实体获取密码
  6. 键盘记录器:记录用户的键盘输入

熵值:密码强度的科学衡量

熵值定义

熵值(Entropy)是衡量密码不确定性的科学指标,通常以比特(bits)为单位。熵值越高,密码越难破解,因为攻击者需要尝试更多的可能组合。

熵值计算公式

熵值的计算公式为:

code
理论搜索空间(比特) = 密码长度 × log₂(字符集大小)

例如:

  • 8位纯小写字母密码:8 × log₂(26) ≈ 8 × 4.7 = 37.6 比特
  • 12位混合密码(大小写字母+数字):12 × log₂(62) ≈ 12 × 5.95 = 71.4 比特
  • 16位全字符集密码(大小写字母+数字+符号):16 × log₂(94) ≈ 16 × 6.55 = 104.8 比特

不同密码类型的熵值对比

密码类型 长度 字符集大小 理论比特数 解释
纯数字 6 10 20 搜索空间较小
纯小写字母 8 26 37.6 理论搜索空间
混合(大小写+数字) 10 62 59.5 理论搜索空间
全字符集 12 94 78.6 理论搜索空间
全字符集 16 94 104.8 理论搜索空间

这些数字假设字符独立且均匀采样,不能直接预测破解时间。攻击成本还取决于在线限速、离线 KDF、硬件、泄露密码列表、密码复用和攻击策略。

密码生成算法详解

随机数生成器

密码生成的核心是使用安全的随机数生成器(RNG):

  1. 伪随机数生成器(PRNG):使用算法生成看似随机的数,但实际上是确定的
  2. 密码安全伪随机数生成器(CSPRNG):设计用于密码学应用,提供更高的安全性
  3. 真随机数生成器(TRNG):使用物理过程生成真正的随机数

密码生成策略

安全密码生成器通常采用以下策略:

  1. 字符集选择:允许用户选择使用的字符类型(大小写字母、数字、符号)
  2. 长度控制:允许用户指定密码长度
  3. 排除相似字符:可选排除容易混淆的字符(如l、1、I、0、O)
  4. 避免重复字符:可选避免连续重复的字符
  5. 密码复杂度检查:确保生成的密码满足指定的复杂度要求

常见密码生成模式

  1. 随机字符模式:完全随机的字符组合
  2. 记忆化模式:由随机单词和数字符号组合而成(如Diceware方法)
  3. 自定义模式:允许用户指定密码的结构(如AANNS-AAAA)

密码最佳实践

密码长度与复杂度

  • 推荐长度:遵循服务当前的长度策略,优先使用较长且唯一的随机值;密码管理器可以存储更长的值。
  • 字符多样性:不要为了满足规则添加可预测替换,使用服务接受的随机字符或词组选择过程。
  • 避免常见模式:不要使用"Password123"、"123456"等常见密码
  • 基于证据更换:在疑似泄露、服务入侵、恢复流程被攻破或策略变更后轮换;无依据的定期轮换可能制造可预测变体。

密码管理策略

  • 使用密码管理器:如Bitwarden、1Password或LastPass
  • 唯一密码原则:每个账户使用不同的密码
  • 安全存储:不要在不安全的地方(如明文文件、便签)存储密码
  • 安全审计:通过密码管理器或服务提供的隐私保护流程检查复用和泄露,不能把现有密码上传到任意检测器。

多因素认证

为重要账户启用多因素认证(MFA),提供额外的安全层:

  • 短信验证码:通过短信接收验证码
  • 认证应用:如Google Authenticator、Microsoft Authenticator
  • 硬件密钥:如YubiKey
  • 生物识别:指纹、面部识别等

代码示例

JavaScript

javascript
// 使用密码安全的随机数生成器生成密码
function generatePassword(length = 12, options = {
  uppercase: true,
  lowercase: true,
  numbers: true,
  symbols: true,
  excludeSimilar: false
}) {
  if (!Number.isInteger(length) || length <= 0) {
    throw new RangeError('长度必须是正整数');
  }
  const charset = {
    uppercase: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
    lowercase: 'abcdefghijklmnopqrstuvwxyz',
    numbers: '0123456789',
    symbols: '!@#$%^&*()_+-=[]{}|;:,.<>?'
  };
  
  let allChars = '';
  if (options.uppercase) allChars += charset.uppercase;
  if (options.lowercase) allChars += charset.lowercase;
  if (options.numbers) allChars += charset.numbers;
  if (options.symbols) allChars += charset.symbols;
  
  if (options.excludeSimilar) {
    allChars = allChars.replace(/[l1Io0O]/g, '');
  }
  
  if (allChars.length === 0) {
    throw new Error('至少需要选择一种字符类型');
  }
  
  let password = '';
  const limit = 256 - (256 % allChars.length);
  while (password.length < length) {
    const array = new Uint8Array(1);
    window.crypto.getRandomValues(array);
    if (array[0] >= limit) continue; // 拒绝采样,避免取模偏差
    password += allChars[array[0] % allChars.length];
  }
  
  return password;
}

// 生成16位包含所有字符类型的密码
const password = generatePassword(16);
// 直接交给可信的密码管理器流程;生产环境不要记录秘密。

Python

python
import secrets
import string

def generate_password(length=12, uppercase=True, lowercase=True, numbers=True, symbols=True, exclude_similar=False):
    charset = ''
    if uppercase:
        charset += string.ascii_uppercase
    if lowercase:
        charset += string.ascii_lowercase
    if numbers:
        charset += string.digits
    if symbols:
        charset += string.punctuation
    
    if exclude_similar:
        charset = charset.translate(str.maketrans('', '', 'l1Io0O'))
    
    if not charset:
        raise ValueError("至少需要选择一种字符类型")
    
    password = ''.join(secrets.choice(charset) for _ in range(length))
    return password

# 生成14位包含字母和数字的密码
password = generate_password(14, symbols=False)
# 通过可信流程存储;生产环境不要打印秘密。

Java

java
import java.security.SecureRandom;
import java.util.HashSet;
import java.util.Set;

public class PasswordGenerator {
    private static final String UPPERCASE = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    private static final String LOWERCASE = "abcdefghijklmnopqrstuvwxyz";
    private static final String NUMBERS = "0123456789";
    private static final String SYMBOLS = "!@#$%^&*()_+-=[]{}|;:,.<>?";
    private static final String SIMILAR_CHARS = "l1Io0O";
    
    private final SecureRandom secureRandom;
    
    public PasswordGenerator() {
        this.secureRandom = new SecureRandom();
    }
    
    public String generate(int length, boolean includeUppercase, boolean includeLowercase,
                          boolean includeNumbers, boolean includeSymbols, boolean excludeSimilar) {
        
        StringBuilder charset = new StringBuilder();
        if (includeUppercase) charset.append(UPPERCASE);
        if (includeLowercase) charset.append(LOWERCASE);
        if (includeNumbers) charset.append(NUMBERS);
        if (includeSymbols) charset.append(SYMBOLS);
        
        String charSetStr = charset.toString();
        
        if (excludeSimilar) {
            charSetStr = removeSimilarChars(charSetStr);
        }
        
        if (charSetStr.isEmpty()) {
            throw new IllegalArgumentException("至少需要选择一种字符类型");
        }
        
        StringBuilder password = new StringBuilder(length);
        for (int i = 0; i < length; i++) {
            int randomIndex = secureRandom.nextInt(charSetStr.length());
            password.append(charSetStr.charAt(randomIndex));
        }
        
        return password.toString();
    }
    
    private String removeSimilarChars(String input) {
        Set<Character> similarSet = new HashSet<>();
        for (char c : SIMILAR_CHARS.toCharArray()) {
            similarSet.add(c);
        }
        
        StringBuilder result = new StringBuilder();
        for (char c : input.toCharArray()) {
            if (!similarSet.contains(c)) {
                result.append(c);
            }
        }
        
        return result.toString();
    }
    
    public static void main(String[] args) {
        PasswordGenerator generator = new PasswordGenerator();
        String password = generator.generate(16, true, true, true, true, false);
        // 通过可信流程存储;生产环境不要打印秘密。
    }
}

常见问题

多长的密码才算安全?

不存在适用于所有服务的安全长度。应遵循服务当前的长度策略,生成唯一随机秘密或独立抽取的口令短语,并同时考虑限速、MFA、恢复流程和泄露风险;密码管理器可以安全保存更长的值。

密码管理器安全吗?

密码管理器可以减少复用和钓鱼风险,但安全性取决于实现、同步/恢复模型、设备安全和主凭据。应选择持续维护的产品,使用唯一强主凭据与 MFA,并了解其泄露、导出和恢复控制。

我应该多久更换一次密码?

在疑似泄露、服务入侵、恢复流程被攻破或策略变更后轮换密码。没有证据的定期轮换可能制造可预测的密码变体。

什么是多因素认证?

多因素认证是一种安全机制,要求用户提供两种或更多种验证因素才能访问账户。常见的因素包括:

  • 知识因素:密码或PIN码
  • 持有因素:手机或硬件密钥
  • 固有因素:指纹或面部识别

总结

密码安全结合唯一生成、安全传递与存储、抗钓鱼机制、MFA、恢复控制、限速和泄露响应。熵值只是生成过程的模型,不是整个账户的安全保证。

快速总结:

  • 理论熵值描述的是假设的随机过程
  • 优先使用唯一随机秘密或独立抽取的口令短语
  • 使用 CSPRNG 和无偏采样,绝不记录生成的秘密
  • 为每个账户使用唯一的密码
  • 使用密码管理器安全存储和管理密码
  • 启用多因素认证以增强安全性

只在可信流程中生成新秘密,避免通过日志或聊天复制,并将其存储在持续维护的密码管理器中。