Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,11 @@ src/

## 部署

- **GitHub Pages**:push `master` 自动触发 [deploy.yml](./.github/workflows/deploy.yml)(typecheck/test/lint/build 全绿后部署;复制 `404.html` 使子路由直链与刷新可用)。
- **Vercel**:仓库含 [vercel.json](./vercel.json)(含 SPA rewrite),导入仓库即可;锁文件以 `--frozen-lockfile` 安装。
- **Docker**:见 [Dockerfile](./Dockerfile) 与 [nginx/](./nginx/)(多阶段构建 + nginx 1.30,`docker build` 时通过 `--build-arg CESIUM_ION_TOKEN=` 传参)。产物文件名带内容哈希,仅哈希文件一年长缓存,入口与 Cesium 等无哈希资源每次协商;默认附带基础安全响应头,CSP 需按实际资源来源收敛后在 `nginx/security-headers.conf` 中启用。
三条产线的安全响应头基线一致(审计 2026-09-22):`X-Content-Type-Options` / `Referrer-Policy` / `X-Frame-Options` / `Permissions-Policy` / CSP;CSP 来源清单按产物逐域核实(高德、Cesium ion、OSM 瓦片、appList 图标、演示视频 CDN),`'unsafe-eval'` 因 Cesium Knockout 模板编译保留。启用 Clarity 统计的部署需自行在 CSP 中追加 `https://www.clarity.ms` 与 `https://c.bing.com`。

- **GitHub Pages**:push `master` 自动触发 [deploy.yml](./.github/workflows/deploy.yml)(typecheck/test/lint/build 全绿、产物秘钥扫描通过后部署;复制 `404.html` 使子路由直链与刷新可用)。平台无法自定义响应头,安全头经产物内的 CSP `<meta>` 提供(`config/config.github.ts`);`X-Frame-Options` 等响应头级的点击劫持防护为平台限制,介意者请用另外两条产线。
- **Vercel**:仓库含 [vercel.json](./vercel.json)(含 SPA rewrite 与安全响应头 `headers`),导入仓库即可;锁文件以 `--frozen-lockfile` 安装。
- **Docker**:见 [Dockerfile](./Dockerfile) 与 [nginx/](./nginx/)(多阶段构建 + nginx 1.30,`docker build` 时通过 `--build-arg CESIUM_ION_TOKEN=` 传参)。产物文件名带内容哈希,仅哈希文件一年长缓存,入口与 Cesium 等无哈希资源每次协商;CSP 以 `Content-Security-Policy-Report-Only` 观察一个迭代周期后在 `nginx/security-headers.conf` 中转正式。

## 第三方许可说明

Expand Down
18 changes: 18 additions & 0 deletions config/config.github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,24 @@ export default defineConfig({
PUBLIC_PATH: '/umi-react-admin/',
UMI_APP_API_BASE: process.env.UMI_APP_API_BASE,
},
// umi 对 metas 数组为整体覆盖(不与 config.ts 逐项合并),viewport 需一并带上。
// meta CSP(审计 2026-09-22 H-3):GitHub Pages 无法自定义响应头,只能走 meta;
// meta 版不支持 frame-ancestors(点击劫持防护为平台限制,README 已声明)与 report-only。
// 来源清单与 nginx/security-headers.conf、vercel.json 保持一致(后者含 frame-ancestors)。
metas: [
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{
'http-equiv': 'Content-Security-Policy',
content:
"default-src 'self'; base-uri 'self'; form-action 'self'; object-src 'none'; " +
"script-src 'self' 'unsafe-eval' https://*.amap.com; style-src 'self' 'unsafe-inline'; " +
"img-src 'self' data: blob: https://gw.alipayobjects.com https://img.alicdn.com https://*.amap.com https://*.autonavi.com " +
'https://tile.openstreetmap.org https://ion.cesium.com https://api.cesium.com https://assets.ion.cesium.com https://*.virtualearth.net; ' +
"connect-src 'self' blob: https://*.amap.com https://*.autonavi.com https://ion.cesium.com https://api.cesium.com https://assets.ion.cesium.com https://*.virtualearth.net; " +
"font-src 'self' data:; media-src 'self' https://sf1-cdn-tos.huoshanstatic.com; " +
"worker-src 'self' blob:; frame-src 'self'",
},
],
favicons: ['/umi-react-admin/favicon.ico'],
base: '/umi-react-admin/',
publicPath: '/umi-react-admin/',
Expand Down
19 changes: 16 additions & 3 deletions nginx/security-headers.conf
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,20 @@
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=(), usb=(), fullscreen=(self)" always;

# CSP 未默认开启:地图(Cesium ion、高德)、第三方 CDN 媒体、Web Worker 等来源较多,
# 贸然开启容易大面积白屏。上线前按实际用到的来源收敛后再启用,例如:
# add_header Content-Security-Policy "default-src 'self'; img-src 'self' data: blob: https:; connect-src 'self' https:; worker-src 'self' blob:" always;
# CSP(审计 2026-09-22 H-3):先以 Report-Only 观察一个迭代周期,确认无地图/富文本/播放器
# 白屏后再去掉 -Report-Only 后缀转正式。来源清单按产物逐域核实(与 vercel.json / config.github.ts 保持一致):
# - 'unsafe-eval':Cesium Knockout 模板编译用 new Function(实测在用),pdfjs 已关 isEvalSupported
# - style 'unsafe-inline':AntD cssinjs 运行时注入 + tailwind 任意值
# - 高德/autonavi:react-amap JSONP;openstreetmap:InfoMap OSM 瓦片;ion.cesium.com:默认影像
# - virtualearth.net:未配置 ion token 时 Cesium 的 Bing 影像兜底(元数据 + 瓦片)。
# 注意瓦片协议跟随页面协议(uriScheme):本站以 http 提供时 Cesium 会请求 http://ecn.t*.tiles…,
# 与 https:// 白名单不匹配(生产 https 部署不受影响);配置了 ion token 的部署走 ion 影像,与此无关
# - alipayobjects/alicdn:appList 图标;huoshanstatic:xgplayer 演示视频(media-src)
# 启用 Clarity 统计的部署需在 script-src/connect-src/img-src 追加 https://www.clarity.ms https://c.bing.com
add_header Content-Security-Policy-Report-Only "default-src 'self'; base-uri 'self'; form-action 'self'; object-src 'none'; frame-ancestors 'self'; script-src 'self' 'unsafe-eval' https://*.amap.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https://gw.alipayobjects.com https://img.alicdn.com https://*.amap.com https://*.autonavi.com https://tile.openstreetmap.org https://ion.cesium.com https://api.cesium.com https://assets.ion.cesium.com https://*.virtualearth.net; connect-src 'self' blob: https://*.amap.com https://*.autonavi.com https://ion.cesium.com https://api.cesium.com https://assets.ion.cesium.com https://*.virtualearth.net; font-src 'self' data:; media-src 'self' https://sf1-cdn-tos.huoshanstatic.com; worker-src 'self' blob:; frame-src 'self'" always;

# HSTS:本服务监听 8080 明文(TLS 通常终止在上游 LB)。若本服务直接对外提供 HTTPS,
# 取消注释启用(max-age 按需调整;启用前确认所有子域均可 HTTPS 访问):
# add_header Strict-Transport-Security "max-age=31536000" always;
18 changes: 18 additions & 0 deletions vercel.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,24 @@
"framework": "umijs",
"installCommand": "pnpm install --frozen-lockfile",
"rewrites": [{ "source": "/(.*)", "destination": "/index.html" }],
"headers": [
{
"source": "/(.*)",
"headers": [
{ "key": "X-Content-Type-Options", "value": "nosniff" },
{ "key": "Referrer-Policy", "value": "strict-origin-when-cross-origin" },
{ "key": "X-Frame-Options", "value": "SAMEORIGIN" },
{
"key": "Permissions-Policy",
"value": "camera=(), microphone=(), geolocation=(), payment=(), usb=(), fullscreen=(self)"
},
{
"key": "Content-Security-Policy",
"value": "default-src 'self'; base-uri 'self'; form-action 'self'; object-src 'none'; frame-ancestors 'self'; script-src 'self' 'unsafe-eval' https://*.amap.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https://gw.alipayobjects.com https://img.alicdn.com https://*.amap.com https://*.autonavi.com https://tile.openstreetmap.org https://ion.cesium.com https://api.cesium.com https://assets.ion.cesium.com https://*.virtualearth.net; connect-src 'self' blob: https://*.amap.com https://*.autonavi.com https://ion.cesium.com https://api.cesium.com https://assets.ion.cesium.com https://*.virtualearth.net; font-src 'self' data:; media-src 'self' https://sf1-cdn-tos.huoshanstatic.com; worker-src 'self' blob:; frame-src 'self'"
}
]
}
],
"github": {
"silent": true
}
Expand Down
Loading