密码攻击与防御
什么是密码攻击
密码攻击是指攻击者通过各种手段获取用户密码,从而未经授权访问系统或数据的攻击方式。密码攻击是最常见的网络攻击类型之一,成功率高且实施成本低。
攻击原理
- 攻击者获取密码存储文件或密码哈希值
- 使用字典攻击、暴力破解、彩虹表等方法破解密码
- 或者通过钓鱼、键盘记录等方式直接获取明文密码
- 使用获取的密码登录系统,窃取数据或进行其他恶意操作
常见攻击手法
- 字典攻击:使用预定义的字典尝试常见密码
- 暴力破解:尝试所有可能的字符组合
- 彩虹表攻击:使用预计算的哈希值表匹配密码哈希
- 钓鱼攻击:通过欺骗用户获取密码
- 键盘记录:通过恶意软件记录用户输入的密码
- 密码重用攻击:利用用户在多个网站使用相同密码的习惯
- 社会工程学:通过欺骗手段获取密码(已单独成篇)
防御措施
- 使用强密码策略:要求密码包含大小写字母、数字和特殊字符
- 密码哈希存储:使用bcrypt、Argon2等强哈希算法存储密码
- 加盐哈希:为每个密码添加唯一盐值,防止彩虹表攻击
- 双因素认证:启用双因素认证,增加额外安全层
- 密码策略:实施密码过期、历史密码检查等策略
- 用户教育:教育用户使用强密码,避免密码重用
- 防钓鱼训练:培训用户识别钓鱼攻击
Node.js防御示例
安全的密码存储与验证
const express = require('express');
const bcrypt = require('bcrypt');
const mongoose = require('mongoose');
const app = express();
app.use(express.json());
// 定义用户模型
const UserSchema = new mongoose.Schema({
username: { type: String, required: true, unique: true },
password: { type: String, required: true }
});
// 密码加密中间件
UserSchema.pre('save', async function(next) {
if (!this.isModified('password')) {
return next();
}
// 生成盐值并加密密码
const salt = await bcrypt.genSalt(12); // 12轮盐值生成
this.password = await bcrypt.hash(this.password, salt);
next();
});
// 密码验证方法
UserSchema.methods.validatePassword = async function(password) {
return bcrypt.compare(password, this.password);
};
const User = mongoose.model('User', UserSchema);
// 用户注册
app.post('/register', async (req, res) => {
try {
const { username, password } = req.body;
// 验证密码强度
if (!/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/.test(password)) {
return res.status(400).send('密码必须至少8位,包含大小写字母、数字和特殊字符');
}
const user = new User({ username, password });
await user.save();
res.status(201).send('用户注册成功');
} catch (error) {
res.status(500).send(error.message);
}
});
// 用户登录
app.post('/login', async (req, res) => {
try {
const { username, password } = req.body;
const user = await User.findOne({ username });
if (!user) {
return res.status(401).send('用户名或密码错误');
}
const isMatch = await user.validatePassword(password);
if (!isMatch) {
return res.status(401).send('用户名或密码错误');
}
// 生成JWT令牌等登录逻辑
res.send('登录成功');
} catch (error) {
res.status(500).send(error.message);
}
});
mongoose.connect('mongodb://localhost:27017/password-security')
.then(() => console.log('MongoDB连接成功'))
.catch(err => console.error('MongoDB连接错误:', err));
app.listen(3000, () => {
console.log('Server running on port 3000');
});
双因素认证实现
const express = require('express');
const speakeasy = require('speakeasy');
const QRCode = require('qrcode');
const app = express();
app.use(express.json());
// 模拟用户数据库
const users = {};
// 生成双因素认证密钥
app.post('/enable-2fa', (req, res) => {
const { userId } = req.body;
// 生成密钥
const secret = speakeasy.generateSecret({ length: 20 });
// 保存密钥到用户数据
users[userId] = { secret: secret.base32 };
// 生成QR码URL
const otpauthUrl = speakeasy.otpauthURL({
secret: secret.ascii,
label: 'MyApp',
issuer: 'MyApp'
});
QRCode.toDataURL(otpauthUrl, (err, dataUrl) => {
if (err) {
res.status(500).send('生成QR码失败');
return;
}
res.send({
secret: secret.base32,
qrCode: dataUrl
});
});
});
// 验证双因素认证代码
app.post('/verify-2fa', (req, res) => {
const { userId, token } = req.body;
if (!users[userId]) {
res.status(404).send('用户未找到');
return;
}
const verified = speakeasy.totp.verify({
secret: users[userId].secret,
encoding: 'base32',
token
});
res.send({ verified });
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});
检测与响应
- 使用密码破解检测工具:如John the Ripper、Hashcat等
- 登录监控:监控异常登录尝试,实施账户锁定
- 密码强度检查:强制用户使用强密码
- 安全审计:定期进行密码安全审计
- 应急响应:制定密码泄露应急响应计划,包括密码重置和账户锁定
最佳实践
- 使用bcrypt、Argon2等强哈希算法存储密码
- 为每个密码添加唯一盐值
- 实施强密码策略,要求密码包含多种字符类型
- 启用双因素认证
- 定期要求用户更改密码
- 禁止密码重用
- 教育用户使用密码管理器
- 定期进行安全测试,包括密码破解测试