Xiuno BBS 审计之问题:时区字符集硬编码
贰先生 5小时前

此文章为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',                          // 硬编码 utf8(utf8mb3)
        '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);   // SET names 拼接
    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");        // 硬编码 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');                           // 硬编码 UTF-8
}
function xn_substr($s, $start, $len) {
    return mb_substr($s, $start, $len, 'UTF-8');             // 硬编码 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;       // 硬编码 746px

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 等函数字符集参数化,从配置读取
最新回复 (0)
全部楼主
返回