问题:用户密码使用 md5(password+salt) 单重哈希存储,未使用 bcrypt/PBKDF2/Argon2
此文章为XIUNOX版本重构审计时发现问题,分享出来方便后续想基于xiuno bbs4.0.4版本制作维护版本或插件模板等需求的开发者和站长参考。
现象
Xiuno BBS 4.0.4 在用户注册、登录、改密、后台建号等多个入口均使用 md5($password.$salt) 形式存储密码摘要。md5 算法本身运算速度极快(现代 GPU 可达每秒数百亿次),且为单重哈希(无迭代、无内存硬化),完全不符合现代密码存储规范。一旦数据库泄露,攻击者可在数小时内使用字典+彩虹表+GPU 暴力破解绝大多数弱口令密码。同时后台安装脚本对管理员密码使用 md5(md5($password).$salt) 双重 md5,仍属不安全范围。
源码证据
文件:xiunobbs_4.0.4/route/user.php 行 154-169(注册时密码写入)
$salt = xn_rand(16);
$pwd = md5($password.$salt);
$gid = 101;
$_user = array (
'username' => $username,
'email' => $email,
'password' => $pwd,
'salt' => $salt,
);
$uid = user_create($_user);
文件:xiunobbs_4.0.4/route/user.php 行 84(登录校验同样为 md5 比对)
md5($password.$_user['salt']) != $_user['password'] AND message('password', lang('password_incorrect'));
文件:xiunobbs_4.0.4/route/user.php 行 277(找回密码重置流程)
$password = md5($password.$salt);
user_update($_uid, array('password'=>$password));
文件:xiunobbs_4.0.4/route/my.php 行 56-58(修改密码)
md5($password_old.$user['salt']) != $user['password'] AND message('password_old', lang('old_password_incorrect'));
$password_new = md5($password_new.$user['salt']);
$r = user_update($uid, array('password'=>$password_new));
文件:xiunobbs_4.0.4/admin/route/index.php 行 27(后台登录校验)
if(md5($password.$user['salt']) != $user['password']) {
xn_log('password error. uid:'.$user['uid'].' - ******'.substr($password, -6), 'admin_login_error');
message('password', lang('password_incorrect'));
}
文件:xiunobbs_4.0.4/admin/route/user.php 行 88(后台建号,使用 md5(md5()))
$r = user_create(array(
'username'=>$username,
'password'=>md5(md5($password).$salt),
'salt'=>$salt,
// ...
));
文件:xiunobbs_4.0.4/install/index.php 行 188(安装时管理员密码)
$salt = xn_rand(16);
$password = md5(md5($adminpass).$salt);
$update = array('username'=>$adminuser, 'email'=>$adminemail, 'password'=>$password, 'salt'=>$salt, 'create_date'=>$time, 'create_ip'=>$longip);
db_update('user', array('uid'=>1), $update);
风险等级与结论
高危
危害后果:
- md5 哈希无迭代、无盐值放大、无内存硬化,攻击者拿到库后可用 hashcat 在单 GPU 上以每秒 10^10 量级速度爆破,常见弱口令几分钟内即被还原。
- 即使前台
md5($password.$salt) 加了 salt,salt 本身与 md5 一同存库,泄露后毫无防御价值。
- 后台
md5(md5($password).$salt) 双重 md5 只是 2 倍计算量,对 GPU 暴力破解毫无阻碍。
- 与现代标准
password_hash() (bcrypt/argon2) 相差 6-7 个数量级的安全强度。
修复建议:
- 立即切换到 PHP 内置
password_hash($password, PASSWORD_BCRYPT) 或 PASSWORD_ARGON2ID,存储格式自带 salt 与 cost factor。
- 校验时使用
password_verify($password, $hash),并在登录成功时调用 password_needs_rehash() 自动平滑升级旧 md5 哈希到 bcrypt。
- 设置 bcrypt cost ≥ 12,Argon2id 推荐参数:
memory_cost=65536, time_cost=4, threads=2。
- 在
model/user.func.php 中封装统一的密码哈希/校验函数,禁止业务层直接调用 md5() 处理密码。