[审计]SoSite V3 安全与逻辑审查报告

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

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

SoSite V3 安全与逻辑审查报告

审查日期:2026-06-21

审查范围:100+ PHP 文件(Core / Controllers / Models / Helpers / Views)

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


总体评分:良好 ✅

整体代码质量较高,安全基座扎实。项目普遍使用参数化查询、CSRF 令牌、htmlspecialchars() 输出转义、密码哈希、文件上传校验等标准安全实践。


1. 安全亮点

项目覆盖情况
SQL 注入防护全部使用参数化查询(:param),无字符串拼接 SQL
XSS 防护模板引擎 {$var} 自动 htmlspecialchars,e() 方法统一转义
CSRF 保护所有 POST 修改操作均校验 csrf 令牌
密码安全password_hash() + PASSWORD_DEFAULT,password_verify() 恒定时间比较
文件上传MIME 校验 + 扩展名白名单 + 危险扩展拦截
速率限制登录锁定(5 次/120s)、注册(3 次/h)、投票(30 次/min)、上传(5 次/min)
会话安全httponly、SameSite=Lax、session_regenerate_id() 登录后
内容过滤Content::sanitizeHtml() HTML 白名单过滤,禁止 javascript:/data: 协议


2. 发现的问题

问题一:Search FTS 同步使用字符串内联 SQL(低风险)

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

问题二:highlightTerms() 双编码 + @ 抑制错误

项目内容
文件app/Helpers/Search.php — highlightTerms() L152-L158
描述视图层调用 $this->highlightSearchTerms($this->e($result['title']), $keyword) 时传入已转义文本,函数内部再次 htmlspecialchars() 导致双编码。@preg_replace 抑制错误
风险极低。preg_quote 转义了搜索关键字,注入不可行。@ 仅隐藏错误
建议去掉视图层多余的 $this->e()(函数内部会转义),移除 @ 错误抑制

问题三:Admin 删除操作通过 GET 传递 CSRF Token

项目内容
文件app/Controllers/Admin/ThreadController.php — L10-L13
描述使用 GET 请求 + URL 中的 csrf token 执行删除。CSRF Token 在 URL 中可能通过 Referer 头泄露
风险低。仅限管理员登录后操作,Referer 泄露在同站点场景下风险有限
建议改为 POST 请求或至少使用 $_SERVER['REQUEST_METHOD'] 校验

问题四:设置项无输入验证

项目内容
文件app/Controllers/Admin/SettingsController.php — L12-L17
代码$settingModel->setValue($key, $_POST[$key] ?? '') — 直接存储用户输入
描述site_name 等设置项未做长度/内容校验,XSS 过滤依赖视图层 e() 转义
风险低。管理员可管理后台,理论上已有完全权限
建议增加长度限制和 HTML 标签剥离

问题五:$_SESSION['role'] 直接存储未经校验

项目内容
文件app/Controllers/AuthController.php — L62-L63
代码$_SESSION['role'] = $user['role'] ?? 'user',直接从数据库取值存入 Session
风险极低。前提是数据库已被攻破,此时问题已超出此范围
建议可选:在 Auth::isAdmin() 中每次都查询数据库而非仅读 Session


3. 逻辑评审

问题说明
Vote 积分奖励条件ApiController::vote() 中 $result['user_vote'] 在 toggle() 返回的是本次投票的值,逻辑始终正确。但比较用 == 而非 ===,建议统一
登录锁定 IP 盲区AuthController::login() 的锁定基于 Session,攻击者可通过清空 Cookie 或更换 IP 绕过。建议结合 IP 进行锁定
RememberMe Token 无轮换每次登录生成新 Token,但没有在使用"自动登录"后轮换 Token(防重放)。建议实现 Token Rotation
HTML 模板缓存安全TemplateCompiler 将编译后的模板写入缓存目录。PHP 模板中若包含用户控制的 {$var:raw} 输出,原始内容可能被写入缓存文件。当前代码中 raw 仅用于信任数据,风险极低


4. 总结

项目值
审查文件数100+ PHP 文件
安全评分82 / 100
直接可利用漏洞0(HIGH / MEDIUM / LOW)
防御层面建议5 项(均为低风险,详见第 2 节)

代码库整体安全性良好,没有可直接利用的漏洞。所有数据交互均使用参数化查询、输出正确转义、关键操作受 CSRF 保护、敏感操作有速率限制和登录验证。上述 5 项问题均为防御纵深层面的建议,可分批优化。

轻量级、高性能、零 MySQL 依赖的PHP社区系统。
| 瀏覽 6 次 | 回覆 0 次

全部回覆 (0)

暫無回覆

請 登入