让Angular使用限制性内容安全策略(CSP)

Nic*_*aux 32 content-security-policy angular-cli angular

我无法使基础Angular2(最终)应用程序与以下限制性CSP一起使用.

default-src 'none';
script-src 'self';
style-src 'self';
font-src 'self';
img-src 'self' data:;
connect-src 'self'
Run Code Online (Sandbox Code Playgroud)

有一个不安全的-EVAL错误lang.js和两个zone.js.你能提供解决方案吗?

步骤使用Angular CLI重现

我创建了一个GitHub存储库.您也可以按照以下说明操作.

将最后一个Angular CLI与webpack 6.0.8一起使用,并使用下面的说明创建新应用程序.

ng new csp-test
Run Code Online (Sandbox Code Playgroud)

在index.html中插入定义以下限制性内容安全策略的元标记.

<meta 
  http-equiv="Content-Security-Policy" 
  content="default-src 'none';script-src 'self';style-src 'self';font-src 'self';img-src 'self' data:;connect-src 'self'">
Run Code Online (Sandbox Code Playgroud)

然后提供申请.

ng serve
Run Code Online (Sandbox Code Playgroud)

访问http:// localhost:4200 /,由于脚本被CSP阻止,因此页面无法加载.

错误

Chrome中出错

lang.js

lang.js:335 Uncaught EvalError: Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src 'self'".
Run Code Online (Sandbox Code Playgroud)

与源代码.

335: return new (Function.bind.apply(Function, [void 0].concat(fnArgNames.concat(fnBody))))().apply(void 0, fnArgValues);
Run Code Online (Sandbox Code Playgroud)

zone.js

zone.js:344 Unhandled Promise rejection: Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src 'self'".
 ; Zone: <root> ; Task: Promise.then ; Value: EvalError: Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src 'self'".

zone.js:346 Error: Uncaught (in promise): EvalError: Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src 'self'".(…)
Run Code Online (Sandbox Code Playgroud)

与源代码.

343: if (rejection) {
344:     console.error('Unhandled Promise rejection:', rejection instanceof Error ? rejection.message : rejection, '; Zone:', e.zone.name, '; Task:', e.task && e.task.source, '; Value:', rejection, rejection instanceof Error ? rejection.stack : undefined);
345: }
346: console.error(e);
Run Code Online (Sandbox Code Playgroud)

Jes*_*sse 17

编辑@angular/cli>=8.2 的答案

这个 Github 线程中,可以使用index属性 inangular.json来控制应用程序 HTML 索引的生成:

build: {
  ...
  "configurations": {
    "production": {
      "index": {
        "input": "src/index.production.html",
         "output": "index.html"
       },
      ...
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

原答案

我找到了一种方法,可以在我的生产环境中使用限制性 CSP,同时仍然能够使用 JTI 编译器进行开发。

  • 添加第二个文件:index.production.htmlsrc文件夹。
  • 将 的内容复制index.html到该文件,并添加限制性 CSP 标头。
build: {
  ...
  "configurations": {
    "production": {
      "index": {
        "input": "src/index.production.html",
         "output": "index.html"
       },
      ...
    }
  }
}
Run Code Online (Sandbox Code Playgroud)
  • 然后,添加到您angular.json的以下内容:
build: {
  ...
  "configurations": {
    "production": {
      "fileReplacements": [
        {
          "replace": "src/index.html",
          "with": "src/index.production.html"
        }
      ],
      ...
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

这确保当您运行生产构建时,它将使用index.production.html具有限制性的 CSP,并且当您在本地运行它时,您可以使用 JTI 编译器。

  • 这是一个很好的解决方案,但不再有效。`fileReplacements` 属性不考虑像 `index.html` 这样的非捆绑文件。更新的解决方案是https://github.com/angular/angular-cli/issues/14599#issuecomment-527131237 (4认同)

Nic*_*aux 5

使用最新的Angular CLI版本(从1.0.0-beta.17开始)已解决了该问题。以下命令可为正在运行的应用程序提供服务,因为它包含提前编译。

ng serve --prod
Run Code Online (Sandbox Code Playgroud)

  • 运行ng serve时:这是一台简单的服务器,可用于在本地测试或调试Angular应用程序。尚未针对安全问题进行审查。**请勿将其用于生产!** (3认同)