docs: plan NavSea PBF tile codec across platforms
This commit is contained in:
95
docs/30_设计/NavSea_PBF自动识别与轻量混淆跨平台方案设计_v1.md
Normal file
95
docs/30_设计/NavSea_PBF自动识别与轻量混淆跨平台方案设计_v1.md
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
# NavSea PBF 自动识别与轻量混淆跨平台方案设计 v1
|
||||||
|
|
||||||
|
日期:2026-09-27
|
||||||
|
状态:**规划 / DESIGN ONLY;未实现、未测试、未发布。**
|
||||||
|
适用范围:NavSea 自有矢量海图 PBF,MapLibre Native Android / iOS 与 MapLibre GL JS Web。
|
||||||
|
归属:MapLibre 资源加载适配层;**不是粒子、Weather Field 或 QBIN 格式变更**。
|
||||||
|
|
||||||
|
## 1. 背景与目标
|
||||||
|
|
||||||
|
NavSea 计划对自己分发的 PBF 进行低成本字节混淆,避免直接下载后被普通 PBF/MBTiles 工具读取;客户端收到瓦片后恢复标准 PBF,继续使用原有 MapLibre 解析和渲染链。Web 版本也要消费同一份服务器资源。
|
||||||
|
本方案明确只是增加直接复用数据的门槛,不承诺数字版权保护、防逆向或防止明文提取。客户端可被调试,解码后的 PBF 可在内存或缓存环节被截获;公开 Web 尤其如此。
|
||||||
|
|
||||||
|
**核心规则:检测到 NavSea 专用 Magic Header → 按版本解码;未检测到 → 维持 MapLibre 原有标准资源流程。** 不依据文件后缀决定是否解码,不修改标准 PBF 解析器,不建立第二套地图引擎。
|
||||||
|
|
||||||
|
## 2. 范围与不变项
|
||||||
|
|
||||||
|
- 只处理自有矢量瓦片资源;普通 PBF、第三方瓦片、Style JSON、Sprite、Glyph、图片以及 Weather/QBIN 不受影响。
|
||||||
|
- 原有 URL 路径、Source/Layer、Style Z-order、粒子绘制、GPU、地图交互与正常 HTTP 重试行为不变。
|
||||||
|
- 服务器可同时提供普通 PBF 与封装 PBF;三端遵守同一二进制契约,各自实现资源加载适配。
|
||||||
|
- 只在有效响应体上进行格式识别;404、500、304、取消、空响应等继续走既有错误/缓存语义,不把错误页当 PBF 解码。
|
||||||
|
- 本文是未来工作的设计草案;不指定当前源码已有某个具体 Hook,进入实施前须按当前 fork 做只读调查。
|
||||||
|
|
||||||
|
## 3. 封装结构草案
|
||||||
|
|
||||||
|
建议文件名仍为 `.pbf`,但编码后内容已不是标准 PBF,必须先解封装。以下 **16 字节头仅为待验证候选格式**,实施前冻结字节序、长度和兼容矩阵。
|
||||||
|
|
||||||
|
| 偏移 | 长度 | 字段 | 候选语义 |
|
||||||
|
| --- | ---: | --- | --- |
|
||||||
|
| 0 | 8 | Magic | ASCII `NSVTILE\0`,固定 8 字节 |
|
||||||
|
| 8 | 1 | Version | `1` |
|
||||||
|
| 9 | 1 | Codec | `1 = XOR-v1`;其他值拒绝 |
|
||||||
|
| 10 | 1 | Flags | bit0 表示内部 GZIP,其余保留位须校验 |
|
||||||
|
| 11 | 1 | HeaderLength | v1 固定 16,给后续扩展留入口 |
|
||||||
|
| 12 | 4 | CRC32 | 解封装且内部解压后,标准 PBF 明文的 CRC32;约定字节序 |
|
||||||
|
| 16… | 可变 | Payload | 经 XOR 混淆的原始 PBF 或内部 GZIP 字节 |
|
||||||
|
|
||||||
|
CRC32 只检测意外损坏或密钥不匹配的常见现象,**不是抗恶意篡改认证**。Magic 是类型标识,不是秘密,也不是加密强度来源。头部存在但格式、版本、长度、Flags、Codec 或校验不合法时,必须拒绝,不能退回普通 PBF。
|
||||||
|
|
||||||
|
## 4. 编码、识别、解码
|
||||||
|
|
||||||
|
服务器预处理一次:标准 PBF → 计算明文 CRC32 → 可选内部 GZIP → XOR → 添加 Header → 存储/CDN。对于已经是 GZIP 存储的原始瓦片,应先核对实际字节语义,再决定保留内部压缩还是重新封装,避免重复压缩。
|
||||||
|
客户端:收到已按 HTTP 传输层规则处理的响应体 → 检查 Magic → 读取并验证头部 → XOR 还原 Payload → 按 Flags 内部解压 → 校验长度/CRC32 → 把标准 PBF 交给现有解析器。普通资源无 Magic 时完全返回既有处理链,不新增一次盲目 GZIP 解压。
|
||||||
|
|
||||||
|
**HTTP `Content-Encoding` 与封装内部 GZIP 必须分开。** XOR 后的压缩 Payload 不得冒充 HTTP gzip,否则网络库可能在 XOR 前尝试解压。封装可用 `Content-Type: application/octet-stream`,自定义 `X-NavSea-Tile-Encoding` 仅作辅助诊断;格式识别以响应体 Header 为准。HTTP 层若另行压缩整个封装,须确认客户端收到的是解开传输编码后的封装字节。
|
||||||
|
|
||||||
|
已声明为“必须受保护”的自有 Source 可另设严格策略:缺少 NavSea Header 也报错(fail-closed),防止服务端误发明文;普通/混合 Source 则执行“无头=原路径”。Source 保护策略与字节自动识别是不同层面,不得混为一谈。
|
||||||
|
|
||||||
|
## 5. 三个平台的接入边界
|
||||||
|
|
||||||
|
| 平台 | 未来接入方向 | 重要约束 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| Android | 在当前 fork 的 MapLibre HTTP 资源响应交给解析器前解封装 | 核对 OkHttp/Native 缓存与 Response 回调实际位置,避免双重解压或额外整份复制 |
|
||||||
|
| iOS | 在当前 MapLibre Native 的对应资源响应路径解封装 | 以实际 iOS 网络资源实现为准,不假设 Android Java 修改会覆盖 iOS |
|
||||||
|
| Web | MapLibre GL JS `addProtocol()` 负责 fetch、校验、解封装并返回标准 PBF `ArrayBuffer` | 自有瓦片 URL 经自定义 scheme 或 `transformRequest` 导向注册的协议;后者本身不能修改响应体 |
|
||||||
|
|
||||||
|
Web 必须核对 GL JS 版本及协议回调契约、Style/TileJSON 的 URL 重写、Worker/主线程负载、CORS 和取消信号;服务端需暴露必要响应头。第三方请求不接入解码器。三端共享格式测试向量,不共享平台相关 HTTP 实现。
|
||||||
|
|
||||||
|
## 6. 缓存、错误与日志
|
||||||
|
|
||||||
|
- CDN/HTTP 缓存以**封装字节**为对象;ETag、Content-Length、缓存键、版本及更新失效策略要与实际封装内容一致。
|
||||||
|
- HTTP 304 没有新响应体;由现有缓存/重验证机制恢复对应实体,不能把空体交给解码器。按当前 Native/Web 路径调查 MapLibre 自有缓存究竟保存封装还是明文,不作默认安全保证。
|
||||||
|
- 若业务要求离线缓存也不可直接导出标准 PBF,需单独设计落盘边界;仅 HTTP 层 XOR 不保证 MapLibre 离线库/内存缓存保存密文。
|
||||||
|
- 解码前限制输入大小,解压后限制最大明文大小与压缩比,避免异常瓦片造成内存放大。数据损坏、版本不支持、密钥不匹配归类为独立 Codec 错误。
|
||||||
|
- 将前述 HTTP URL 诊断与 Codec 诊断分开:`INVALID_URL`、`HTTP_ERROR`、`NETWORK_ERROR`、`UNSUPPORTED_TILE_CODEC`、`TILE_DECODE_FAILED`;只记录必要的 URL(敏感查询参数脱敏)、状态码、版本与长度,不输出密钥或明文 PBF;正常 200 不逐张刷日志,可限频。
|
||||||
|
- 404/500、取消、超时、304、第三方瓦片和正常 200 行为均不因本功能改变。
|
||||||
|
|
||||||
|
## 7. 性能与安全预期
|
||||||
|
|
||||||
|
XOR 是 O(n) 的逐字节操作,优先服务器离线预编码、客户端原地处理,避免 React/JS Bridge 往返和多次完整 Buffer 拷贝。封装额外增加 Header 字节;“XOR 不改变 Payload 长度”不等于整体零额外字节。压缩应在 XOR 前进行,否则压缩收益可能明显恶化。
|
||||||
|
Web 先评估主线程处理时长与地图交互,再决定是否使用 Worker;Android/iOS 关注实际缓存策略、内存峰值与线程阻塞。性能影响只能经真实 PBF 样本、冷/热缓存及拖动缩放实测后定论。
|
||||||
|
|
||||||
|
固定或循环 XOR 密钥可以被分析,已知格式和客户端代码会进一步降低逆向门槛;把算法放到 C++/WASM 或换成 AES 也无法阻止客户端截获已解码的明文。本方案定位为**轻量混淆**。若未来目标提高到防批量下载,应另行规划 HTTPS、授权、短期访问凭据、配额/限速、异常下载监测与必要的数据分发范围;不要把 XOR 描述成加密认证。
|
||||||
|
|
||||||
|
## 8. 未来实施阶段(本次均不执行)
|
||||||
|
|
||||||
|
| 阶段 | 工作 | 产出/闸门 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| A 只读调查 | 当前 fork Android/iOS HTTP、资源与磁盘缓存;GL JS 版本;服务器 PBF/GZIP、CDN、TileJSON/Style 路径 | 确认真实接入点、压缩语义和数据所有权 |
|
||||||
|
| B 协议冻结 | 冻结 Header 字节序/CRC 覆盖、Codec、Flags、版本策略、普通/受保护 Source、Golden vectors | 三端可交叉解码同一 fixture |
|
||||||
|
| C 服务端 | 离线编码工具、标准/封装样本、响应头及缓存策略 | 普通与封装资源同时可分发 |
|
||||||
|
| D Android/iOS | 各自最小资源适配,保持解析器与业务接口不变 | 各平台原生样本验证;构建/实机由用户手工执行 |
|
||||||
|
| E Web | 注册自定义协议、URL 路由、解码与取消/CORS | 自有/第三方混合地图正常 |
|
||||||
|
| F 综合验收 | 性能、离线缓存、故障、日志、安全边界与回退 | 三端统一验收通过后再决定发布 |
|
||||||
|
|
||||||
|
验收矩阵至少覆盖:原始 PBF、标准 HTTP gzip、封装 RAW、封装内部 gzip、无头普通资源、受保护 Source 缺头、短头/错误 Magic/版本/Flags、错误 CRC/密钥、空瓦片、404/500/304、网络失败/取消、第三方瓦片、冷/热/离线缓存、跨平台 Golden Fixture、Web CORS 与长时间拖动缩放;不得以单张瓦片可显示作为最终通过。
|
||||||
|
|
||||||
|
## 9. 待实施前决策
|
||||||
|
|
||||||
|
1. 是否采用 XOR-v1 作为正式首版,还是只做试验;客户端密钥静态分发的风险是否接受。
|
||||||
|
2. Magic/Header 的精确二进制布局、CRC 字节序、最大明文长度、Codec ID 和压缩 Flags 是否按本草案冻结。
|
||||||
|
3. 哪些 NavSea Source 必须受保护;普通/混合资源的无头旁路范围。
|
||||||
|
4. 离线缓存是否必须保存封装字节,以及 MapLibre 内建缓存如何满足该要求。
|
||||||
|
5. Web URL 路由和跨域部署方案;第三方瓦片是否保持完全独立。
|
||||||
|
|
||||||
|
**本次结论:仅保留规划文档。没有新增 Codec、改动服务器资源、修改 MapLibre HTTP、引入密钥、触发构建/测试或宣布任何平台支持完成。**
|
||||||
Reference in New Issue
Block a user