4、口令认证实战:强口令策略设计、口令存储(加盐哈希)、Linux PAM模块配置、常见攻击(暴力破解/撞库)防御
口令认证,说白了就是“用户名+密码”这套东西。别看它老,工业现场90%以上的身份认证还得靠它。我见过太多工厂,PLC的密码还是admin/123456,防火墙的Web管理口连个复杂口令都没有。嗯,这章咱们就把口令认证这件事彻底讲透。
核心观点:口令认证的安全不在于口令本身有多复杂,而在于“策略+存储+传输+防御”四道防线是否都到位。缺任何一环,整个体系就形同虚设。
4.1 强口令策略设计——别让用户自己瞎编
我经常被问到:“到底什么样的口令才算强?”其实答案很简单——让机器猜不到,让人记不住。但工业环境里,操作员要记的口令太多了,所以策略要平衡安全性和可用性。
4.1.1 口令复杂度规则
我个人习惯用这个标准,大家可以参考:
| 维度 | 最低要求 | 推荐配置 | 说明 |
|---|---|---|---|
| 长度 | 8位 | 12-16位 | 每增加1位,暴力破解时间指数级增长 |
| 字符集 | 3类 | 4类(大小写+数字+特殊符号) | 避免只改首字母大写+末尾数字 |
| 禁止项 | 用户名、连续字符 | 键盘序列、常见单词、重复字符 | qwerty、123456、password这些直接拉黑 |
| 历史禁止 | 最近3次 | 最近5次 | 防止用户来回换那两三个口令 |
避坑指南:我曾经见过一个客户,口令策略要求“必须包含特殊字符”,结果全厂都统一在末尾加了个“!”。这种策略等于没设。建议在策略里明确禁止“常见替换模式”,比如把a换成@、把s换成$这种。
4.1.2 口令有效期与锁定策略
口令不能永远不换,但也不能换得太勤。我建议工业环境按这个节奏来:
- 普通用户:90天过期,提前7天提醒
- 管理员/特权账户:60天过期,提前14天提醒
- 服务账户/系统账户:不设过期(但要用随机长口令+密钥管理)
- 锁定阈值:连续5次失败,锁定15分钟
为什么会这样?你想想看,操作员正在产线上盯着参数,突然被踢出去改口令,那不得骂娘?所以提醒期要够长,锁定时间要合理。
4.2 口令存储——加盐哈希,别给我存明文
这是我最想强调的一点。2023年还有厂商把用户口令明文存数据库,我真是服了。一旦数据库泄露,所有账户全部沦陷。
4.2.1 为什么不能直接哈希?
直接对口令做哈希(比如MD5、SHA-1)也不安全。为什么?因为彩虹表。攻击者提前算好常见口令的哈希值,一比对就出来了。
加盐(Salt)就是给每个口令加一段随机字符串,再一起做哈希。这样就算两个用户口令相同,哈希值也不同。
4.2.2 加盐哈希的正确姿势
我推荐用bcrypt或Argon2,它们内置了盐值和迭代次数。如果你非要用SHA-256自己实现,记住这几个要点:
# 伪代码示例:加盐哈希存储
# 1. 生成16字节随机盐值
salt = random_bytes(16)
# 2. 将盐值与口令拼接
salted_password = salt + password
# 3. 做10000次迭代哈希
hash = SHA256(salted_password)
for i in range(9999):
hash = SHA256(hash + salt)
# 4. 存储格式:salt$hash
stored = base64(salt) + "$" + base64(hash)
警告:千万不要自己发明加密算法!不要用MD5!不要用SHA-1!不要用少于16字节的盐值!迭代次数不要低于10000次!这些都是我用血泪教训换来的。
4.2.3 口令验证流程
验证时,从数据库取出salt$hash,用同样的盐值+用户输入的口令重新计算哈希,比对即可。整个过程不涉及解密,因为哈希是单向的。
4.3 Linux PAM模块配置——工业系统的守门员
工业现场大量使用Linux作为控制平台(PLC编程站、SCADA服务器、边缘网关)。PAM(Pluggable Authentication Modules)是Linux的认证框架,配置好了能挡住大部分攻击。
4.3.1 PAM基础配置
PAM的配置文件在/etc/pam.d/目录下。以SSH登录为例,修改/etc/pam.d/sshd:
# 1. 启用pam_cracklib.so强制口令复杂度
password requisite pam_cracklib.so \
minlen=12 \
dcredit=-1 ucredit=-1 ocredit=-1 lcredit=-1 \
difok=5 \
reject_username \
enforce_for_root
# 2. 启用pam_tally2.so限制登录失败次数
auth required pam_tally2.so \
deny=5 \
unlock_time=900 \
even_deny_root \
root_unlock_time=1800
# 3. 启用pam_unix.so使用SHA512哈希
password sufficient pam_unix.so \
sha512 \
rounds=10000 \
remember=5
参数说明:
minlen=12:口令最小长度12位dcredit=-1:至少1位数字ucredit=-1:至少1位大写字母ocredit=-1:至少1位特殊字符deny=5:5次失败后锁定unlock_time=900:锁定15分钟(秒)rounds=10000:哈希迭代次数
避坑指南:我曾经在配置pam_tally2时忘了加even_deny_root,结果root账户被暴力破解了3天都没锁。记住,工业系统的root账户更要保护,攻击者最喜欢拿root。
4.3.2 配置验证
配置完一定要测试:
# 测试口令策略
# 用弱口令试试能不能通过
echo "123456" | passwd --stdin testuser
# 查看登录失败记录
pam_tally2 --user testuser
# 重置失败计数(管理员用)
pam_tally2 --user testuser --reset
4.4 常见攻击防御——暴力破解与撞库
工业系统最怕什么?不是APT攻击,而是最原始的暴力破解和撞库。为什么?因为工业协议往往没有速率限制,攻击者可以慢慢试。
4.4.1 暴力破解防御
暴力破解就是穷举所有可能的口令组合。防御手段有这几层:
| 防御层 | 具体措施 | 适用场景 |
|---|---|---|
| 网络层 | IP白名单、速率限制、fail2ban | SSH、Web管理口、PLC编程口 |
| 应用层 | 登录失败锁定、CAPTCHA、延迟响应 | SCADA客户端、HMI登录 |
| 协议层 | 工业协议认证增强(如OPC UA的证书认证) | PLC、RTU、DCS控制器 |
我个人习惯在工业网关上部署fail2ban,配置很简单:
# /etc/fail2ban/jail.local
[sshd]
enabled = true
port = 22
filter = sshd
logpath = /var/log/secure
maxretry = 3
bantime = 3600
findtime = 600
这个配置的意思是:10分钟内失败3次,封禁1小时。对于工业环境,这个阈值已经够宽松了,操作员输错几次密码很正常,但攻击者别想连续试。
4.4.2 撞库防御
撞库就是攻击者用其他平台泄露的口令库来试你的系统。防御核心就一句话:别让攻击者知道用户名是否存在。
具体做法:
- 统一返回信息:不管用户名是否存在,都返回“用户名或密码错误”
- 延迟响应:每次登录都固定延迟2-3秒,让攻击者无法通过响应时间推断
- 二次认证:对敏感操作(如修改配置、下载程序)增加二次口令或动态令牌
警告:千万不要在登录接口返回“用户名不存在”或“密码错误”这种区分信息。我曾经审计过一个工控系统,登录失败时返回了不同的HTTP状态码,攻击者用这个信息5分钟就枚举出了所有有效用户名。
4.5 本章知识体系
下面这张图把口令认证的四个核心环节串起来了:
4.6 实战检查清单
最后,我给大家一个检查清单,部署完可以逐条核对:
- 口令策略:是否强制12位以上?是否禁止常见弱口令?是否设置了有效期?
- 口令存储:是否使用加盐哈希?盐值是否随机且≥16字节?迭代次数是否≥10000?
- PAM配置:是否启用了pam_cracklib?是否配置了登录失败锁定?root账户是否也被锁定?
- 攻击防御:是否部署了fail2ban或类似工具?登录失败信息是否统一?是否有速率限制?
- 定期审计:是否定期检查弱口令?是否监控异常登录行为?是否有口令泄露应急响应预案?
避坑指南:我曾经帮一个客户做安全审计,发现他们所有配置都符合要求,唯独忘了给默认的admin账户改口令。攻击者直接用admin/admin123就登录了SCADA系统。记住,默认账户是最大的安全漏洞,没有之一。