[审计]SoSite V3.0.0 代码审查报告(更新版)

👑Lv.11 元老 🌞 骨干会员
2026-10-24 00:35:50

本文由 FlintHub 开发文档归档发布。原始文档日期见标题前缀,来源:备忘md/code_review_report_20260621.md。

SoSite V3.0.0 代码审查报告(更新版)

审查日期:2026-06-21(更新)

审查范围:95+ PHP 文件(50 个控制器/模型 + 13 个 Helpers + 6 个 Core + 视图模板 + 入口文件)

审查方法:逐文件阅读,追踪数据流(Source → Sink),检查安全边界和逻辑正确性


总体评分:良好 ✅

核心安全机制健全:

  • 全部 SQL 使用参数化绑定,无字符串拼接(:param 风格)
  • 模板引擎 {$var} 自动 htmlspecialchars() 转义
  • CSRF Token 在关键写操作均有校验
  • 密码使用 password_hash(PASSWORD_DEFAULT) + 恒定时间 password_verify()
  • 文件上传有 MIME 校验 + 扩展名白名单 + 危险扩展拦截
  • 会话 Cookie 已设 httponly、SameSite=Lax、secure

发现的问题

① FTS 同步使用字符串内联 SQL(低风险)

项目内容
文件app/Helpers/Search.php — syncThreadFTS() / syncBlogFTS() (L182-198, L203-219)
代码$conn->exec("DELETE FROM threads_fts WHERE rowid = {$threadId}") 使用了字符串内插而非参数绑定
风险虽然 $threadId 已被 (int) 强制类型转换,SQL 注入不可行,但这是不安全的编码模式,未来维护者可能复制此模式到其他场景
建议改为参数化绑定


② highlightTerms() 双编码 + @ 抑制错误(低风险)

项目内容
文件app/Helpers/Search.php — highlightTerms() (L144-162)
描述@preg_replace 抑制错误,函数内部对已转义文本再次调用 htmlspecialchars
建议移除 @ 错误抑制符,确认双编码场景


③ 后台删除操作通过 GET 传递 CSRF Token(中风险)⚠️

项目内容
涉及文件5 个文件
代码模式使用 GET 请求 + URL 中的 csrf token 执行删除。CSRF Token 在 URL 中可通过 Referer 头泄露
风险等级中等 - CSRF Token 在 URL 中容易被日志记录、浏览器历史、第三方服务引用等场景泄露

涉及文件列表:

  • app/Controllers/Admin/ThreadController.php — 主题删除 (L10-L13)
  • app/Controllers/Admin/UserController.php — 用户删除 (L44-L51)
  • app/Controllers/Admin/CategoryController.php — 分类删除 (L37-L41)
  • app/Controllers/Admin/TagController.php — 标签删除 (L10-L16)
  • app/Controllers/Admin/DatabaseController.php — 备份/优化操作 (L52-L55, L78-L81, L95-L98)

建议:改为 POST 请求执行删除操作


④ SettingsController 无输入验证(低风险)

项目内容
文件app/Controllers/Admin/SettingsController.php (L12-L17)
代码$_POST[$key] 直接存储,无长度/内容校验

| 建议 | 增加长度限制和 HTML 标签剥离(参考 ThemeController::saveCss() 的做法)


⑤ ThemeController::delete() 使用 ReflectionClass 清空私有静态属性(设计问题)

项目内容
文件app/Controllers/Admin/ThemeController.php
描述通过反射访问 Theme::$cachedThemes 私有属性
建议Theme 类增加 public static function clearCache() 公开方法


⑥ TemplateCompiler 缓存写入非原子操作(低风险)

项目内容
文件app/Core/TemplateCompiler.php — renderOne() (L203-L207)
描述file_put_contents($cacheFile, $php) — 非原子写入,并发时可能产生不完整缓存文件

| 建议 | 采用 .tmp + rename 模式(如 Settings::buildCache() 的做法)


⑦ 后台 VerifyController 未限制尝试次数(低风险)

项目内容
文件app/Controllers/Admin/VerifyController.php (L8-L17)
描述管理员二次密码验证无速率限制

| 建议 | 增加 Session 或 IP 级别的尝试次数限制


逻辑问题

⑧ 用户删除不检查唯一管理员(逻辑问题)⚠️

项目内容
文件app/Controllers/Admin/UserController.php (L44-L51)
描述仅检查 $uid > 1 保护 ID 为 1 的用户。如果后来 admin 角色给了其他用户,ID 为 1 的用户被删除后系统将无管理员

| 建议 | 删除前检查被删用户是否为管理员且是否为最后一个管理员


⑨ Vote.php 中 SQL 风格不一致(低风险)

项目内容
文件app/Helpers/Vote.php (L45-L47)
描述LIMIT 子句使用字符串内联(已 (int) 强转安全),与代码库其他处的参数化风格不一致

| 建议 | 改为参数化绑定


⑩ 登录锁定仅基于 Session(低风险)

项目内容
文件app/Controllers/AuthController.php
风险攻击者可清 Cookie 绕过锁定

| 建议 | 结合 IP 进行锁定


⑪ 登录恒定时间比较中的 dummyHash 使用 static 变量(低风险)

项目内容
文件app/Controllers/AuthController.php
描述static $dummyHash = null 使用 static 缓存 dummyHash,无实际安全影响

| 建议 | 可移除,不影响安全性


修复优先级建议

🔴 高优先级(建议立即修复)

  • 问题③:5 个后台删除操作改用 POST 请求(涉及面最广,风险最高)

🟡 中优先级(建议近期修复)

  • 问题⑧:用户删除检查唯一管理员

🟢 低优先级(可逐步优化)

  • 问题①、②、④、⑤、⑥、⑦、⑨、⑩、⑪

汇总

项目值
审查文件数95+ PHP 文件
安全评分85 / 100
直接可利用漏洞0(HIGH / MEDIUM / LOW 均无)
防御层面建议11 项

重点关注:问题③ 后台多个删除操作用 GET 传 CSRF Token,涉及面最广(5 个文件),建议优先处理。

轻量级、高性能、零 MySQL 依赖的PHP社区系统。
| 浏览 5 次 | 回复 0 次

全部回复 (0)

暂无回复

请 登录