在发布之前混淆浏览器扩展

已发布的扩展是一个任何人都能解包阅读的 zip。混淆后台脚本和内容脚本会改变什么,以及发布前需要确认的商店政策。

任何人都可以解压一个已发布的扩展,并读取其中的全部内容。你是否被允许发布经过混淆的扩展,取决于商店。

已发布的扩展就是一份可下载的源代码副本

已发布的扩展就是一份可下载的源代码副本。商店提供的安装包是一个 zip 文件,解包只需要右键点一下。之后,后台脚本、内容脚本以及任何打包进去的逻辑都只是磁盘上的普通文件。任何人都可以读到其中有意思的部分,把它拿走,再换个名字重新上传一个分支版本。

先确认商店政策

商店政策决定了你到底能不能发布经过混淆的扩展。各个商店的限制不同,而且会变化,审核人员也可能要求你在上传安装包的同时提交可读的或原始的源代码。在发布混淆构建之前,请阅读你所用商店的现行政策,并做好被要求提供源代码归档的准备。

混淆不是让构建通过审核的手段,也不是向审核人员隐瞒扩展行为的手段。如果商店询问代码做了什么,就如实回答。

混淆后的扩展构建会改变什么

在允许发布混淆构建的地方,输出符合平台对它的要求。它在运行时不使用 eval,而扩展的内容安全策略禁止 eval。

每次构建都会取一个新的 seed,产出不同的形态。别人针对你某个版本的安装包制作的分支版本或补丁,不会延续到你发布的下一个版本上。

对打包后的输出运行它

把 CLI 作为构建后的步骤,对你构建好的输出目录运行;如果你的打包工具已经接入了 AfterPack 插件,也可以使用插件:

$ npx afterpack@latest dist/ --preset=hard

只会收集 .js、.mjs 和 .cjs 文件,因此 manifest.json 以及 _locales/ 下的任何内容都会原样通过。对于希望保持原样的内置第三方 SDK,使用 paths.exclude;要处理打包进安装包的 node_modules/ 副本,使用 paths.include。如果某个符号名必须在你自己的各个文件之间保持一致,用 identifiers.reserved 固定它。

在一次运行中构建所有上下文,把后台 service worker 和内容脚本放在一起,这样它们共享同一个种子,两端共同依赖的消息类型也能保持一致。

打 zip 之前检查安装包

构建后打开 Protection Map,确认你打算保护的脚本都已被覆盖。对于要上传的安装包,保持 sourceMap.enabled 关闭,因为 zip 里的一个 map 就相当于直接发布原始文件,源码一览无余。对即将打 zip 的目录运行 afterpack verify,这样保护未生效的构建会在到达商店之前就失败。

对扩展而言它阻止不了什么

每次发布都换一种新形态,会提高让分支版本或补丁持续跟上你扩展的成本,而且你每发布一次,这笔成本就要重新付一次。

它不能阻止任何人阅读、分叉或重新上传安装包,扩展内部的密钥或令牌也不会因为经过编码就变得安全。必须随包发布的 API 密钥该怎么办讲的就是这种情况。

下一步