使 Angular 使用限制性内容安全策略 (CSP)
Make Angular working with restrictive Content Security Policy (CSP)
我无法使基础 Angular2(最终)应用程序与以下限制性 CSP 一起工作。
default-src 'none';
script-src 'self';
style-src 'self';
font-src 'self';
img-src 'self' data:;
connect-src 'self'
lang.js and two in zone.js 中有一个 unsafe-eval 错误。您能提供解决方案吗?
使用 Angular CLI 重现的步骤
我创建了一个 GitHub repository。您也可以按照以下说明进行操作。
将最后一个 Angular CLI 与 Webpack 6.0.8 一起使用,并按照以下说明创建新的应用程序。
ng new csp-test
在 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'">
然后提供应用程序。
ng serve
访问 http://localhost:4200/,由于脚本被 CSP 阻止,页面无法加载。
错误
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'".
附上源代码。
335: return new (Function.bind.apply(Function, [void 0].concat(fnArgNames.concat(fnBody))))().apply(void 0, fnArgValues);
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'".(…)
附上源代码。
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);
使用离线模板编译器应该可以解决这个问题。
http://www.syntaxsuccess.com/viewarticle/offline-compilation-in-angular-2.0
https://github.com/angular/angular/issues/1744
使用提前编译解决了这个问题。以下命令可用于构建使用限制性 CSP 的应用程序。
ng build --prod
要在本地测试它,您可以使用
ng serve --prod
为@angular/cli>=8.2
编辑的答案
从this Github thread开始,可以使用angular.json
中的index
属性来控制应用程序HTML索引的生成:
build: {
...
"configurations": {
"production": {
"index": {
"input": "src/index.production.html",
"output": "index.html"
},
...
}
}
}
原回答
我找到了一种在我的生产环境中使用限制性 CSP 同时仍然能够使用 JTI 编译器进行开发的方法。
- 添加第二个文件:
index.production.html
到 src
文件夹。
- 将
index.html
的内容复制到该文件,并添加限制性 CSP header。
<meta http-equiv="Content-Security-Policy"
content="default-src 'none';
frame-src 'self';
script-src 'self';
style-src 'self' 'unsafe-inline';
font-src 'self';
img-src 'self' data:;
connect-src 'self'">
- 然后,将以下内容添加到您的
angular.json
中:
build: {
...
"configurations": {
"production": {
"fileReplacements": [
{
"replace": "src/index.html",
"with": "src/index.production.html"
}
],
...
}
}
}
这确保当您 运行 生产构建时,它将使用 index.production.html
和限制性 CSP,并且当您 运行 在本地安装它时,您可以使用 JTI 编译器。
这个问题发生在我身上 Angular 9 部署在 WildFly Server 上。该错误在 WildFly Server 配置中,在 response-header 中设置在 standalone.xml
中,它不在 index.html和我想的一样
standalone.xml
:
<filters>
<response-header name="server-header" header-name="Server" header-value="JBoss-EAP/7"/>
<response-header name="x-powered-by-header" header-name="X-Powered-By" header-value="Undertow/1"/>
>>> Here >>> <response-header name="Content-Security-Policy" header-name="Content-Security-Policy" header-value="default-src 'self'; style-src 'self' 'unsafe-inline'"/>
<response-header name="x-frame-options" header-name="X-Frame-Options" header-value="SAMEORIGIN"/>
<response-header name="x-xss-protection" header-name="X-XSS-Protection" header-value="1; mode=block"/>
<response-header name="x-content-type-options" header-name="X-Content-Type-Options" header-value="nosniff"/>
<response-header name="strict-transport-security" header-name="Strict-Transport-Security" header-value="max-age=31536000; includeSubDomains;"/>
<response-header name="my-custom-header" header-name="my-custom-header" header-value="my-custom-value"/>
</filters>
注意:重启WildFly服务器:
./jboss-cli.sh --connect command=:reload
jboss-cli
位于 WildFly Server 的 bin
文件夹中:
请注意,我从 Angular 10 个文档中获得了此信息,此处:https://angular.io/guide/security
我在服务器响应中添加 header 时解决了这个问题。
Content-Security-Policy: trusted-types angular; require-trusted-types-for 'script';
我无法使基础 Angular2(最终)应用程序与以下限制性 CSP 一起工作。
default-src 'none';
script-src 'self';
style-src 'self';
font-src 'self';
img-src 'self' data:;
connect-src 'self'
lang.js and two in zone.js 中有一个 unsafe-eval 错误。您能提供解决方案吗?
使用 Angular CLI 重现的步骤
我创建了一个 GitHub repository。您也可以按照以下说明进行操作。
将最后一个 Angular CLI 与 Webpack 6.0.8 一起使用,并按照以下说明创建新的应用程序。
ng new csp-test
在 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'">
然后提供应用程序。
ng serve
访问 http://localhost:4200/,由于脚本被 CSP 阻止,页面无法加载。
错误
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'".
附上源代码。
335: return new (Function.bind.apply(Function, [void 0].concat(fnArgNames.concat(fnBody))))().apply(void 0, fnArgValues);
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'".(…)
附上源代码。
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);
使用离线模板编译器应该可以解决这个问题。
http://www.syntaxsuccess.com/viewarticle/offline-compilation-in-angular-2.0 https://github.com/angular/angular/issues/1744
使用提前编译解决了这个问题。以下命令可用于构建使用限制性 CSP 的应用程序。
ng build --prod
要在本地测试它,您可以使用
ng serve --prod
为@angular/cli>=8.2
编辑的答案从this Github thread开始,可以使用angular.json
中的index
属性来控制应用程序HTML索引的生成:
build: {
...
"configurations": {
"production": {
"index": {
"input": "src/index.production.html",
"output": "index.html"
},
...
}
}
}
原回答
我找到了一种在我的生产环境中使用限制性 CSP 同时仍然能够使用 JTI 编译器进行开发的方法。
- 添加第二个文件:
index.production.html
到src
文件夹。 - 将
index.html
的内容复制到该文件,并添加限制性 CSP header。
<meta http-equiv="Content-Security-Policy"
content="default-src 'none';
frame-src 'self';
script-src 'self';
style-src 'self' 'unsafe-inline';
font-src 'self';
img-src 'self' data:;
connect-src 'self'">
- 然后,将以下内容添加到您的
angular.json
中:
build: {
...
"configurations": {
"production": {
"fileReplacements": [
{
"replace": "src/index.html",
"with": "src/index.production.html"
}
],
...
}
}
}
这确保当您 运行 生产构建时,它将使用 index.production.html
和限制性 CSP,并且当您 运行 在本地安装它时,您可以使用 JTI 编译器。
这个问题发生在我身上 Angular 9 部署在 WildFly Server 上。该错误在 WildFly Server 配置中,在 response-header 中设置在 standalone.xml
中,它不在 index.html和我想的一样
standalone.xml
:
<filters>
<response-header name="server-header" header-name="Server" header-value="JBoss-EAP/7"/>
<response-header name="x-powered-by-header" header-name="X-Powered-By" header-value="Undertow/1"/>
>>> Here >>> <response-header name="Content-Security-Policy" header-name="Content-Security-Policy" header-value="default-src 'self'; style-src 'self' 'unsafe-inline'"/>
<response-header name="x-frame-options" header-name="X-Frame-Options" header-value="SAMEORIGIN"/>
<response-header name="x-xss-protection" header-name="X-XSS-Protection" header-value="1; mode=block"/>
<response-header name="x-content-type-options" header-name="X-Content-Type-Options" header-value="nosniff"/>
<response-header name="strict-transport-security" header-name="Strict-Transport-Security" header-value="max-age=31536000; includeSubDomains;"/>
<response-header name="my-custom-header" header-name="my-custom-header" header-value="my-custom-value"/>
</filters>
注意:重启WildFly服务器:
./jboss-cli.sh --connect command=:reload
jboss-cli
位于 WildFly Server 的 bin
文件夹中:
请注意,我从 Angular 10 个文档中获得了此信息,此处:https://angular.io/guide/security
我在服务器响应中添加 header 时解决了这个问题。
Content-Security-Policy: trusted-types angular; require-trusted-types-for 'script';