Xiuno BBS 审计之问题:无统一 API 层,无风控入口
贰先生 6小时前

此文章为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');

// hook index_inc_route_before.php

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 行

// 直接返回帖子的 html
$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);                         // message 中既可能是 HTML 也可能是 JSON
} 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'];
    // hook model_message_start.php
    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");
            }
        }
    }
    // hook model_message_end.php
    exit;                                      // 直接 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();                           // 每个 route 文件自行调用登录检查
// hook post_start.php

文件: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,由全局异常处理器统一格式化输出
最新回复 (0)
全部楼主
返回