安全加固与 PHP 8 兼容
Why
Xiuno BBS 4.0 核心代码使用 mysql_* 等已在 PHP 7.0 移除的函数,无法在 PHP 8.0+ 运行;同时存在密码明文 MD5+salt 存储、无 CSRF 防护、无登录失败限制等高危安全漏洞。本阶段目标是让核心代码在 PHP 8.0+ 无错运行并修复所有已知高危安全问题。
What Changes
修复 PHP 8 不兼容语法(&new、each()、create_function()、preg_replace /e 等)
BREAKING 移除 db_mysql.class.php,将 mysql 驱动默认切换为 pdo_mysql;保留 db_* 全局函数签名不变
BREAKING user 表新增 password_hash 字段,登录验证逻辑改为优先 password_verify
user 表新增 login_attempts、last_login_ip、last_login_time、banned_until 字段
新增 user_login_log 表
所有 POST 表单新增 csrf_token 隐藏字段,服务端统一验证
输出转义:默认 htmlspecialchars($var, ENT_QUOTES | ENT_HTML5),富文本经 HTMLPurifier
新增 CsrfService、LoginSecurityService 服务类
新增 install/upgrade_phase1.sql 升级脚本
Impact
Affected specs: 数据库层、用户认证、表单处理、输出渲染
Affected code:
xiunophp/db_mysql.class.php — 标记废弃,不再默认加载
xiunophp/db.func.php — db_new() 移除 mysql case
xiunophp/db_pdo_mysql.class.php — 成为默认驱动
xiunophp/xiunophp.min.php — 同步移除 db_mysql 代码
model/user.func.php — 新增 user_login_verify()、user_login_attempt()、user_login_log()
route/user.php — 登录逻辑重写,POST 处理前验证 CSRF
route/*.php — 所有 POST 分支前加 CSRF 验证
view/htm/*.htm — 所有 <form> 内加 csrf_token 隐藏字段
index.inc.php — 生成 CSRF token 并存入 session
install/install.sql — 新增字段和表
conf/conf.default.php — 新增安全配置项
xiunophp/xn_html_safe.func.php — 增强为 HTMLPurifier 封装
ADDED Requirements
Requirement: PHP 8 语法兼容
系统 SHALL 在 PHP 8.0 ~ 8.3 下无错运行,不使用任何已移除函数或语法。
Scenario: 移除 mysql_* 函数
Scenario: 移除 &new 语法
Scenario: each() 替换
Requirement: PDO 数据库驱动迁移
系统 SHALL 将 db_mysql.class.php 标记为 @deprecated,默认使用 db_pdo_mysql.class.php,保留所有 db_* 全局函数签名不变。
Scenario: 默认驱动切换
Scenario: db_* 函数兼容
Requirement: 密码哈希迁移
系统 SHALL 支持从 MD5+salt 到 password_hash() 的渐进式迁移。
Scenario: 新用户注册
Scenario: 旧用户登录自动升级
Scenario: 新密码验证
Scenario: 批量迁移脚本
Requirement: CSRF Token 验证
系统 SHALL 为所有 POST/PUT/DELETE 请求验证 CSRF Token。
Scenario: Token 生成
Scenario: 表单提交
Scenario: AJAX 请求
Scenario: Token 轮换
Requirement: 输出转义
系统 SHALL 对所有输出进行安全转义。
Scenario: 纯文本输出
Scenario: 富文本输出
Requirement: 登录失败限制
系统 SHALL 限制登录失败次数,防止暴力破解。
Scenario: 失败计数
Scenario: 账户锁定
Scenario: 登录成功
Scenario: 登录日志
WHEN 每次登录(成功或失败)
THEN 写入 user_login_log 表(uid, ip, time, success, user_agent)
Requirement: 升级脚本
系统 SHALL 提供 SQL 升级脚本,支持从 4.0 无损升级。
Scenario: 执行升级
MODIFIED Requirements
Requirement: db_new() 函数
原实现支持 mysql 类型。修改后:mysql case 移除,映射为 pdo_mysql 并记录日志。函数签名 db_new($dbconf) 不变。
Requirement: user_login 验证逻辑
原实现使用 md5($password.$user['salt']) == $user['password']。修改后:优先 password_verify(),回退旧方式并自动升级。登录前检查 banned_until。
Requirement: POST 路由处理
原实现直接处理 POST 参数。修改后:所有 POST 分支在业务逻辑前调用 csrf_check()。
REMOVED Requirements
Requirement: db_mysql 驱动
Reason: mysql_* 函数在 PHP 7.0 已移除,无法在 PHP 8.0+ 运行
Migration: conf.php 中 db.type 从 mysql 改为 pdo_mysql;db_mysql.class.php 文件保留但标记 @deprecated,不再被 db_new() 加载
作者:贰先生
链接:https://juejin.cn/post/7647463706607009835
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。