返回

安全执行字符串JavaScript:Chrome扩展方案

javascript

Content Script 执行字符串 JavaScript 代码

浏览器扩展常需在页面上执行动态的JavaScript代码。 这项需求,尤其在处理用户提交的自定义脚本时更为常见。 使用像 eval()Function() 构造函数这种直接将字符串转换为代码执行的方式,可能看起来简单直接,但受浏览器安全策略限制,尤其是在 Chrome 扩展 Manifest V3 中,此类方法已被禁用。 本文分析了此问题的原因,并提供了几种安全的替代解决方案,确保在不同页面上的脚本执行都能顺利进行。

挑战:安全策略和代码执行

使用 eval()new Function() 从字符串动态生成 JavaScript 代码时,可能会违反网站的安全策略(CSP)。网站可能设置内容安全策略,限制 eval 以及其他执行动态代码的行为, 从而引发脚本执行失败。 同时, setTimeout(string, 0) 或类似方式利用旧特性来运行字符串代码的方法,并不安全,还会被 CSP 所限制。这种方法的可靠性和兼容性堪忧。

解决方案: chrome.scripting.executeScript

chrome.scripting.executeScript 是 Manifest V3 浏览器扩展中推荐使用的,用于注入和执行 JavaScript 代码的方法。 此方法会先解析给定的代码,确保不会有任何直接使用 eval 的风险,再将其注入到目标页面的上下文环境中。它能够绕过一些 CSP 限制。

代码示例

chrome.scripting.executeScript({
    target: { tabId: tabId },
    function: (codeToExecute) => {
       eval(codeToExecute); // 执行的语句是会被沙箱化的,可以不处理,直接注入
     },
     args: [userCodeString], //用户提供的代码字符串
   });
  • target.tabId: 指定代码注入的目标选项卡 ID。
  • function: 是在目标页面执行的函数。这个函数内部需要利用沙箱环境安全的使用 eval() 执行字符串的代码,也可以替换为使用构造函数或其它的代码运行方法。
  • args: 是传给 function 的参数,在本示例中是用户提交的字符串形式的代码 userCodeString

操作步骤

  1. 确保你的 Manifest V3 扩展有 scriptingactiveTab 权限:
"permissions": [
  "scripting",
  "activeTab"
]
  1. 获取当前激活选项卡的 tabId。可以通过例如 chrome.tabs.query 函数或在其他相关事件的回调函数中取得当前页面的 id
  2. 使用 chrome.scripting.executeScript 并将字符串代码作为参数传入。
  3. (可选)捕获潜在的执行错误,并对错误进行记录或处理。

解决方案: 创建和注入 script 元素

另一种可行的替代方案是动态创建一个 <script> 标签,将用户的代码注入此标签的 textContent 属性,再将这个元素添加到文档中,促使脚本执行。这个方案可以比较干净的处理字符串脚本,避免使用危险操作。

代码示例

chrome.scripting.executeScript({
  target: { tabId: tabId },
  function: (userCodeString) => {
        const script = document.createElement('script');
        script.textContent = userCodeString;
        (document.head || document.documentElement).appendChild(script);
        script.remove(); //脚本执行完毕移除该节点
   },
   args: [userCodeString]
});

操作步骤

  1. 与前一方案一样,确认 scriptingactiveTab 权限已声明。
  2. 获得当前激活选项卡的 tabId
  3. 使用 chrome.scripting.executeScript 将注入脚本的函数注入页面。
  4. 在注入函数中动态构建<script>标签并将用户代码赋予给 textContent属性。
  5. 附加此 <script> 标签到 document.headdocument.documentElement,确保其可以执行。
  6. 执行结束后可以移除创建的标签。

安全性提示

  • 代码审查: 对用户提交的代码执行之前,进行代码审查是一个很好的实践。 这可以提前识别出潜在的安全隐患或恶意代码。 例如检查提交的字符串代码中是否有无限循环之类的代码。
  • 使用严格的权限: 只申请需要的最低权限。 不需要的权限声明只会加大安全漏洞风险。
  • 内容隔离: 注意利用 executeScriptisolated world 参数, 使扩展程序的代码尽可能与其宿主页面隔离,避免意外的代码冲突。

通过合理的使用 chrome.scripting.executeScript API 或者构造 <script> 标签执行代码,可以有效地解决动态执行用户字符串 JavaScript 代码的问题。 在安全方面也要采取积极预防措施,这样才可以构建既强大又安全的扩展程序。