[审计]SoSite 安全与逻辑审计报告(2026-08-12)

👑Lv.11 元老 🌞 骨干会员
2026-10-25 00:14:41

本文由 FlintHub 开发文档归档发布。原始文档日期见标题前缀,来源:8月13日备份/审计报告-20260812.md。

SoSite 安全与逻辑审计报告(2026-08-12)

审计方式:全代码只读遍历(静态扫描 + 人工走读 + 调用链追踪),交叉验证 2026-08-06 审计报告整改情况。

范围:app/(Controllers/Core/Helpers/Models/Views)、plugins/(16 个插件)、assets/、protected/、config.php、根目录入口。

结论:本次审计未修改任何代码,以下为发现与建议,供决策参考。


一、安全审计(A1-A11)

1.1 SQL 注入 —— 总体良好,无新增可利用点 ✅

参数化纪律继续保持:Database::query() 一律 prepare() + 参数绑定,ATTR_EMULATE_PREPARES=false;IN (...) 全部 intval 过滤或 ? 占位符(Thread::batchDelete / User::deleteWithContent / Vote::getCounts);LIMIT/OFFSET 显式 (int);Model::buildWhere 正则白名单。未发现用户输入直拼 SQL 的注入点。

#位置风险说明
S1app/Controllers/Admin/DatabaseController.php mysqlImport🟠 中管理员导入 .sql 逐条 $conn->exec() 原样执行(功能固有风险,CSRF+路径+扩展名校验在,但被篡改备份可致全库沦陷)——2026-08-06 已报,未变
S2app/Core/Model.php:198-201🟡 低sanitizeOrderBy 黑名单剔除而非白名单——已报,未变

1.2 XSS 输出 —— 转义纪律良好 ✅

  • 模板引擎 {$var} 默认 htmlspecialchars 转义;{$var:raw} 为显式原始输出 ✅
  • 视图扫描:132 处输出初筛 → 全部经 $this->e() / (int) / 模板转义;勋章插件视图(admin.php / index.php)均 $this->e() 转义 ✅
  • Content::sanitizeHtml 白名单净化完整:允许标签/属性白名单、on* 属性删除、href/src 协议白名单(含 java script: 空格绕过防御)、SVG 拒绝、<?php 占位符保护 ✅
  • Content::formatPostContent 纯文本 → htmlspecialchars + 自动链接转义 ✅
  • X1 已修复 ✅:theme/settings.php 的 $color 已 $this->e() 转义(2026-08-06 报 X1)
  • X2(search_settings.php $percent)未强转,但为纯数值(round()),语义安全,🟡 建议 (int) 兜底

1.3 CSRF —— 覆盖完整 ✅

所有写操作均 Csrf::verifyOrDie() / Csrf::verify():发帖/回帖/编辑/删除/私信/上传/投票/收藏/签到/骰子/红包/勋章佩戴/邀请码/友链申请/关注、全部 15 个 Admin 控制器(继承 Admin/BaseController)+ 6 个插件 Admin 控制器。Csrf::verify 只校验不轮换(防并发 AJAX 403),登录/登出 rotate() 显式轮换 ✅。未发现缺失。

1.4 文件上传 —— 校验完善,服务器防护仍缺失 ⚠️

Upload.php 链路完整:扩展名白名单 → is_uploaded_file → finfo MIME 严格匹配 → 16 字节随机名 → move_uploaded_file → 缩略图(>5000px 像素炸弹拒绝、Imagick 格式限制、SVG 禁用)✅

#位置风险说明
U1assets/uploads/(无防护文件)🟠 中无 .htaccess/nginx 禁止脚本执行规则——已报,未修复。虽 MIME+扩展名双白名单无 php,但建议部署 php_flag engine off / nginx location ~ \.php$ { deny all; }
U2app/Helpers/Upload.php:58-61🟡 低finfo 不可用时仅扩展名兜底放行(有 error_log)——已报,未变
U3app/Helpers/Upload.php:107🟡 低原图保存前无 getimagesize 真实性校验(仅缩略图阶段有)——已报,未变

ApiController::upload:登录 + CSRF + 限流(5/分)✅;AttachmentController::download:basename + realpath 双重校验 + 版块权限(can_view/can_attach)+ attachment_download_before 钩子 ✅

1.5 SSRF —— 两个高危绕过点仍未修复 🔴

ApiController::fetchImage(L158-293)已有:登录 + 限流(20/分)+ URL 协议校验 + host 内网检测 + DNS 解析真实 IP 校验 + IP 替换 host 防 DNS Rebinding。

#位置风险说明
R1L181-205🔴 高169.254.0.0/16(云元数据 169.254.169.254)与 100.64.0.0/10(CGNAT)仍未封禁——已报,未修复
R2L217 / L236🔴 高follow_location=1 + cURL FOLLOWLOCATION 跟随重定向,重定向目标未逐跳二次内网校验——已报,未修复
R3L222-226🟡 低SSL 校验关闭(IP 直连所需,可接受但应知悉);端口未限制 80/443

1.6 命令注入 —— 零发现 ✅

全库扫描 shell_exec/system/exec/passthru/proc_open/popen:仅注释提及,无实际调用。插件缓存文件改为 json_decode 读取(消除 include RCE 风险)✅。

1.7 认证与会话 —— 配置严谨 ✅

  • Session:use_only_cookies、cookie_httponly、use_strict_mode、samesite=Lax、cookie_secure 按 HTTPS 自适应;MySQL sessions 表存储(独立 PDO 连接防游标冲突),表不存在回退文件存储 ✅
  • RememberMe:token 仅存 sha256 哈希 + hash_equals 恒定比较 + 自动登录轮换 token + httponly/samesite ✅
  • 登录:CSRF + 验证码 + DB 持久化锁定(5 次/15 分钟,换 Session 无法绕过)+ session_regenerate_id(true) + Csrf::rotate() ✅
  • 注册:限流(3/时)+ 验证码 + CSRF ✅;忘记密码:限流(3/时)+ 防枚举提示 + token 仅存哈希 + 1 小时过期 + 使用后作废 + 重置后清 remember_token ✅
  • Auth::requireAdmin:30 分钟二次验证(admin_verified_at)✅
#位置风险说明
P-2ProfileController.php:31-52🟠 中改邮箱无需当前密码确认 → 配合忘记密码构成账号接管链(会话窃取 → 改绑邮箱 → 重置密码)——已报,未修复
P-3AuthController.php:23-132🟠 中登录仅按用户名锁定,无 IP 级限流,密码喷洒(每账号 1-4 次)不受限;DB 锁定可被恶意触发登录 DoS——已报,未修复
P-6AuthController.php:247-312🟡 低忘记密码无验证码(登录/注册有),仅限流——已报,未变

1.8 越权(IDOR)—— 总体覆盖良好 ✅

  • 私信:MessageController::detail 校验收发双方、markAsRead/deleteOwned 带属主条件 ✅
  • 主题/回复:ThreadController::edit/delete 属主校验 + 版块权限 + post_id 跨主题校验 + 复合鉴权(楼主可删违规回复)✅
  • 附件删除:PostController::edit/ThreadController::edit 删除附件前校验 thread_id/post_id 归属 ✅
  • 博客:BlogController::create/edit/delete 属主校验 ✅
  • 勋章:setWearing 校验只能佩戴自己已获得的勋章 ✅
#位置风险说明
P-5BlogController.php:168-278🟠 中前台 Blog 增删改(admin-only)只查 isAdmin(),绕过 admin_verified_at 30 分钟二次验证——已报,未修复
P-9ThreadController.php:202/290、PostController.php:172🟡 低管理员前台编辑/删除他人帖子不要求二次验证(与 P-5 同类)——已报,未变
P-8ThemeController.php:19-24🟡 低主题切换 POST 无 requireLogin(仅 CSRF),影响面小——已报,未变
P-1User.php:38 + SearchController.php:66🟠 中用户搜索仍泄露 email/role/status 给任意登录用户——已报,未修复

1.9 信息泄露 —— 少量低危

  • User::search 泄露 email/role/status(见 P-1)
  • 错误信息不回显用户(PostController::create 捕获异常后提示"发帖失败,请稍后重试")✅
  • protected/ 有 .htaccess 全拒;app/Views/errors/404.php 已存在(4.2 悬空引用已修复 ✅)
  • user_profile 主页对非本人隐藏 email/email_verified ✅

1.10 配置与部署安全 ⚠️

#位置风险说明
C1config.php:14-15🟠 中DB 账号 fastbb/123456 弱默认口令——正式部署必须更换
C2config.php:27🟡 低MAIL_PASS_KEY 固定 AES 密钥——正式部署必须更换
C3assets/uploads/🟠 中同 U1,无脚本执行防护
—SITE_URL✅邮件链接用 SERVER_NAME(防 Host 头注入)✅

1.11 插件安全 —— 权限与钩子均规范 ✅

  • 6 个插件 Admin 控制器全部继承 Admin\BaseController(含二次验证)✅
  • 前台写操作全部 requireLogin + CSRF:签到/骰子/猜题对决/邀请码/勋章佩戴/通知/收藏/红包/友链申请/关注 ✅
  • Plugin::hook:路径 realpath + 前缀校验(防穿越)、单钩子 try/catch 隔离、插件缓存 json 化 ✅
  • Plugin::activate 建表幂等;缓存文件守卫模式 ✅

二、逻辑审计(B1-B10)

2.1 事务与一致性 —— 核心链路良好,发现 2 处中危缺陷

✅ 良好实践确认:

  • Points::deduct:事务 + FOR UPDATE 行锁,防并发透支 ✅
  • Vote::toggle:ON DUPLICATE KEY UPDATE 原子 upsert,防并发重复投票 ✅
  • red_packet:grab/create 均事务 + FOR UPDATE 行锁 + 防重复领取 ✅
  • Thread::batchDelete:事务 + 附件名白名单 + 全部 intval ✅
  • User::deleteWithContent:事务逆序清理(投票→标签→附件→回帖→主题→消息→博客→在线→用户)✅
  • PostController::create:事务包裹(插入主题 + 标签 + 发帖数 + 积分 + 计数)✅
#位置风险说明
L1plugins/quiz_duel/QuizDuelController.php:204-296🟠 中accept() 并发缺陷:Points::deduct 先执行(自开事务提交),随后 UPDATE quiz_duels + 发奖无事务包裹;且 accept 前仅 SELECT ... WHERE status='open',无行锁/无条件更新。两个对手可同时 accept 同一场对决 → 双方扣分但只一方发奖,或重复发奖。需 FOR UPDATE 或 UPDATE ... WHERE status='open' 条件更新
L2plugins/daily_checkin/CheckinController.php:191-208🟡 低签到 INSERT daily_checkin 与 UPDATE users points 两查询无事务包裹;表有 UNIQUE(user_id, checkin_date) 防重(✅ 防并发双签),但 INSERT 成功而 UPDATE 失败会积分丢失;并发双击时第二次 INSERT 抛异常被 catch 吞掉显示"签到失败"
L3plugins/invite/InviteController.php:47🟠 中生成邀请码不扣积分:Points::award($userId, -$pointsCost, ...) 传负值,而 Points::award 首行 if ($points <= 0) return; 拒绝 → 扣分静默失效(插件当前停用,但逻辑 bug 存在)
L4plugins/medal/Plugin.php:211-225🟡 低grant() 先 SELECT 再 INSERT,无 try/catch 捕获唯一键冲突;并发自动颁发时第二次 INSERT 抛异常会中断 checkAutoRules 循环(user_medals 有唯一键,防重 ✅,但异常未捕获)
L5plugins/dice/DiceController.php:73-79🟡 低日次数检查(getDailyPlayCount)与扣分(Points::deduct)非原子,并发可少量突破日上限;deduct 行锁正确但 count 检查在锁外

2.2 频率限制与防刷 —— 发帖仍无限流 🔴

#位置风险说明
P-4PostController::create:20-170🟠 中发新主题无频率限制(回帖/评论/私信/上传/投票/签到/搜索都有限流,唯独发帖没有)→ 可无限刷帖刷积分(+5/帖)——已报,未修复
P-7app/Helpers/RateLimiter.php:97-106🟡 低IP 文件缓存读-改-写无锁(仅写时 LOCK_EX),并发可少量突破阈值(TOCTOU)——已报,未变

2.3 核心业务(积分/勋章/投票/收藏)—— 设计良好 ✅

  • 积分:award/deduct 调用方权限校验完整、防负值、日志完整(points_log)✅
  • 投票:ApiController::vote 登录+CSRF+限流+类型白名单+ID 数字校验+获赞积分(自赞不奖)✅
  • 勋章:checkAutoRules 固定 3 次查询 + 会话守卫 + 30 分钟节流(性能与正确性兼顾);setWearing 事务 + 属主校验 + WEAR_LIMIT ✅
  • 收藏:post_favorite 登录 + CSRF + 唯一键防重 ✅
  • 签到:UNIQUE(user_id, checkin_date) 防重 ✅;积分封顶 50 ✅
  • 红包:grab 事务 + 行锁 + 防重复 + 过期退回 ✅
  • 猜题对决:store 扣分失败退还 ✅;accept 并发缺陷见 L1

2.4 消息/通知 —— 属主校验完整 ✅

  • 私信收发/已读/删除:全部带收发双方校验(Message::markAsRead/deleteOwned)✅
  • 通知:NotificationController/content_review::FrontController 批量删除带 userId 作用域 ✅

2.5 附件生命周期 —— 防误删设计良好 ✅

  • cleanupOrphanAttachments:保护头像/封面/内容嵌入图/缩略图 + 24 小时时间缓冲 + 跳过符号链接 + 仅扫 uploads(medals 图放 assets/medals/ 不会被误删,与交接文档约定一致)✅
  • 删除帖子:附件文件名白名单正则(hex名.扩展名)防路径穿越 ✅

2.6 搜索/分页/排序 —— 参数化与权限过滤 ✅

  • Search::search:分词 token 全部命名占位符 + 版块权限过滤(allowedCategoryIds)✅
  • User::search:LIKE 通配符转义 + 分页 (int) ✅
  • sanitizeOrderBy 黑名单(S2,低危)

2.7 错误处理 —— 良好 ✅

  • 404 视图已存在(errors/404.php);插件 hook 异常隔离;DB 异常统一 error_log 不回显 ✅
  • 孤儿文件复核:admin/settings.php、schema_mysql.sql/schema_sqlite.sql、rebuild_runtime.php、emails/verify_email.txt、tmp_audit_xss.php 均已删除 ✅

三、2026-08-06 报告整改状态汇总

编号问题状态
R1/R2SSRF 两个绕过点❌ 未修复(🔴 优先)
P-1用户搜索泄露 email/role/status❌ 未修复
P-2改邮箱无需密码(账号接管链)❌ 未修复
P-3登录无 IP 级限流❌ 未修复
P-4发新主题无频率限制❌ 未修复
P-5/P-9前台 admin 操作绕过二次验证❌ 未修复
P-6忘记密码无验证码❌ 未变(低危)
P-7RateLimiter TOCTOU❌ 未变(低危)
P-8主题切换无 requireLogin❌ 未变(低危)
U1uploads 无脚本执行防护❌ 未修复
U2/U3上传 finfo 兜底 / 原图未校验❌ 未变(低危)
S1后台 SQL 导入 exec❌ 未变(功能固有风险)
S2sanitizeOrderBy 黑名单❌ 未变(低危)
X1theme/settings.php $color 未转义✅ 已修复
4.2user_profile 悬空 404 视图✅ 已修复(errors/404.php 已建)
4.1孤儿文件(settings.php/schema/rebuild/emails)✅ 已删除
4.5临时文件 tmp_audit_xss.php✅ 已删除
C1/C2config 弱口令/固定密钥⚠️ 部署注意项(未改)


四、本次新增发现(2026-08-12)

#位置风险说明
L1quiz_duel accept()🟠 中并发应战缺陷(双扣分/重复发奖),需行锁或条件 UPDATE
L3invite 生成邀请码🟠 中Points::award 负值被拒 → 扣分静默失效(插件停用中)
L2daily_checkin🟡 低INSERT+UPDATE 无事务,部分失败积分丢失
L4medal grant()🟡 低唯一键冲突异常未捕获(自动颁发循环中断)
L5dice 日次数🟡 低次数检查与扣分非原子,并发可突破日上限


五、风险汇总矩阵(按优先级)

优先级问题位置
🔴 高SSRF:169.254.0.0/16 与 100.64.0.0/10 未封禁 + 重定向未二次校验ApiController.php:181-236
🟠 中改邮箱无需密码(账号接管链)ProfileController.php:31-52
🟠 中发新主题无频率限制(刷积分)PostController.php:20
🟠 中登录无 IP 级限流AuthController.php:23
🟠 中前台 admin-only 操作绕过二次验证BlogController / ThreadController / PostController
🟠 中用户搜索泄露 email/role/statusUser.php:38
🟠 中uploads 目录无禁止脚本执行规则assets/uploads/
🟠 中quiz_duel 并发应战缺陷QuizDuelController.php:204
🟠 中invite 生成邀请码不扣积分(停用中)InviteController.php:47
🟡 低RateLimiter TOCTOU / 忘记密码无验证码 / 主题切换无登录 / sanitizeOrderBy 黑名单 / 上传兜底 / 签到事务 / medal grant 异常 / dice 日次数等多处

六、建议整改顺序

  1. 安全:修复 SSRF 两绕过点(R1:补 169.254.0.0/16、100.64.0.0/10;R2:重定向逐跳校验)→ 改邮箱加密码确认(P-2)→ 发帖补限流(P-4)→ 登录补 IP 级限流(P-3)→ uploads 禁止脚本执行(U1)
  2. 逻辑:quiz_duel accept 加 FOR UPDATE/条件 UPDATE(L1)→ invite 改用 Points::deduct(L3)
  3. 信息泄露:User::search 裁剪字段(P-1)
  4. 低危:签到事务化(L2)、medal grant 捕获唯一键异常(L4)、dice 次数原子化(L5)、RateLimiter 加读锁
  5. 部署卫生:更换 config.php 弱口令与固定密钥(C1/C2)

审计完成 — SoSite 2026-08-12。本次未修改任何代码,所有结论基于只读检查。

轻量级、高性能、零 MySQL 依赖的PHP社区系统。
| Views 3 | Replies 0

All Replies (0)

No replies yet

Please Log in