此文章为XIUNOX版本重构审计时发现问题,XIUNOX版本已优化修复此问题。分享出来方便后续想基于xiuno bbs4.0.4版本制作维护版本或插件模板等需求的开发者和站长参考。
现象
Xiuno BBS 4.0.4 在多处硬编码时区(Asia/Shanghai)与字符集(utf8),虽然部分硬编码有配置项覆盖,但默认值固定,且代码内部存在多处与配置无关的字符集/时区硬编码。数据库字符集默认 utf8(实为 utf8mb3)无法存储 emoji 与 4 字节字符,与现代应用兼容性差。多语言支持的时区切换、字符集切换均无机制。
源码证据
1. conf.default.php 硬编码时区与字符集
文件:xiunobbs_4.0.4/conf/conf.default.php 第 19-22 行
'mysql' => array (
'master' => array (
'charset' => 'utf8',
'engine' => 'innodb',
),
),
'timezone' => 'Asia/Shanghai',
'lang' => 'zh-cn',
2. xiunophp.php 时区默认值仍硬编码 Asia/Shanghai
文件:xiunobbs_4.0.4/xiunophp/xiunophp.php 第 62-82 行
empty($conf) AND $conf = array('db'=>array(), 'cache'=>array(), 'tmp_path'=>'./', 'log_path'=>'./', 'timezone'=>'Asia/Shanghai');
empty($conf['timezone']) AND $conf['timezone'] = 'Asia/Shanghai';
date_default_timezone_set($conf['timezone']);
3. db_mysql.class.php real_connect 用 SET names 设置字符集,未使用 mysql_set_charset
文件:xiunobbs_4.0.4/xiunophp/db_mysql.class.php 第 52-59 行
public function real_connect($host, $user, $password, $name, $charset = '', $engine = '') {
$link = @mysql_connect($host, $user, $password);
if(!$link) { $this->error(mysql_errno(), '连接数据库服务器失败:'.mysql_error()); return FALSE; }
if(!mysql_select_db($name, $link)) { $this->error(mysql_errno(), '选择数据库失败:'.mysql_error()); return FALSE; }
$charset AND $this->query("SET names $charset, sql_mode=''", $link);
return $link;
}
$charset 直接拼入 SQL(虽来自配置但未做白名单校验),且 SET names 不改变 mysql 客户端库的字符集认知,mysql_real_escape_string 仍按默认字符集工作,存在多字节注入风险。
4. xiunophp.php 强制 Content-type 为 utf-8
文件:xiunobbs_4.0.4/xiunophp/xiunophp.php 第 30-35 行
if(IN_CMD) {
} else {
header("Content-type: text/html; charset=utf-8");
}
5. xn_json_encode 硬编码 UTF-8 操作
文件:xiunobbs_4.0.4/xiunophp/misc.func.php 第 195-211 行
function xn_strlen($s) {
return mb_strlen($s, 'UTF-8');
}
function xn_substr($s, $start, $len) {
return mb_substr($s, $start, $len, 'UTF-8');
}
6. db_pdo_mysql.class.php 同样以配置字符集拼接 DSN
文件:xiunobbs_4.0.4/xiunophp/db_pdo_mysql.class.php(Grep 显示 3 处 try/catch)
PDO DSN 中 charset 参数直接拼入,未做白名单。
7. xn_html_safe 中硬编码 BBS 回帖宽度 746
文件:xiunobbs_4.0.4/model/misc.func.php 第 150 行
empty($arg['table_max_width']) AND $arg['table_max_width'] = 746;
8. humandate 中硬编码中文语言包兜底
文件:xiunobbs_4.0.4/xiunophp/misc.func.php 第 481-487 行
empty($lan) AND $lan = array(
'month_ago'=>'月前',
'day_ago'=>'天前',
'hour_ago'=>'小时前',
'minute_ago'=>'分钟前',
'second_ago'=>'秒前',
);
风险等级与结论
架构缺陷(中)
危害:
- 数据库
utf8(utf8mb3)无法存储 emoji、4 字节汉字(如部分生僻字、历史字符),用户昵称/帖子内容会被截断或报错
SET names 拼接字符集 + mysql_real_escape_string 按默认字符集工作,多字节字符集下存在 SQL 注入风险
- 时区硬编码
Asia/Shanghai,海外部署需手工修改配置,且无运行时按用户切换时区机制
Content-type 强制 text/html; charset=utf-8,无法输出 JSON/XML/其他字符集
- 兜底中文语言包硬编码在
humandate,多语言切换失效
mb_strlen/mb_substr 硬编码 UTF-8,若运行时字符集变化(如处理 GBK 数据)会出错
修复建议:
- 数据库字符集默认改为
utf8mb4,支持完整 Unicode
- 使用
mysql_set_charset() 或 PDO setAttribute(PDO::MYSQL_ATTR_INIT_COMMAND, "SET NAMES utf8mb4") 替代 SET names 拼接
- 时区、字符集、语言均从配置读取,提供运行时切换 API(如按用户偏好时区显示时间)
Content-type 由响应类型决定(JSON 输出 application/json)
- 兜底语言包移至
lang/ 目录,按 $conf['lang'] 加载
mb_strlen 等函数字符集参数化,从配置读取