Skip to content

🔒 为用户脚本执行入口加入构建期调用令牌并显式传递上下文 - #1735

Open
cyfung1031 wants to merge 7 commits into
mainfrom
security/fix-001
Open

🔒 为用户脚本执行入口加入构建期调用令牌并显式传递上下文#1735
cyfung1031 wants to merge 7 commits into
mainfrom
security/fix-001

Conversation

@cyfung1031

@cyfung1031 cyfung1031 commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator

Checklist / 检查清单

  • Fixes mentioned issues / 修复已提及的问题
  • Code reviewed by human / 代码通过人工检查
  • Changes tested / 已完成测试

Description / 描述

背景

ScriptCat 的普通脚本、inject 与 pre-inject 执行路径都需要把已编译的脚本函数交给执行器,再以 ScriptCat 创建的执行上下文启动用户脚本。现有流程中,部分入口通过 window[flag] 完成函数交接,同时脚本主体依赖调用时的 this 作为全局执行上下文。

本 PR 保留现有跨环境交接流程,在执行入口增加一层统一的调用约束,并把执行上下文的提供方收敛到 ExecScript。这样可以在不重构现有脚本加载与 early-start 生命周期的前提下,让“谁可以进入目标函数”和“脚本以哪个上下文执行”成为两个明确的步骤。

本次改动

  • Rspack 在每次构建时生成 SC_RANDOM_FNKEY,作为脚本执行包装器与 ExecScript 之间的调用令牌。
  • 新增 SC_ZN_RAND,作为执行上下文临时方法名的构建级随机前缀;包装器再追加运行时随机值,降低临时属性名称碰撞。
  • ScriptFunc 统一调整为接收 tokencontext、named globals 与 script name;ExecScript.exec() 显式提供这些参数。
  • compileScript、inject 与 pre-inject 入口使用相同的调用约束:令牌匹配后才进入目标函数。
  • 目标函数会短暂挂载到执行上下文,再通过 context[key](...) 的方法调用形式启动,从而保留 userscript 所需的 this === context 语义,同时不依赖 .call().apply().bind()
  • 临时方法属性在目标函数开始执行前删除;原始 named globals 与 script name 参数按原顺序透传。
  • inject / pre-inject 的生成包装逻辑集中在 codeFunction(),减少不同执行路径之间的实现差异。
  • 更新 Vitest 环境常量与相关单元测试,并新增对生成代码的实际运行测试。

实现考虑

构建期调用令牌

调用令牌由构建阶段生成,而执行包装器与 ExecScript 又来自同一套构建产物,因此无需为每个脚本额外维护运行时握手或状态对象,就可以给已有执行入口增加一致的调用约束。页面直接取得挂载函数后,如果没有 ScriptCat 执行器提供的令牌,不会进入目标脚本。

执行上下文由执行器显式提供

旧调用方式把目标函数的 this 与调用形式绑定在一起。本 PR 改为由 ExecScript 明确传入 execContext,包装器只负责校验并启动目标函数。这样执行上下文的来源更清晰,也让普通编译脚本、inject 与 pre-inject 可以使用同一套调用契约。

通过临时方法调用保留 this

userscript 执行仍需要目标函数中的 this 指向 ScriptCat 构造的上下文。实现先把目标函数写入 context[key],再以对象方法形式调用,因此 JavaScript 原生调用语义会把 receiver 保持为该 context。临时属性会在参数求值阶段删除,因此目标函数真正开始执行时不会继续保留该挂载。

统一生成代码与运行时契约

compileScript 与生成到 MAIN-world 的 inject / pre-inject 包装器遵循相同的参数顺序和执行规则;inject / pre-inject 又共用 codeFunction() 生成包装代码。这样后续维护执行入口时可以围绕同一组不变量验证行为:令牌校验、context 绑定、参数透传和临时属性清理。

验证

  • 最终变更绑定到 main@12fa384e3c108b19dd5944965498d9e9b8958221security/fix-001@9982549d4fa586f21d79d1e3e1e3943932873ff9
  • src/app/service/content/utils.test.ts 新增对生成 inject / pre-inject 代码的实际执行测试,通过 new Function(...) 验证生成结果可运行。
  • 运行时测试覆盖:正确上下文、named globals / script name 参数透传、临时属性清理、错误令牌拒绝执行、挂载函数自动删除/保留,以及 pre-inject 的脚本加载事件发送。
  • compileScript 继续覆盖同步、异步、异常传播与错误令牌不执行目标代码等行为。
  • head 9982549d4fa586f21d79d1e3e1e3943932873ff9 的 License Compliance 状态为 success。

Screenshots / 截图

N/A — 本 PR 仅调整 userscript 执行包装器、构建常量与相关测试,无 UI 变更。

@cyfung1031 cyfung1031 changed the title 🔒 为用户脚本执行增加完整性校验并避免页面调用 # 🔒 加固用户脚本执行入口:加入构建期调用令牌并调整上下文绑定 Sep 9, 2026
@cyfung1031 cyfung1031 changed the title # 🔒 加固用户脚本执行入口:加入构建期调用令牌并调整上下文绑定 🔒 为用户脚本执行入口加入构建期调用令牌并显式传递上下文 Sep 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant