[审计]FlintHub assets 静态安全审计报告

👑Lv.11 元老 🌞 骨干会员
2026-10-26 10:55:33

FlintHub assets 静态安全审计报告

审计对象:uploads/assets.zip 解压后的前端资源,工作副本为 assets_audit_src/。审计日期:2026-09-29。

结论

资源包没有确认的远程代码执行或 SQL 注入原语。发现的主要风险集中在富文本编辑器的客户端协议过滤、以 GET 执行远程图片落盘、HTMX/Alpine 的动态执行能力,以及重复资源和第三方依赖缺少完整 provenance。

客户端净化不能替代服务端净化。当前 app/Helpers/Content.php 的服务端白名单、控制字符删除和 CSS 过滤提供了重要纵深防线,但编辑器预览仍可能先处理到未被客户端正确拦截的链接。

这是静态审计,不代表已在真实站点完成浏览器攻击、跨站请求、服务器配置或 PHP 运行时验证。

0已确认高危
3中危或条件性中危
3低危/供应链与维护项
assets_audit_src审查副本

中危与条件性中危

中危A-01 客户端协议过滤可被控制字符绕过

js/editor.js:618-652;服务端对照:app/Helpers/Content.php:113-117

编辑器将属性值转小写后,直接检查是否以 javascript: 开头,但没有先移除或规范化属性值中的空格、制表符、换行和控制字符。浏览器会把部分形式规范化为可执行的 javascript: 协议;已验证的例子包括 java\nscript:、java\tscript:。

影响:恶意或历史未净化正文在编辑器预览中可能留下危险链接。当前服务端净化层会删除这类协议,因此静态证据不足以确认存储型 XSS,但客户端防线本身不完整。
修复:对 href、src 和相关 URL 先删除 U+0000-U+0020、U+007F 等控制字符,再使用严格协议白名单;补充 CR/LF/Tab、HTML 实体和混合大小写测试。

中危,条件性A-02 远程图片抓取使用 GET 且不带 CSRF

js/editor.js:2247-2275;app/Controllers/ApiController.php:191-249

编辑器通过原生 XHR 调用 GET /api/fetch-image?url=...。后端要求登录并检查附件权限,也做了 host/IP 和逐跳重定向校验,但该写入上传目录的操作没有 CSRF token;编辑器调用也没有传 category_id。

影响:在站点 Cookie 跨站发送且用户具备附件权限的部署条件下,第三方页面可能诱导浏览器触发远程抓图、消耗配额和磁盘。SameSite Cookie 或浏览器策略可能降低可利用性,但不能代替接口设计上的 CSRF 控制。
修复:改为 POST;校验 CSRF;显式传入并校验真实版块 ID;继续保留 SSRF、重定向和响应大小限制。若必须保留 GET,应保证其绝不产生落盘或其他状态变化。

中危,条件性A-03 HTMX/Alpine 允许动态表达式和脚本响应

lib/fhajax.js:16;lib/fhstate.js;app/Views/layouts/main.php:87-91

本地 HTMX 兼容层默认启用 allowEval:true 和 allowScriptTags:true;Alpine 运行时包含基于 new Function 的表达式执行。若不可信响应、模板属性或可编辑数据进入这些处理路径,HTML 交换可能扩大为脚本执行。

影响:风险取决于服务端响应是否完全可信、是否允许用户控制 hx-*/x-* 属性以及 CSP 是否存在。资源本身不能证明已形成可利用的 stored XSS,但动态执行面明显扩大。
修复:在业务不需要时关闭 HTMX eval 和脚本标签;对响应片段实行可信来源策略;限制 Alpine 指令可接受的数据;部署严格 CSP,优先使用 nonce/hash,避免把用户数据放入 HTML 属性或表达式。

低危与维护风险

低危,条件性A-04 翻译文案被拼接到 innerHTML

js/editor.js:1002、js/auth.js:31;app/Views/layouts/main.php:72-78

编辑器标签栏和密码强度提示使用 innerHTML 拼接 window.__t() 返回值。当前语言字典由服务端 JSON 安全注入,若字典只来自受信任代码文件,风险较低;若未来允许管理员或用户编辑翻译值,就会成为 DOM XSS 入口。

修复:文案使用 textContent 或 DOM 节点 API;确需图标 HTML 时分离固定模板和动态文字,禁止将翻译值直接作为 HTML 片段。

低危,可靠性编辑器存在多个重复版本,容易产生安全修复漂移

js/editor.js、js/editor.php、js/editor_zip/editor.js、js/editor.zip

资源包同时包含实际主文件、PHP 扩展名副本和嵌套压缩包副本。它们功能和行号存在差异;实际页面从 app/Views/layouts/main.php:66 加载 js/editor.js,但部署或打包流程若选择了其他副本,可能带入旧的净化逻辑。

影响:修复只落在一个副本时,生产环境仍可能使用未修复版本;PHP 扩展名还会增加服务器 MIME/处理器配置的不确定性。
修复:保留单一源文件和明确的构建产物;删除未使用的副本与嵌套压缩包;在 CI 中对最终发布目录做 hash 和版本一致性检查。

低危,供应链第三方资源的版本与完整性元数据不完整

js/marked.min.js;js/turndown.js;js/turndown-plugin-gfm.js;lib/fhajax.js;lib/fhstate.js

资源均为本地副本,未见 package lock、发布 hash、构建来源或统一的依赖清单。marked.min.js明确标注 v15.0.12,HTMX 兼容层标注 2.0.10,其他资源的版本和来源不完整。

影响:无法仅凭资源包可靠复现依赖来源、核对上游安全公告或确认生产文件未被替换。
修复:记录每个依赖的名称、版本、来源、许可证和 SHA-256;固定构建输入;在发布流程验证 hash,并定期检查上游安全公告。

已确认的正向控制

  • 编辑器用独立 createHTMLDocument 沙箱解析 HTML,并移除 script、style、iframe、object、embed、svg 等标签。
  • 服务端 Content::sanitizeHtml() 删除 raw-text 元素,限制标签/属性白名单,并在 URL 过滤前移除控制字符;sanitizeCssStyle() 拦截 url()、expression()、@import、javascript: 等模式。
  • 编辑器上传使用 POST 并附带 CSRF token;后端上传接口校验请求方法、Session、CSRF、版块附件权限和上传限流。
  • 远程图片接口已实现 host/IP 内网阻断、DNS 解析后的 IP 校验和逐跳重定向检查;这些控制不抵消 GET/CSRF 设计问题。
  • 本次对主要 JavaScript 资源和 editor.php 做了 Node 语法解析检查,未发现语法错误;未发现直接的 eval 或命令执行调用,Alpine/HTMX 的框架级动态执行另列于 A-03。

资源范围

  • 编辑器与交互:js/editor.js、js/auth.js、js/lightbox.js、js/pow.js、js/thread.js。
  • 本地依赖:js/marked.min.js、js/turndown.js、js/turndown-plugin-gfm.js、lib/fhajax.js、lib/fhstate.js、lib/qrcode.min.js。
  • 样式与主题:根目录 CSS、css/themes/ 及嵌套 themes.zip 副本。
  • PWA:pwa/manifest.webmanifest 与四个 PNG 图标资源。

检查结果与限制

  • 浏览器验证了 URL 属性中的换行和制表符会被规范化为 javascript: 协议形式;该结果用于支持 A-01。
  • 没有 PHP CLI,未能运行 php -l 或后端集成测试;editor.php 已通过 JavaScript VM 解析检查。
  • 没有完整入口、路由、生产 CSP、Cookie 属性、Web Server 配置和语言字典管理流程,因此 A-02 至 A-04 的公网影响需要部署验证。
  • 未发现 CSS 外链、expression()、-moz-binding 或明显的恶意外连;本结论不替代依赖来源与 hash 验证。

建议修复顺序

  1. 先修复 A-01:统一客户端和服务端 URL 协议规范化,加入控制字符、实体和大小写组合测试。
  2. 将 /api/fetch-image 改为 POST + CSRF,并显式携带真实 category_id;继续执行响应大小上限和 SSRF 测试。
  3. 评估关闭 HTMX eval/script 响应和收紧 Alpine 指令,配合严格 CSP 做运行时防护。
  4. 将动态文案从 innerHTML 改为 textContent,删除或构建化管理编辑器重复副本。
  5. 补齐第三方依赖清单、版本、来源和 SHA-256,随后在真实站点做浏览器级 XSS、CSRF、上传和部署配置复测。
报告为 assets 静态审计结果,不代表已在真实服务器上完成渗透测试。文件位置:outputs/assets_audit_report.html。
轻量级、高性能、零 MySQL 依赖的PHP社区系统。
| 浏览 1 次 | 回复 0 次

全部回复 (0)

暂无回复

请 登录