csp 的条件下对于懒加载的影响

csp 的条件下对于懒加载的影响

本文介绍在开启CSP的条件下,webpack 的懒加载会受到的影响。

Trusted Types

简单的说就是在使用Trusted Types的条件下,对于 DOM 的一些属性的赋值,必须要经过 policy,否则,浏览器会报错。这个安全机制是为了防止 XSS 攻击的注入攻击下沉(injection sink)。例如 html 中的innerhtml, script 的src属性等。得采用如下的方式来进行赋值

// 这些是定义对可能存在风险的代码进行消毒
cosnt mypolicy = trustedTypes.createPolicy('mypolicyName',{
    createHTML:(url)=>url,
    createScript:(script)=>script,
    createScriptURL:(url)=>url
});
const script = document.createElement('script');
script.src = mypolicy.createScriptURL(url);  // 相当于提供一个方式让你对于这些url 进行消毒。

webpack 中对于 dynamic import 会出现代码分割(code split), 当我们懒加载分割出来的 bundle 的时候,会遇到问题。如下是 webpack runtime 中进行动态加载的代码片段

script = document.createElement("script");
script.charset = "utf-8";
script.timeout = 120;
if (__webpack_require__.nc) {
  script.setAttribute("nonce", __webpack_require__.nc);
}
script.setAttribute("data-webpack", dataWebpackPrefix + key);
script.src = url;

也就是说 webpack 是通过在 dom 上创建script标签来加载懒加载的 bundle 的。那么script.src=url这段代码在开启 csp 的情况下是不允许的。所以会记载报错。那么所以的支持懒加载的框架都会遇到这个尴尬的问题

怎么解决这个问题呢?

方法一 hack, 既然script不能用,那加载 bundle,也可以采用 es6 的import()来实现。前提是你的运行环境是 es6.

  • 在你项目的入口文件中 import hack 的代码
// hack.js
/* eslint-disable no-undef */
(() => {
  var inProgress = {};
  if (__webpack_require__.l) {
    __webpack_require__.l = (url, done, key, chunkId) => {
      if (inProgress[url]) {
        inProgress[url].push(done);
        return;
      }

      inProgress[url] = [done];
      import(/*webpackIgnore: true*/ url).then(
        (mod) => {
          var doneFns = inProgress[url];
          delete inProgress[url];
          doneFns &&
            doneFns.forEach((fn) => fn({ type: "timeout", target: null }));
        },
        (err) => {}
      );
    };
  }
})();
- 然后将这个文件导入到你的`index.tsx|ts`的第一行,这里假设hack.js 与index.ts 在共同级目录,注意后缀名
import "./hack.js";
- 最后,修改webpack 中的module>rule, 对于`hack.js`不要进行babel 转码

这个方法本质上是替换掉 webpack runtime 中的懒加载的方式。

方法二, webpack 本身就对于 trustedTypes 进行支持

在 webpack.config.js 中的 output>trustedTypes 中放入你支持的 policy 的名字

output:{
    trustedTypes: {
        policyName: 'mypolicy',
    },
}

然后将这个 policy 加入到你的 html 的 meta 中

<meta
  http-equiv="Content-Security-Policy"
  content="
    default-src 'self'; 
    script-src 'self'; 
    trusted-types myPolicy;
  "
/>

最终 webpack 的 runtime 会生成如下的代码


var policy;
__webpack_require__.tt = () => {
    // Create Trusted Type policy if Trusted Types are available and the policy doesn't exist yet.
    if (policy === undefined) {
        policy = {
        createScriptURL: (url) => (url)
    };
    if (typeof trustedTypes !== "undefined" && trustedTypes.createPolicy) {
        policy = trustedTypes.createPolicy("myPolicy", policy);
    }
return policy;
};


script = document.createElement("script");
script.charset = "utf-8";
script.timeout = 120;
if (__webpack_require__.nc) {
  script.setAttribute("nonce", __webpack_require__.nc);
}
script.setAttribute("data-webpack", dataWebpackPrefix + key);
script.src = __webpack_require__.tt().createScriptURL(url);

总结

推荐方法二,一开始问了 chatgpt,被它给误导了,其实用 google 搜索,第二条就是答案。不能过度依赖 AI.

posted @   kongshu  阅读(4)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
历史上的今天:
2017-01-20 Deploy Note
点击右上角即可分享
微信分享提示