12 KiB
12 KiB
安全审核报告
审核日期:2026-10-14。范围:F:\Codes\HTML\convert 当前目录全部文件,包括隐藏文件。审核开始时目录仅有 index.html(68 行);全文人工审查并进行了危险 API、网络调用、凭据模式扫描。后续也审查了新增的回归测试。
1. 项目概况与依赖
项目是本地离线书签 HTML → CSV 转换器,使用 HTML、CSS、原生浏览器 JavaScript;无框架、后端、数据库、浏览器扩展、桌面 IPC、移动端代码或 CI/CD 配置。
| 清单项 | 结果 |
|---|---|
| 直接第三方依赖及实际版本 | 0;没有 npm/CDN/其他第三方库 |
| 锁文件及关键间接依赖实际版本 | 无锁文件,0 个可识别的间接依赖 |
| 包管理器、依赖清单 | 无;未发现 package.json、requirements.txt、go.mod、Cargo.toml、pom.xml、Podfile 或同类文件 |
| 构建、现成测试 | 无;直接由浏览器打开 HTML |
| 停止维护、长期未更新、疑似仿冒包 | 无适用第三方包 |
因此没有需要逐包检索的名称或版本,也没有可运行的项目级 npm audit / pip-audit / cargo audit 等依赖审计。不为此安装依赖或制造清单。已通过网络查询 OWASP、MDN、WHATWG,核对代码风险与防护方式。没有声称项目受某个 CVE 影响。
浏览器属于外部运行环境;其安装版本、扩展和系统漏洞不属于此项目依赖图,仍需保持浏览器更新。
2. 问题汇总
下表“位置”为修复后代码行;各项详情同时给出审核前行号,方便对应原问题。
| 编号 | 类别 | 严重级别 | 位置 | 状态 |
|---|---|---|---|---|
| S01 | 代码 | High | index.html:26、48 | 已修复;数据变化已获开发者同意 |
| S02 | 代码 | Medium | index.html:31、48 | 已修复 |
| S03 | 代码 | Medium | index.html:5、34 | 已修复;原行为是否触发请求取决于浏览器 |
| S04 | 代码 | Low | index.html:41、47 | 已修复 |
| S05 | 代码 | Low | index.html:62、87 | 建议关注 |
| S06 | 代码 | Low | index.html:70、79 | 已修复 |
未发现 Critical 问题;未发现第三方依赖漏洞或真实硬编码凭据。静态审核和回归测试不能证明不存在所有漏洞。
3. 已修复问题与利用条件
S01:CSV 公式注入(High,条件性风险)
- 原位置:
index.html:44–47。标题仅转义双引号,未处理公式起始字符。 - 条件:攻击者影响网站标题或提供恶意书签文件;用户转换后用会识别 CSV 公式的表格软件打开。是否发生外部请求、敏感数据读取或进一步危害取决于软件、公式功能及安全提示;不声称所有环境都能执行系统命令。
- 修复:统一
toCsvField()编码;对公式符号、相关全角符号、前置空白后的公式符号及开头控制字符添加可见文本:前缀。所有字段仍使用双引号包裹并转义内部双引号。 - 取舍:开发者明确选择了“给危险标题加文本前缀”。正常标题保持原样;危险标题的底层 CSV 数据会变化。采用普通文字前缀避免依赖某个软件对单引号或制表符的特殊解释。
- 参考:OWASP CSV Injection。OWASP 明确指出没有适用于所有表格软件和下游消费者的通用策略。
- 验证:覆盖
= + - @、全角变体、前置空白、Tab、CR、LF、NUL 及实际转换输出。Excel / LibreOffice 的打开、重新保存、再次打开行为待确认,本次没有启动这些应用。
S02:URL 字段未做完整 CSV 编码(Medium)
- 原位置:
index.html:45–47。URL 直接拼接入带引号的字段;未统一转义内部引号。 - 条件:构造浏览器 URL 序列化后仍包含特殊分隔内容的 href,并由下游 CSV 解析器处理。例如
httpx:payload","=1+1会被原来的 http 前缀检查接受,而且浏览器 href 保留双引号;这与 S04 的宽松协议检查相关。普通 HTTP(S) URL 中的引号通常会被编码,不能把每个双引号 URL 都当成可利用案例。 - 风险:CSV 结构损坏;在可突破字段边界的输入/解析器组合下可能插入额外字段或公式。
- 修复:标题和经标准 URL 解析的 URL 都调用同一个 CSV 编码函数,采用 CRLF 行分隔,保留中文 BOM。
- 验证:双引号、逗号、换行、HTML 实体、含引号 URL;浏览器确认上述自定义协议能保留引号,新实现拒绝该输入。浏览器将普通 HTTP(S) 测试 URL 中的引号编码为
%22,输出保持两个字段。
S03:导入 HTML 的外部资源请求风险(Medium)
- 原位置:
index.html:36–37。使用 DOMParser 解析不可信 HTML,没有资源加载策略。 - 条件:用户选择包含 img、iframe 等资源标签的恶意 HTML;使用会在此解析过程中加载资源的浏览器。原始项目在特定浏览器是否发出请求待确认,本次未对修复前版本做动态复现。
- 风险:向攻击者或本机/内网地址发起客户端请求,泄露 IP、访问时间等信息;不属于后端 SSRF,也没有证据表明原代码能读取跨源响应。
- 修复:在未挂载的 template 内容中解析,只读取链接文本和 href,不将导入节点移入活动 DOM;增加
default-src 'none'的 CSP,脚本和样式仅允许匹配 SHA-256 哈希的本地内联内容,禁用 base 和表单提交。删除内联 onclick,改为事件监听器,将内联状态样式移入 style 块。 - 参考:MDN DOMParser.parseFromString、WHATWG template 文档模型、MDN CSP。
- 验证:恶意 img / iframe / stylesheet 资源均指向回归测试的本机计数端点;收到 0 次请求。导入 script 与事件处理器未执行,导入节点未进入页面。
S04:协议校验使用字符串前缀(Low)
- 原位置:
index.html:46。startsWith('http')也允许httpx:等自定义协议。 - 条件:恶意文件包含以 http 开头的自定义协议;下游软件打开链接,且系统安装了对应协议处理器。
- 风险:非预期协议进入导出结果。转换器自身不会导航到这些链接,没有证据表明这构成直接代码执行。
- 修复:使用无 base 参数的
new URL()解析原始 href,只允许http:、https:。不受导入 HTML 的 base 标签影响。非法 URL、相对 URL、file/data/javascript/自定义协议均跳过。 - 验证:大小写 HTTP 接受;其他协议与相对 URL 拒绝。
S06:未释放下载对象 URL(Low)
- 原位置:
index.html:54–60。创建 Blob URL 后没有释放。 - 条件:同一页面反复转换,尤其处理较大的书签文件。
- 风险:累积保留 Blob 内存,可能造成页面资源压力。
- 修复:下载锚点在 finally 中移除,随后延迟释放对象 URL,保留下载触发时间。
- 验证:真实 FileReader 产生 Blob,下载文件名正确,URL 被释放。测试截获下载点击并检查 Blob 内容,没有验证操作系统实际保存文件的交互。
其他加固
- 状态输出使用 textContent。原来的 innerHTML 仅插入数字计数,没有证明原处存在 XSS;这是减少危险输出 API 的加固。
- 读取失败给出用户可理解的状态提示,不输出文件内容或路径。
- 将“100% 安全私密”的绝对声明改为准确的本地处理、不上传书签说明。没有在软件 UI 放入审核过程备注。
4. 密钥、敏感文件与其他检查
- 对全部当前文件进行了 API Key、AccessKey、Token、密码、私钥头、常见云/平台密钥模式、数据库连接串、Webhook 地址检索,并人工检查原始文件全部内容;未发现真实凭据。新增测试中的
file:///secret是拒绝本地协议的测试数据,不是密钥或真实文件路径。 - 未发现
.env、证书、私钥、配置、示例、文档或构建产物中的真实秘密。没有需要迁移到环境变量的配置,因此不创建空的.env.example。 - 当前目录不是 Git 仓库,没有
.git或.gitignore;无法确认历史版本、上级其他仓库、远程仓库或已发布副本曾否包含秘密。若以后加入环境文件,应忽略实际.env并只提交变量名示例。 - 若开发者知道任何凭据曾提交或泄露,应到对应平台作废并重新生成;删除代码不足以消除泄露。
- 未发现 SQL/NoSQL、命令执行、eval、动态代码加载、服务端模板、文件系统路径拼接、解压、反序列化、加密、TLS 关闭、敏感日志、跨窗口消息、凭据存储代码。
- CSRF、服务端 SSRF、CORS、认证/越权、浏览器扩展权限、桌面 IPC/WebView、CI Action 固定版本检查无适用实现。
- 允许用户选取 HTML 是功能输入;accept 属性仅是选择提示,不作为安全边界。导入内容不执行、不挂载、资源加载受策略限制。
- HTTP(S) 书签仍可指向钓鱼网站;转换器不替用户审核目标网站信誉,也不自动访问目标网站。
5. 开发者决定与剩余风险
没有尚未获得批准、必须阻断本次修复的事项。公式前缀的数据变化已获同意;没有依赖大版本升级、删除功能、密钥轮换或旧数据结构兼容修改。
S05:超大文件造成页面卡顿(Low,建议关注)
- 位置:
index.html:62、87,完整读取文件后在主线程解析,并在内存中生成 CSV。 - 条件:用户主动选择极大或结构复杂的 HTML;风险主要是当前页面可用性。
- 方案 A:设定明确的文件大小上限;方案 B:保留无限制输入,未来按实际规模考虑分块处理;方案 C:增加用户确认或可取消处理。
- 建议:先依据真实书签文件大小确定上限。未擅自选取阈值,以免拒绝原本可转换的正常文件。这是后续产品取舍,本次保留原行为。
其他限制与建议:
- 本次浏览器测试使用本机 Chrome,通过临时 HTTP 服务加载;直接 file:// 打开、Firefox、Safari 与实际 Excel/LibreOffice 打开 CSV 的结果待确认。没有扩大“已验证”的范围。
- CSP 哈希必须随内联脚本/样式更新;浏览器计算时使用规范化后的换行。新增测试会检查哈希是否匹配,后续改动需同步计算 SHA-256 哈希。
- 若未来通过服务器公开部署,应在 HTTP 响应增加合适的 CSP 和
frame-ancestors/ 点击劫持防护;meta CSP 不支持所有响应头能力。目前没有服务器配置可修。 - CSP 和 template 防护依赖浏览器正确实现;保持浏览器更新,避免安装会读取页面和文件内容的不可信扩展。
6. 验证与改动文件
- 修改:
index.html,完成上述修复与加固。 - 新增:
security-tests.cjs,仅使用 Node 内置模块和已安装 Chromium 浏览器,无新增第三方依赖。使用独立临时浏览器配置和本机服务器,不使用用户现有浏览器资料。 - 新增:本报告,作为项目审核交付物,不在软件 UI 中展示。
- 原项目没有构建或测试命令,因此不存在可运行的既有构建。执行
node --check security-tests.cjs通过;执行node security-tests.cjs通过:31 项浏览器检查、CSP 哈希一致、导入资源请求为 0。 - 首次沙箱内启动 Chrome/Edge 异常退出;在获得执行环境自动审批后使用沙箱外 Chrome 完成测试。测试期间发现并修正 CSP 哈希换行规范化问题,最终测试通过。
Conventional Commits 建议:
fix(security): harden bookmark parsing and CSV export
未执行 Git 提交;当前目录也不是 Git 仓库。