You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在head与body脚本间安全通信?防止第三方脚本窃取数据

客户端安全通信方案(绕过第三方脚本拦截)

针对你这种head脚本与body应用脚本被第三方脚本隔开的场景,以下是几种无需服务器端支持、且能有效防止第三方脚本窃取数据的方案:

方案1:预共享密钥加密传输(最安全)

利用Web Crypto API的对称加密算法,将敏感数据加密后存在全局,body脚本用预共享的密钥解密。第三方即使拿到加密数据,没有密钥也无法破解。

实现步骤:

  1. 预共享密钥:在head脚本和body应用脚本中硬编码同一个AES密钥(建议用Base64编码混淆,避免明文暴露)。
  2. head脚本加密数据:
    // head 脚本
    (async function() {
      // 预共享的AES密钥(Base64编码,需自行生成)
      const keyStr = 'YOUR_BASE64_ENCODED_AES_KEY';
      const sharedKey = await crypto.subtle.importKey(
        'raw',
        Uint8Array.from(atob(keyStr), c => c.charCodeAt(0)),
        { name: 'AES-GCM' },
        false,
        ['encrypt']
      );
    
      // 你的敏感数据
      const secretData = { userId: 123, token: 'xxx' };
      const encodedData = new TextEncoder().encode(JSON.stringify(secretData));
      const iv = crypto.getRandomValues(new Uint8Array(12)); // AES-GCM要求12字节IV
      const encryptedData = await crypto.subtle.encrypt(
        { name: 'AES-GCM', iv },
        sharedKey,
        encodedData
      );
    
      // 将加密数据和IV存为不可枚举的全局属性(避免被常规遍历发现)
      const storageKey = Math.random().toString(36).slice(2);
      Object.defineProperty(window, storageKey, {
        value: { encrypted: encryptedData, iv },
        enumerable: false,
        configurable: true
      });
    
      // 把存储密钥加密后存在固定全局变量(供body脚本获取)
      const encodedStorageKey = new TextEncoder().encode(storageKey);
      const keyIv = crypto.getRandomValues(new Uint8Array(12));
      const encryptedStorageKey = await crypto.subtle.encrypt(
        { name: 'AES-GCM', iv: keyIv },
        sharedKey,
        encodedStorageKey
      );
      window.__encryptedStorageKey = { data: encryptedStorageKey, iv: keyIv };
    })();
    
  3. body应用脚本解密数据:
    // body 应用脚本
    (async function() {
      const keyStr = 'YOUR_BASE64_ENCODED_AES_KEY'; // 和head脚本一致的密钥
      const sharedKey = await crypto.subtle.importKey(
        'raw',
        Uint8Array.from(atob(keyStr), c => c.charCodeAt(0)),
        { name: 'AES-GCM' },
        false,
        ['decrypt']
      );
    
      // 解密存储密钥
      const { data: encryptedStorageKey, iv: keyIv } = window.__encryptedStorageKey;
      const decodedStorageKey = await crypto.subtle.decrypt(
        { name: 'AES-GCM', iv: keyIv },
        sharedKey,
        encryptedStorageKey
      );
      const storageKey = new TextDecoder().decode(decodedStorageKey);
    
      // 获取加密数据并解密
      const { encrypted, iv } = window[storageKey];
      const decodedData = await crypto.subtle.decrypt(
        { name: 'AES-GCM', iv },
        sharedKey,
        encrypted
      );
      const secretData = JSON.parse(new TextDecoder().decode(decodedData));
    
      // 清理全局残留数据
      delete window[storageKey];
      delete window.__encryptedStorageKey;
    
      // 处理你的数据
      console.log(secretData);
    })();
    

方案2:一次性限时访问函数(轻量)

如果不需要强加密,可通过限时、一次性的全局函数传递数据,降低第三方脚本窃取的概率。

实现步骤:

  1. head脚本定义访问函数:
    // head 脚本
    const secretData = { userId: 123, token: 'xxx' };
    const expireTime = Date.now() + 5000; // 5秒后过期
    let isCalled = false;
    
    window.__fetchSecretData = function() {
      if (!isCalled && Date.now() < expireTime) {
        isCalled = true;
        delete window.__fetchSecretData; // 调用后立即删除函数
        return secretData;
      }
      return null;
    };
    
  2. body应用脚本调用函数:
    // body 应用脚本
    const secretData = window.__fetchSecretData();
    if (secretData) {
      // 处理数据
      console.log(secretData);
    }
    

注意:此方案依赖body脚本快速加载执行,若第三方脚本提前调用函数会导致数据泄露,适合对安全性要求不极高的场景。

方案3:Closed Shadow DOM存储(隔离性强)

利用Closed模式的Shadow DOM存储数据,外部脚本无法直接访问Shadow Root,仅head脚本可提供访问入口。

实现步骤:

  1. head脚本创建Shadow DOM存储数据:
    // head 脚本
    const secretData = { userId: 123, token: 'xxx' };
    const shadowHost = document.createElement('div');
    shadowHost.style.display = 'none';
    document.head.appendChild(shadowHost);
    // Closed模式:外部脚本无法获取shadowRoot
    const shadowRoot = shadowHost.attachShadow({ mode: 'closed' });
    
    // 将数据存在Shadow DOM内的元素上
    const dataEl = document.createElement('span');
    dataEl.dataset.secret = JSON.stringify(secretData);
    shadowRoot.appendChild(dataEl);
    
    // 定义一次性访问函数
    let isCalled = false;
    window.__getSecret = function() {
      if (!isCalled) {
        isCalled = true;
        delete window.__getSecret;
        return JSON.parse(dataEl.dataset.secret);
      }
      return null;
    };
    
  2. body应用脚本调用函数:
    // body 应用脚本
    const secretData = window.__getSecret();
    if (secretData) {
      // 处理数据
      console.log(secretData);
    }
    

优势:Shadow DOM的Closed模式天然隔离外部脚本,即使第三方脚本遍历DOM也无法访问内部数据,仅能通过你提供的函数获取。


内容的提问来源于stack exchange,提问作者Yossi Rubin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 14:35:55