此文章为XIUNOX版本重构审计时发现问题,XIUNOX版本已优化修复此问题。分享出来方便后续想基于xiuno bbs4.0.4版本制作维护版本或插件模板等需求的开发者和站长参考。
现象
Xiuno BBS 4.0.4 没有统一的 API/Controller 接口层。前端路由通过 index.inc.php 中的 switch 语句硬编码分发到各 route/*.php 文件,AJAX 与页面请求混用同一入口;每个 route 文件自行处理参数校验、权限检查、响应输出(message() 函数直接 exit),无中间件层、无统一风控入口、无统一响应格式、无 API 版本管理。后台 admin 路由同样为 switch 硬编码,前后台两套独立路由表,无统一调度。
源码证据
1. 前台路由 switch 硬编码,无路由表抽象
文件:xiunobbs_4.0.4/index.inc.php 第 49-80 行
$route = param(0, 'index');
if(!defined('SKIP_ROUTE')) {
switch ($route) {
case 'index': include _include(APP_PATH.'route/index.php'); break;
case 'thread': include _include(APP_PATH.'route/thread.php'); break;
case 'forum': include _include(APP_PATH.'route/forum.php'); break;
case 'user': include _include(APP_PATH.'route/user.php'); break;
case 'my': include _include(APP_PATH.'route/my.php'); break;
case 'attach': include _include(APP_PATH.'route/attach.php'); break;
case 'post': include _include(APP_PATH.'route/post.php'); break;
case 'mod': include _include(APP_PATH.'route/mod.php'); break;
case 'browser': include _include(APP_PATH.'route/browser.php'); break;
default:
include _include(APP_PATH.'route/index.php'); break;
}
}
2. 后台路由独立 switch,与前台无统一调度
文件:xiunobbs_4.0.4/admin/index.inc.php 第 24-47 行
$route = param(0, 'index');
switch ($route) {
case 'index': include _include(ADMIN_PATH.'route/index.php'); break;
case 'setting': include _include(ADMIN_PATH.'route/setting.php'); break;
case 'forum': include _include(ADMIN_PATH.'route/forum.php'); break;
case 'friendlink': include _include(ADMIN_PATH.'route/friendlink.php'); break;
case 'group': include _include(ADMIN_PATH.'route/group.php'); break;
case 'other': include _include(ADMIN_PATH.'route/other.php'); break;
case 'user': include _include(ADMIN_PATH.'route/user.php'); break;
case 'thread': include _include(ADMIN_PATH.'route/thread.php'); break;
case 'plugin': include _include(ADMIN_PATH.'route/plugin.php'); break;
default:
include _include(ADMIN_PATH.'route/index.php'); break;
}
3. route/post.php 中 AJAX 与页面请求混用同一入口,无统一响应格式
文件:xiunobbs_4.0.4/route/post.php 第 84-99 行
$return_html = param('return_html', 0);
if($return_html) {
$filelist = array();
ob_start();
include _include(APP_PATH.'view/htm/post_list.inc.htm');
$s = ob_get_clean();
message(0, $s);
} else {
message(0, lang('create_post_sucessfully'));
}
4. message() 函数内联 exit,无中间件后置处理
文件:xiunobbs_4.0.4/model/misc.func.php 第 81-114 行
function message($code, $message, $extra = array()) {
global $ajax, $header, $conf;
$arr = $extra;
$arr['code'] = $code.'';
$arr['message'] = $message;
$header['title'] = $conf['sitename'];
static $called = FALSE;
$called ? exit(xn_json_encode($arr)) : $called = TRUE;
if($ajax) {
echo xn_json_encode($arr);
} else {
if(IN_CMD) {
exit;
} else {
if(defined('MESSAGE_HTM_PATH')) {
include _include(MESSAGE_HTM_PATH);
} else {
include _include(APP_PATH."view/htm/message.htm");
}
}
}
exit;
}
5. 鉴权/CSRF/风控检查散落在各 route 文件,无统一入口
文件:xiunobbs_4.0.4/route/post.php 第 1-9 行
!defined('DEBUG') AND exit('Access Denied.');
$action = param(1);
user_login_check();
文件:xiunobbs_4.0.4/route/thread.php 第 12-14 行
if($action == 'create') {
user_login_check();
文件:xiunobbs_4.0.4/route/user.php 中 user_login_check 仅在 create/logout 等动作内隐式调用,无统一前置中间件。
6. 无 API 版本管理、无 OpenAPI/Swagger、无统一错误码
全站无 v1/、v2/ 版本前缀,无 Api/Controller 命名空间,错误码为 0/1/-1 + 字段名(如 'email'),无统一错误码表。
风险等级与结论
架构缺陷(严重)
危害:
- 无中间件层导致鉴权/CSRF/限流/日志/风控等横切关注点必须在每个 route 文件重复实现,遗漏即漏洞
- AJAX 与页面请求混用入口,
message() 直接 exit 使后置中间件无法执行(如响应日志、压缩、CORS)
- 路由 switch 硬编码,新增模块需改核心文件,插件无法注册新路由
- 前后台两套独立路由表,无统一调度,维护成本翻倍
- 无统一响应格式(code/message/extra vs HTML vs JSON),客户端解析困难
- 无 API 版本管理,破坏性变更无法灰度
修复建议:
- 引入路由表配置(如
routes.php 数组),支持插件注册路由
- 抽象 Middleware 链(Auth/Csrf/RateLimit/Log),统一前置后置处理
- 统一响应格式为
{"code":0,"message":"","data":{}},HTML 视图作为独立响应类型
- 引入 API 版本前缀
/api/v1/,前后台共用路由调度器
message() 改为抛出 BusinessException,由全局异常处理器统一格式化输出