feat(studio): inject.ts 去 gamedef 化石注释 + CSP 收紧(撤 unsafe-eval)

产物沙箱 inject.ts 外科改(两条加载路径主体不碰):
- 删 L69-71 三行 gamedef 专属注释化石(声明式 gameDefinition behaviors/rules
  + gd-runtime new Function 编译执行的理由)
- CSP script-src 由 'unsafe-inline' 'unsafe-eval' 收紧为 'unsafe-inline':
  两条活路径(A-model esbuild iife bundle / SDK Runtime 内联)皆静态打包、
  不含 eval/new Function,'unsafe-eval' 纯属已删 gamedef gd-runtime 遗留需求,
  撤之缩小 XSS 攻击面、不影响活路径

验证:cd game-studio && npm run build = 绿(vue-tsc 类型检查 + vite build
全过,✓ built;CSP/注释改动不引入类型错,无 spec 预警的 vue-i18n 红)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
lili 2026-06-25 02:28:56 -07:00
parent 5661e2015f
commit 0fa1cda1b7

View File

@ -65,10 +65,8 @@ export function buildIframeSrcdoc(
: ''; : '';
// CSP(P2 引擎包分支沿用·零放宽外域): // CSP(P2 引擎包分支沿用·零放宽外域):
// - script-src 'unsafe-inline' 'unsafe-eval':内联脚本执行(SDK/Runtime 注入 + P2 引擎 bundle 内联 <script>),不放外域 <script src>; // - script-src 'unsafe-inline':内联脚本执行(SDK/Runtime 注入 + P2 引擎 bundle 内联 <script>),不放外域 <script src>;
// 'unsafe-eval' 为 **gamedef 运行时必需**:声明式 gameDefinition 的 behaviors/rules 各带逻辑 JS 串,gd-runtime 用 new Function 编译执行; // 两条活路径(A-model esbuild iife bundle / SDK Runtime 内联)皆静态打包、不含 eval/new Function,故不需 'unsafe-eval';
// 缺它则 new Function 抛 EvalError 被静默吞进 errors[] → tickBehaviors 空 → 游戏只渲首帧静态、世界永不演进(bug#2 实证 2026-06-21,A/B:加后 errCnt 7→0、score 0→演进);
// 安全承接:逻辑串经 scanLogic 静态拦危险面 + connect-src 'none' 无网络出站 + iframe sandbox 隔离,三重边界使 'unsafe-eval' 不扩大真实攻击面;
// - connect-src 'none':禁一切网络出站。引擎 bundle 文本由【宿主层 fetch】后内联,非 iframe 内 fetch,故无需放宽; // - connect-src 'none':禁一切网络出站。引擎 bundle 文本由【宿主层 fetch】后内联,非 iframe 内 fetch,故无需放宽;
// 引擎资产经 GamePackage assets[].url 走 <img>/drawImage 加载(img-src 已放行),不触发 connect-src 死结(shouldFix#2)。 // 引擎资产经 GamePackage assets[].url 走 <img>/drawImage 加载(img-src 已放行),不触发 connect-src 死结(shouldFix#2)。
// - img-src data: blob: https::放开 demo/引擎资源占位加载(现状即够,引擎不在 iframe 内 fetch 资产)。 // - img-src data: blob: https::放开 demo/引擎资源占位加载(现状即够,引擎不在 iframe 内 fetch 资产)。
@ -78,7 +76,7 @@ export function buildIframeSrcdoc(
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" /> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<meta http-equiv="Content-Security-Policy" <meta http-equiv="Content-Security-Policy"
content="default-src 'none'; script-src 'unsafe-inline' 'unsafe-eval'; style-src 'unsafe-inline'; img-src data: blob: https:; connect-src 'none';" /> content="default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; img-src data: blob: https:; connect-src 'none';" />
<style> <style>
html,body{margin:0;height:100%;background:#070911;overflow:hidden;} html,body{margin:0;height:100%;background:#070911;overflow:hidden;}
#game{display:block;width:100%;height:100%;touch-action:none;} #game{display:block;width:100%;height:100%;touch-action:none;}