对于想了解Webpack开发服务器ReactContentSecurityPolicy错误的读者,本文将是一篇不可错过的文章,我们将详细介绍webpack起服务,并且为您提供关于ApacheTomca
对于想了解Webpack开发服务器React Content Security Policy错误的读者,本文将是一篇不可错过的文章,我们将详细介绍webpack起服务,并且为您提供关于Apache Tomcat 8.5.51是否支持content-security-policy标头、Content Security Policy、Content Security Policy (CSP) 中的 frame-ancestors ''self'' 指令介绍、Content Security Policy (CSP) 介绍的有价值信息。
本文目录一览:- Webpack开发服务器React Content Security Policy错误(webpack起服务)
- Apache Tomcat 8.5.51是否支持content-security-policy标头
- Content Security Policy
- Content Security Policy (CSP) 中的 frame-ancestors ''self'' 指令介绍
- Content Security Policy (CSP) 介绍
Webpack开发服务器React Content Security Policy错误(webpack起服务)
我的单页应用程序在webpack-dev-
server上运行。我可以在上加载和重新加载我的进入路线,localhost:8080
并且每次都可以使用。但是我localhost:8080/accounts/login
只能通过应用程序内的链接加载localhost:8080/accounts/login
,即每当我从浏览器刷新按钮重新加载时,我都会
Cannot GET /accounts/login/
作为服务器响应,在控制台上我得到
内容安全策略:页面的设置禁止自行加载资源(“ default-src http://
localhost:8080 ”)。来源:;(function
installGlobalHook(window){....
这是我在单页应用程序的index.html上的CSP标头
<meta http-equiv="Content-Security-Policy" content="default-src * ''self'' ''unsafe-inline'' ''unsafe-eval''">
我也没有使用任何devtool
对我的webpack.config.json
。我想念什么。
答案1
小编典典如果在项目中使用Webpack,请在Webpack配置文件中添加output.publicPath =''/''
和devServer.historyApiFallback = true
。
Apache Tomcat 8.5.51是否支持content-security-policy标头
如何解决Apache Tomcat 8.5.51是否支持content-security-policy标头?
我已经按照下面的链接进行操作,但是它抛出错误“找不到HTTP 404”
configuring Content-Security-Policy in tomcat
我错过了什么吗?
谢谢
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)
Content Security Policy
Content Security Policy(内容安全策略,简称csp)用于检测并阻止网页加载非法资源的安全策略,可以减轻xss攻击带来的危害和数据注入等攻击。本文讲述的内容主要有如何使用csp和业务接入csp流程这两部分。
简介
csp主要工作是定义一套页面资源加载白名单规则,浏览器使用csp规则去匹配所有资源,禁止加载不符合规则的资源,同时将非法资源请求进行上报。
csp作用:减轻网页被xss攻击后所受到的危害。实际上csp是在xss攻击发生后才起作用,阻止请求注入的非法资源,csp并不是直接阻止xss攻击的发生。
使用方式
csp主要有两种使用方式,分别是设置响应头Content-Security-Policy
和使用meta
标签。
响应头
在网页html请求的响应头中进行定义,定义方式:
Content-Security-Policy: 指令1 指令值1 指令值2; 指令2 指令值1;
例子:
Content-Security-Policy: srcipt-src ''self'' *.test.com''; img-src: https: data:;
后面会重点讲解csp中具体存在哪些指令和指令值,可以在定义规则中看到具体的介绍。
meta
在网页html文件中进行定义,定义方式:
<meta
http-equiv="Content-Security-Policy"
content="指令1 指令值1 指令值2; 指令2 指令值1;"
>
例子:
<html>
<head>
<meta
http-equiv="Content-Security-Policy"
content="srcipt-src ''self'' *.test.com''; img-src: https: data:;"
>
</head>
<body>...</body>
</html>
注意:由于html文档是从上至下进行解析,因此,meta尽量写在最前面,保证能够对所有资源请求进行约束。
效果
csp规则匹配到的资源都能够正常请求,一旦有非法资源请求,浏览器就会立即阻止,阻止的效果如下
定义规则
csp规则内容主要由指令和指令值这两部分构成,指令用于定义资源类型,指令值用于定义资源请求地址规则。
例子:
Content-Security-Policy: srcipt-src ''self'' *.test.com'';
上面csp规则中,script-src
是脚本资源加载指令,''self''
和*.test.com
是指令值,当加载js脚本的时候,只有满足指令值定义的规则才能正常加载。
指令
指令 | 说明 | 示例 |
---|---|---|
default-src | 定义所有类型资源默认加载策略,当下面这些指令未被定义的时候,浏览器会使用default-src 定义的规则进行校验 | ''self'' *.test.com |
script-src | 定义JavaScript资源加载策略 | ''self'' js.test.com |
style-src | 定义样式文件的加载策略 | ''self'' css.test.com |
img-src | 定义图片文件的加载策略 | ''self'' img.test.com |
font-src | 定义字体文件的加载策略 | ''self'' font.test.com |
connect-src | 定义XHR、WebSocket等请求的加载策略,当请求不符合定义的规则时,浏览器会模拟一个响应状态码为400的响应 | ''self'' |
object-src | 定义<object> <embed> <applet> 等标签的加载策略 | ''self'' |
media-src | 定义<audio> <video> 等多媒体html标签资源加载策略 | ''self'' |
frame-src | 【已废弃】定义iframe标签资源加载策略(新指令:child-src) | ''self'' |
sandbox | 对请求的资源启用sandbox,类似于iframe中的sandbox功能 | allow-scripts |
report-uri | 定义上报地址。当有资源被拦截的时候,浏览器带着被拦截的资源信息请求这个uri。(只在响应头中定义才能生效) | https://csp.test.com/report |
child-src | 【csp2】定义子窗口(iframe、弹窗等)的加载策略 | ''self'' *.test.com |
form-action | 【csp2】定义表单提交的源规则 | ''self'' |
frame-ancestors | 【csp2】定义当前页面可以被哪些页面使用ifram、object进行加载 | ''self'' |
plugin-types | 【csp2】定义页面允许加载哪些插件 |
指令值
指令值 | 说明 | 示例 |
---|---|---|
* | 所有内容都正常加载 | img-src *; |
''none'' | 不允许加载任何资源 | img-src ''none''; |
''self'' | 允许加载同源资源 | img-src ''self''; |
''unsafe-inline'' | 允许加载inline内容(例如:style、onclick、inline js、inline css等) | srcript-url ''unsafe-inline''; |
''unsafe-eval'' | 允许加载动态js代码(例如:eval() ) | script-src ''unsafe-eval''; |
http: | 允许加载http协议资源 | img-src http:; |
https: | 允许加载https协议资源 | img-src https:; |
data: | 允许使用data协议(css中加载base64图片使用的就是data协议) | img-src data:; |
域名 | 允许加载该域名下所有https协议资源 | img-src test.com; |
路径 | 允许加载该路径下所有https协议资源 | img-src test.com/img/; |
通配符 | *.test.com 允许加载子域名下所有https协议的资源(任意子域名);*://*.test.com:* 这个匹配逻辑原意是任意协议、任意子域名、任意端口,但在实际测试过程中发现这个指令值没有任何作用 | img-src *.test.com; |
实际业务开发
前面我们了解了csp基本用法,接下来讲述下业务接入csp流程。由于浏览器会禁止加载违反csp规则的资源,因此,我们需要对csp进行一系列验证后,才能正式上线,下面将带着大家一步一步的完成业务csp规则的部署。
整理资源地址
<!-- window.performance.getEntries().map(info => info.name).filter(str => !!~str.indexOf('':'')) -->
web页面中,浏览器有提供performance.getEntries()
接口,用于获取网页加载的资源信息,其中initiatorType
(资源类型)属性可以知道资源属于哪个指令,name
(资源地址)可以定义指令值有哪些。
为了简便,下面将只定义default-src
这一个指令,所有资源加载检测都直接走default-src
定义的规则。
const entries = window.performance.getEntries()
const names = entries.map(info => info.name);
生成csp规则
const parseReg = /^(?:([A-Za-z]+):)?(\/{0,3})([0-9.\-A-Za-z]+)(?::(\d+))?(?:\/([^?#]*))?(?:\?([^#]*))?(?:#(.*))?$/;
const httpList = [];
const httpsList = [];
const otherProtocol = [];
// 分离https、http、其他协议资源
names.forEach(str => {
const parse = parseReg.exec(str);
// 实测 *://*.test.com:*并不能匹配test.com任意协议、任意子域名、任意端口,因此这里将http和https分离
if ([''https'', ''http''].includes(parse[1])) {
const domain = parse[3];
const midProduct = domain.split(''.'');
const midProductLen = midProduct.length;
const childDomain = midProductLen > 2 ? `*.${midProduct.slice(midProductLen - 2).join(''.'')}` : domain;
if (parse[1] === ''https'') {
httpsList.push(childDomain);
} else {
httpList.push(`http://${childDomain}`);
}
} else {
otherProtocol.push(parse[1]);
}
});
const domains = new Set(otherProtocol.concat(httpsList).concat(httpList))
const defaultSrc = [...domains].join('' '');
这样我们就能够得到一个比较简单的default-src
指令值,如果项目中还存在inlin的代码或者使用了eval
函数动态执行js代码,就需要在default-src
中配置额外的值,具体应该添加什么内容,大家可以在指令值看到。
本地测试
在谷歌浏览器插件应用,添加CSP Mitigator
插件,然后配置页面地址、csp规则信息。
插件内容配置完成以后,点击start开始测试。进入业务页面,查看控制台有哪些资源不符合csp规则,然后再根据报错将csp规则补全。
如果本地测试,没有出现违背csp规则的资源加载时,就可以考虑将csp规则放到现网进行测试。只是此时放入现网使用的响应头不是Content-Security-Policy
,而是Content-Security-Policy-Report-Only
,下面一个板块将详细介绍现网测试。
现网测试
一般情况下,浏览器会禁止加载违反csp规则的资源,这对于csp准确度要求比较高,如果我们不小心遗漏了某个规则,将会影响到页面正常展示,这无疑会给开发者带来巨大的压力。浏览器为了解决这一问题,提供了Content-Security-Policy-Report-Only
响应头,对于违反csp规则的资源,只进行上报处理,不禁止加载资源,这样我们可以在不影响业务使用的情况下,使用上报的非法资源数据,来逐渐补全csp规则。
资源被阻止后,浏览器上报的内容如下:
如果上报的被阻止数据中存在合法资源,我们就需要将该资源写入规则中,更新后,我们可以将规则写到CSP Mitigator
插件中,然后在页面控制台中使用fetch
函数去请求之前上报的资源地址,如果控制台没有报禁止加载的问题,那说明最新的csp规则是有效的。经过一段时间优化后,csp优化好以后,继续写入Content-Security-Policy-Report-Only
响应头中进行观察。
正式上线
如果确认csp上报的资源只有非法资源了,此时便可以将响应头改成Content-Security-Policy
。当响应头改为Content-Security-Policy
以后,违背csp规则的资源会被禁止加载,同时会进行上报处理。
参考
- Content Security Policy 介绍
- Content Security Policy 入门教程
- Content Security Policy Level 2 介绍
- Content Security Policy (CSP)
- performance.getEntries()
Content Security Policy (CSP) 中的 frame-ancestors ''self'' 指令介绍
Content Security Policy (CSP) 是一种 Web 安全标准,旨在减少和防止网站上的一些特定类型的攻击,例如跨站脚本攻击(XSS)。CSP 允许站点管理员定义允许加载的资源的白名单,限制了浏览器可以执行的操作,从而提高网站的安全性。在 CSP 中,frame-ancestors
是一项用于限制页面能够被嵌入的位置的指令。指令的具体内容是 frame-ancestors ''self''
,意味着只允许页面在相同的源(origin)中被嵌套,而不允许在其他域中嵌套。
现在让我们更深入地了解这个 CSP 指令的含义和应用。
Content Security Policy
CSP 通过在 HTTP 头中添加一系列的策略指令,告知浏览器哪些资源可以加载、哪些行为是允许的,从而减少恶意攻击的可能性。frame-ancestors
是其中一项指令,专门用于控制页面在 <frame>
, <iframe>
, <embed>
, 和 <object>
中的显示情况。
frame-ancestors ''self''
的含义
frame-ancestors
指令定义了一个白名单,指定了哪些页面可以嵌套当前页面。在这个例子中,''self''
表示只有相同源(origin)的页面能够嵌套当前页面,而其他域的页面则被禁止。这种设置有助于防止点击劫持攻击,其中攻击者试图将目标网站嵌套到一个透明的 iframe 中,使用户在不知情的情况下与目标页面进行交互。
举例说明
假设我们有一个在线银行服务,其网址为 https://bank.example.com
。为了确保用户在访问银行服务时不会受到点击劫持攻击,我们可以使用 frame-ancestors ''self''
来设置 CSP 头。
Content-Security-Policy: frame-ancestors ''self'';
这将确保银行服务页面只能被嵌套到相同源的页面中,如 https://bank.example.com/account
只能被嵌套到 https://bank.example.com/home
中,而无法被嵌套到其他域如 https://evil.example.com
。
总结
通过使用 frame-ancestors ''self''
,我们加强了网站的安全性,防止了点击劫持攻击。这种 CSP 设置是一项有力的安全措施,尤其对于处理敏感信息的网站来说至关重要。除了这个例子,CSP 还有许多其他指令和配置,可以根据具体需求来进一步提高 Web 应用程序的安全性。在构建现代 Web 前端应用时,除了精通各种前端框架和渲染技术,理解和正确配置安全策略也是不可忽视的一部分。
Content Security Policy (CSP) 介绍
<table> <tbody> <tr> <td>
<p>当我不经意间在 Twitter 页面 <code>view source</code> 后,发现了惊喜。</p> <div><pre><!<span>DOCTYPE</span> <span>html</span>> <<span>html</span> <span>lang</span>=<span><span>"</span>en<span>"</span></span>> <<span>head</span>> <<span>meta</span> <span>charset</span>=<span><span>"</span>utf-8<span>"</span></span> /> <<span>title</span>>Twitter</<span>title</span>> <<span>style</span>><span></span> <span> <span>body</span> {</span> <span> <span><span>background-color</span></span>: <span>#ffffff</span>;</span> <span> <span><span>font-family</span></span>: <span>sans-serif</span>;</span> <span> }</span> <span> <span>a</span> {</span> <span> <span><span>color</span></span>: <span>#1da1f2</span>;</span> <span> }</span> <span> <span>svg</span> {</span> <span> <span><span>color</span></span>: <span>#1da1f2</span>;</span> <span> <span><span>display</span></span>: <span>block</span>;</span> <span> <span><span>fill</span></span>: <span>currentcolor</span>;</span> <span> <span><span>height</span></span>: <span>21<span>px</span></span>;</span> <span> <span><span>margin</span></span>: <span>13<span>px</span></span> <span>auto</span>;</span> <span> <span><span>width</span></span>: <span>24<span>px</span></span>;</span> <span> }</span> <span> </span><span><</span>/<span>style</span>> </<span>head</span>> <<span>body</span>> <<span>noscript</span>>
<<span><span>center</span></span>>If you’re not redirected soon, please <<span>a</span> <span>href</span>=<span><span>"</span>/<span>"</span></span>>use this link</<span>a</span>>.</<span><span>center</span></span>>
</<span>noscript</span>>
<<span>script</span> <span>nonce</span>=<span><span>"</span>SG0bV9rOanQfzG0ccU8WQw==<span>"</span></span>><span></span>
<span> </span> <span> <span>document</span>.<span>cookie</span> <span>=</span> <span><span>"</span>app_shell_visited=1;path=/;max-age=5<span>"</span></span>;</span> <span> </span> <span> <span>location</span>.<span>replace</span>(<span>location</span>.<span>href</span>.<span>split</span>(<span><span>"</span>#<span>"</span></span>)[<span>0</span>]);</span> <span> </span><span><</span>/<span>script</span>> </<span>body</span>> </<span>html</span>></pre></div>
<p>相比平时看到的其他站点的源码,可以说是很清爽了。没有乱七八糟的标签,功能却一样不少。特别有迷惑性,以为这便是页面所有的源码,但查看 DevTools 的 Source 面板后很容易知道这并不是真实的 HTML 代码。但为何页面源码给出的是如此清爽的版本,这里先不研究。</p> <p>把目光移向 script 标签时,发现一个不认识的 <code>nonce</code> 属性。它以及它后面的神秘字符串成功引起了我的好奇。再去看 Google 首页的源码,也有好些 <code>nonce</code> 的运用。是时候去了解一下这里的 <code>nonce</code> 是什么了。</p> <div><pre><span><span>!</span> <script nonce="SG0bV9rOanQfzG0ccU8WQw=="></span>
document.cookie = "app_shell_visited=1;path=/;max-age=5";
location.replace(location.href.split("#")[0]);
</script></pre></div>
<h3>Content Security Policy (CSP)</h3> <p>要了解 <code>nonce</code>, 先了解 <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP" rel="nofollow">Content-Security-Policy(CSP)</a>。</p> <p>我们都知道浏览器有同源策略(<a href="https://en.wikipedia.org/wiki/Same-origin_policy" rel="nofollow">same-origin policy</a>)的安全限制,即每个站点只允许加载来自和自身同域(origin)的数据,<code>https://a.com</code> 是无法从 <code>https://b.com</code> 加载到资源的。每个站点被严格限制在了自已的孤岛上,自己就是一个沙盒,这样很安全,整个网络不会杂乱无章。主要地,它能解决大部分安全问题。假若没有同源策略,恶意代码能够轻松在浏览器端执行然后获取各种隐私信息:银行帐号,社交数据等。</p> <blockquote> <p>那网站间如何进行数据共享,当然是有办法的,了解下 <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" rel="nofollow">CORS</a>。</p> </blockquote> <p>现实中,问题是同源策略也并不是万无一失,跨域攻击 <a href="https://en.wikipedia.org/wiki/Cross-site_scripting" rel="nofollow">Cross-site scripting (XSS)</a> 便包含五花八门绕开限制的手段,形式上通过向页面注入恶意代码完成信息的窃取或攻击。比如 UGC 类型的站点,因为内容依赖用户创建,这就开了很大一个口子,允许用户输入的内容运行在页面上。当然,因为我们都知道会有注入攻击,所以对用户输入的内容进行防 XSS 过滤也成了标配。</p> <p>Content-Security-Policy 从另一方面给浏览器加了层防护,能极大地减少这种攻击的发生。</p> <h3>原理</h3> <p>CSP 通过告诉浏览器一系列规则,严格规定页面中哪些资源允许有哪些来源, 不在指定范围内的统统拒绝。相比同源策略,CSP 可以说是很严格了。</p> <p>其实施有两种途径:</p> <ul> <li>服务器添加 <code>Content-Security-Policy</code> 响应头来指定规则</li> <li>HTML 中添加 <code><meta></code> 标签来指定 <code>Content-Security-Policy</code> 规则</li> </ul> <p><a target="_blank" rel="noopener noreferrer" href="https://user-images.githubusercontent.com/3783096/44004494-f3c9bdf2-9e95-11e8-8793-e2966d79ecae.png"><img src="https://user-images.githubusercontent.com/3783096/44004494-f3c9bdf2-9e95-11e8-8793-e2966d79ecae.png" alt="mobile.twitter.com header 中的 CSP 规则"></a><br> <em>mobile.twitter.com header 中的 CSP 规则</em></p> <p>为了测试方便,以下示例均使用 <code><meta></code> 标签来开启 CSP 规则。但 <code><meta></code> 中有些指令是不能使用的,后面会了解到。只有响应头中才能使用全部的限制指令。</p> <h4>一个简单示例</h4> <p>创建一个 HTML 文件放入以下内容:</p> <p><em>csp_test.html</em></p> <div><pre><!<span>DOCTYPE</span> <span>html</span>> <<span>html</span> <span>lang</span>=<span><span>"</span>en<span>"</span></span>> <<span>head</span>> <<span>meta</span> <span>http-equiv</span>=<span><span>"</span>Content-Security-Policy<span>"</span></span> <span>content</span>=<span><span>"</span>script-src ''self'' https://unpkg.com<span>"</span></span>> <<span>title</span>>CSP Test</<span>title</span>> </<span>head</span>> <<span>body</span>> <<span>script</span> <span>src</span>=<span><span>"</span>https://unpkg.com/react@16/umd/react.development.js<span>"</span></span>><span><</span>/<span>script</span>> </<span>body</span>> </<span>html</span>></pre></div> <p>在该测试文件所在目录开启一个本地 server 以访问,这里使用 Python 自带的 server:</p> <div><pre>$ python -m SimpleHTTPServer 8000</pre></div> <p>然后访问 localhost:8000 以观察结果:</p> <p><a target="_blank" rel="noopener noreferrer" href="https://user-images.githubusercontent.com/3783096/44004498-fdd37004-9e95-11e8-895d-53797ae105c1.png"><img src="https://user-images.githubusercontent.com/3783096/44004498-fdd37004-9e95-11e8-895d-53797ae105c1.png" alt="符合 CSP 规则情况下的正常访问"></a><br> <em>符合 CSP 规则情况下的正常访问</em></p> <p>然后我们将 <code>Content-Security-Policy</code> 改成不允许任何资源再试一下:</p> <p><em>csp_test.html</em></p> <div><pre><!DOCTYPE html> <html lang="en"> <head> <span><span>-</span> <meta http-equiv="Content-Security-Policy" content="script-src ''self'' https://unpkg.com"></span> <span><span>+</span> <meta http-equiv="Content-Security-Policy" content="script-src ‘none’></span> <title>CSP Test</title> </head> <body> <script src="https://unpkg.com/react@16/umd/react.development.js"></script> </body> </html></pre></div> <p><a target="_blank" rel="noopener noreferrer" href="https://user-images.githubusercontent.com/3783096/44004501-0fac3a18-9e96-11e8-98bf-01e77f4a5e6a.png"><img src="https://user-images.githubusercontent.com/3783096/44004501-0fac3a18-9e96-11e8-98bf-01e77f4a5e6a.png" alt="触发 CSP 规则资源被 block 的情况"></a><br> <em>触发 CSP 规则资源被 block 的情况</em></p> <p>下面我们来解释这里设置的 CSP 规则及理解为何资源加载失败。</p> <h4>CSP 规则</h4> <p>无论是 header 中还是 <code><meta></code> 标签中指定,其值的格式都是统一的,由一系列 CSP 指令(directive)组合而成。</p> <p>示例:</p> <pre><code>Content-Security-Policy: <policy-directive>; <policy-directive>… </code></pre> <p>这里 directive,即指令,是 CSP 规范中规定用以详细详述某种资源的来源,比如前面示例中使用的 <code>script-src</code>,指定脚本可以有哪些合法来源,<code>img-src</code> 则指定图片,以下是常用指令:</p> <ul> <li><code>base-uri</code> 限制可出现在页面 <code><base></code> 标签中的链接。</li> <li><code>child-src</code> 列出可用于 worker 及以 frame 形式嵌入的链接。 譬如: <code>child-src https://youtube.com</code> 表示只能从 Youtube 嵌入视频资源。</li> <li><code>connect-src</code> 可发起连接的地址 (通过 XHR, WebSockets 或 EventSource)。</li> <li><code>font-src</code> 字体来源。譬如,要使用 Google web fonts 则需要添加 <code>font-src https://themes.googleusercontent.com</code> 规则。</li> <li><code>form-action</code> <code><form></code> 标签可提交的地址。</li> <li><code>frame-ancestors</code> 当前页面可被哪些来源所嵌入(与 <code>child-src</code> 正好相反)。作用于 <code><frame></code>, <code><iframe></code>, <code><embed></code> 及 <code><applet></code>。 该指令不能通过 <code><meta></code> 指定且只对非 HTML文档类型的资源生效。</li> <li><code>frame-src</code> 该指令已在 level 2 中废弃但会在 level 3 中恢复使用。未指定的情况下回退到 <code>tochild-src</code> 指令。</li> <li><code>img-src</code> 指定图片来源。</li> <li><code>media-src</code> 限制音视频资源的来源。</li> <li><code>object-src</code> Flash 及其他插件的来源。</li> <li><code>plugin-types</code> 限制页面中可加载的插件类型。</li> <li><code>report-uri</code> 指定一个可接收 CSP 报告的地址,浏览器会在相应指令不通过时发送报告。不能通过 <code><meta></code> 标签来指定。</li> <li><code>style-src</code> 限制样式文件的来源。</li> <li><code>upgrade-insecure-requests</code> 指导客户端将页面地址重写,HTTP 转 HTTPS。用于站点中有大量旧地址需要重定向的情形。</li> <li><code>worker-src</code> CSP Level 3 中的指令,规定可用于 worker, shared worker, 或 service worker 中的地址。</li> </ul> <blockquote> <p><code>child-src</code> 与 <code>frame-ancestors</code> 看起来比较像。前者规定的是页面中可加载哪些 iframe,后者规定谁可以以 iframe 加载本页。 比如来自不同站点的两个网页 A 与 B,B,B 中有 iframe 加载了 A。那么</p> <ul> <li>A 的 <code>frame-ancestors</code> 需要包含 B</li> <li>B 的 <code>child-src</code> 需要包含 A</li> </ul> </blockquote> <p>默认情况下,这些指令都是最大条件开放的,可以理解为其默认值为 <code>*</code>。比如 <code>img-src</code>,如果不明确指定,则可以从所有地方加载图片资源。</p> <p>还有种特殊的指令 <code>default-src</code>,如果指定了它的值,则相当于改变了这些未指定的指令的默认值。可以理解为,上面 <code>img-src</code> 如果没指定,本来其默认值是 <code>*</code>,可以加载所有来源的图片,但设置 <code>default-src</code> 后,默认值就成了 <code>default-src</code> 指定的值。</p> <p>常见的做法会设置 <code>default-src ‘self’</code>,这样所有资源都被限制在了和页面同域下。如果此时想要加载从 CDN 来的图片,将图片来源单独添加上即可。</p> <pre><code>Content-Security-Policy: default-src ‘self’; img-src https://cdn.example.com </code></pre> <p>现在来看开头那个示例,也许现在就能看明白了。因为页面中需要从 CDN 加载 React 库,所以我们<code><meta></code> 标签指定了如下 CSP 规则:</p> <pre><code>script-src ''self'' https://unpkg.com </code></pre> <p>这里的 <code>self</code> 及后来改成的 <code>none</code> 是预设值,需用引号包裹,否则会当成 URI 来解析。这里的 CSP 规则表示页面中脚本只能从同域及 <code>https://unpkg.com</code> 加载。假如我们把后者去掉,同样会像上图截图那样 React 库会加载失败,同时控制台中会有加载失败的日志及被触发的规则列出来。</p> <p>改成 <code>none</code> 之后表示页面不加载任何脚本,即使自己站点上的脚本都无法被加载执行。这里不妨试一下在 <code>csp_test.html</code> 旁边创建一个脚本文件 <code>test.js</code>:</p> <p><em>test.js</em></p> <pre><code>alert(‘来自 test.js 的问候!’) </code></pre> <p>同时在页面中引用它:</p> <p><em>csp_test.html</em></p> <div><pre><!DOCTYPE html> <html lang="en"> <head> <meta http-equiv="Content-Security-Policy" content="script-src ''none''"> <title>CSP Test</title> </head> <body> <script src="https://unpkg.com/react@16/umd/react.development.js"></script> <span><span>+</span> <script src="./test.js"></script></span> </body> </html></pre></div> <p>页面执行结果:</p> <p><a target="_blank" rel="noopener noreferrer" href="https://user-images.githubusercontent.com/3783096/44004512-262c4df0-9e96-11e8-88e9-df4e08cb98f1.png"><img src="https://user-images.githubusercontent.com/3783096/44004512-262c4df0-9e96-11e8-88e9-df4e08cb98f1.png" alt="script-src none 时页面将不加载任何脚本"></a><br> <em>script-src none 时页面将不加载任何脚本</em></p> <p>是的,哪怕是自己的脚本也无法被加载执行。CSP 就是这样严格和明确,不存在模棱两可的情况。所以在指定来源时,我们需要确认 URI 是否正确。</p> <h3>指令可接受的值</h3> <p>指令后面跟的来源,有两种写法</p> <ul> <li>预设值</li> <li>URI 通配符</li> </ul> <h4>预设值</h4> <p>其中预设值有以下这些:</p> <ul> <li><code>none</code> 不匹配任何东西。</li> <li><code>self</code> 匹配当前域,但不包括子域。比如 <code>example.com</code> 可以,<code>api.example.com</code> 则会匹配失败。</li> <li><code>unsafe-inline</code> 允许内嵌的脚本及样式。是的,没看错,对于页面中内嵌的内容也是有相应限制规则的。</li> <li><code>unsafe-eval</code> 允许通过字符串动态创建的脚本执行,比如 <code>eval</code>,<code>setTimeout</code> 等。</li> </ul> <p>特别地,在 CSP 的严格控制下,页面中内联脚本及样式也会受影响,在没有明确指定的情况下,其不能被浏览器执行。</p> <p>考虑下面的代码:</p> <p><em>csp_test.html</em></p> <div><pre><!<span>DOCTYPE</span> <span>html</span>> <<span>html</span> <span>lang</span>=<span><span>"</span>en<span>"</span></span>> <<span>head</span>> <<span>title</span>>CSP Test</<span>title</span>> <<span>style</span>><span></span> <span> <span>body</span>{</span> <span> <span><span>color</span></span>:<span>red</span>;</span> <span> }</span> <span> </span><span><</span>/<span>style</span>> </<span>head</span>> <<span>body</span>> <<span>h1</span>>Hello, World!</<span>h1</span>> <<span>script</span>><span></span> <span> <span>window</span>.<span>onload</span><span>=</span><span>function</span>(){</span> <span> <span>alert</span>(<span><span>''</span>hi jack!<span>''</span></span>)</span> <span> }</span> <span> </span><span><</span>/<span>script</span>> </<span>body</span>> </<span>html</span>></pre></div> <p><br> <a target="_blank" rel="noopener noreferrer" href="https://user-images.githubusercontent.com/3783096/44004521-427e59bc-9e96-11e8-9608-743f4e3bfefe.png"><img src="https://user-images.githubusercontent.com/3783096/44004521-427e59bc-9e96-11e8-9608-743f4e3bfefe.png" alt="未指定 CSP 的情况"></a><br> <em>未指定 CSP 的情况</em></p> <p>根据 MDN 上的描述,如果站点未指定 CSP 无则,浏览器默认不会开启相应检查,所以上面一切运行正常,只受正常的同域限制 。</p> <blockquote> <p>If the site doesn''t offer the CSP header, browsers likewise use the standard same-origin policy.<br> <em>— 来自 <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP" rel="nofollow"> MDN 关于 Content Security Policy (CSP) 的描述</a></em></p> </blockquote> <p>我们加上 CSP 限制:</p> <p><em>csp_test.html</em></p> <div><pre><!DOCTYPE html> <html lang="en"> <head> <span><span>+</span> <meta http-equiv="Content-Security-Policy" content="default-src ''self''"></span> <title>CSP Test</title> <style> body{ color:red; } </style> </head> <body> <h1>Hello, World!</h1> <script> window.onload=function(){ alert(''hi jack!'') } </script> </body> </html></pre></div> <p>配置站点默认只信息同域的资源,但注意,这个设置并不包含内联的情况,所以结果会如下图。</p> <p><a target="_blank" rel="noopener noreferrer" href="https://user-images.githubusercontent.com/3783096/44004526-54cf1a5c-9e96-11e8-8bca-c980e51a82ae.png"><img src="https://user-images.githubusercontent.com/3783096/44004526-54cf1a5c-9e96-11e8-8bca-c980e51a82ae.png" alt="内联代码被禁止"></a><br> <em>内联代码被禁止</em></p> <p>如何修复它呢。如果我们想要允许页面内的内联脚本或样式,则需要明确地通过 <code>script-src</code> 和 <code>style-src</code> 指出来。</p> <p><em>csp_test.html</em></p> <div><pre><!DOCTYPE html> <html lang="en"> <head> <span><span>!</span> <meta http-equiv="Content-Security-Policy" content="default-src ''self'' ‘unsave-inline’”></span> <title>CSP Test</title> <style> body{ color:red; } </style> </head> <body> <h1>Hello, World!</h1> <script> window.onload=function(){ alert(''hi jack!'') } </script> </body> </html></pre></div> <p>这里 <code>default-src ''self'' ‘unsave-inline’</code> 配置默认可信的来源有这些: 和页面同域的,以及内联的。</p> <p>刷新页面,样式及脚本又可以正常执行了。</p> <p>通常是不建议使用 <code>unsafe-inline</code> 的(同样也不推荐使用 <code>unsafe-eval</code>),因为内联的脚本和样式维护不便,也不利用良好地组织代码。最佳实践是样式抽离到样式文件,脚本放到单独的 js 文件中加载,让 HTML 文件纯粹一点才是好的做法。即使是 <code>onclick=“myHandler”</code> 或 <code>href=“javascript:;”</code> 这种平时常见的写法,也属于内联的脚本,是需要改造的。</p> <p>如果页面中非得用内联的写法,还有种方式。即页面中这些内联的脚本或样式标签,赋值一个加密串,这个加密串由服务器生成,同时这个加密串被添加到页面的响应头里面。</p> <div><pre><<span>script</span> <span>nonce</span>=<span>EDNnf03nceIOfn39fn3e9h3sdfa</span>><span></span> <span> <span><span>//</span> 这里放置内联在 HTML 中的代码</span></span> <span></span><span><</span>/<span>script</span>></pre></div> <p>页面 HTTP 响应头的 <code>Content-Security-Policy</code> 配置中包含相同的加密串:</p> <pre><code>Content-Security-Policy: script-src ''nonce-EDNnf03nceIOfn39fn3e9h3sdfa'' </code></pre> <p>注意这里的 <code>nonce-</code> 前缀。</p> <p>这也就是文章开头看到的方式,到这里明白了。</p> <p><code><style></code> 标签也是类似的处理。</p> <p>这里的加密串一定是随机不可预测的,否则达不到安全效果,且每次页面被访问时重新生成。</p> <p>除了使用 <code>noce</code> 指定加密串,还可以通过混淆的 hash 值来达到目的。这种做法不需要在标签上加 <code>nonce</code> 而是将需要内嵌的代码本身使用加密算法生成 hash 后放入 CSP 指令中作为值使用,这里的加密算法支持 sha256, sha384 和 sha512。此时 CSP 中使用的前缀为相应的算法名。</p> <p>hash 方式的示例:</p> <div><pre><<span>script</span>><span><span>alert</span>(<span><span>''</span>Hello, world.<span>''</span></span>);</span><span><</span>/<span>script</span>></pre></div> <pre><code>Content-Security-Policy: script-src ''sha256-qznLcsROx4GACP2dm0UCKCzCG-HiZ1guq6ZZDob_Tng='' </code></pre> <h3>eval</h3> <p>js 中好些地方是可以以字符串方式动态创建代码并执行,这被认为是不安全的,所以不推荐使用,一般最佳实践里都会提。</p> <ul> <li><code>setTimeout/setInterval</code> 可接收一段字符串作为代码执行。<code>setTimout(‘alert(1)’,1000)</code>。</li> <li><code>eval</code> 。<code>eval(‘alert(1)’)</code>。</li> <li><code>Function</code> 构造函数。 <code>new Function(‘alert(1)’)</code>。</li> </ul> <p>和内联一样,有专门的指令 <code>unsafe-eval</code> 以允许类似代码的执行。但建议的做法是对于 <code>eval</code> 和 <code>Function</code> 构造器,杜绝使用,而 <code>setTimeout/setInterval</code> 可改造为非字符串形式。</p> <div><pre><span>setTimout</span>(<span>function</span>(){ <span>alert</span>(<span>1</span>); }, <span>1000</span>)</pre></div> <h3>URI</h3> <p>除了上面的预设值,还可通过提供完整的 URI 或带通配符 <code>*</code> 的地址来匹配,以指定资源的合法来源。这里 URI 的规则和配置服务器的跨域响应头是一样的,参考 <a href="https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy" rel="nofollow">Same-origin policy</a>。</p> <ul> <li><code>*://*.example.com:*</code> 会匹配所有 <code>example.com</code> 的子域名,但不包括 <code>example.com</code>。</li> <li><code>http://example.com</code> 和 <code>http://www.example.com</code> 是两个不同的 URI。</li> <li><code>http://example.com:80</code> 和 <code>http://example.com</code> 也是是两个不同的 URI,虽然网站默认端口就是 80</li> </ul> <blockquote> <p>根据维基百科 <a href="https://en.wikipedia.org/wiki/Uniform_Resource_Identifier" rel="nofollow">Uniform Resource Identifier 页面</a> 给出的解释,一个完整的 URI 由以下部分组成:<br> <code>URI = scheme:[//authority]path[?query][#fragment]</code></p> <p>其中 <code>authority</code> 又包含:<br> <code>authority = [userinfo@]host[:port]</code></p> <p>所以你可以认为其中某一项不同,那都是两个 URI。了解这点很重要,一如上面列出的第一条例子 <code>*.example.com</code>, 我们很容易先入为主地认为既然已经允许了该域名的所有子域名,那必然 <code>example.com</code> 也是合法的。</p> </blockquote> <p>因为 URI 是进行动态匹配的,所以解释了上面提到的预设值缘何要加引号。因为如果不加引号的话, <code>self</code> 会表示 host 是 <code>self</code> 的资源地址,而不会表示原有的意思。</p> <h4>优先级</h4> <p>CSP 的配置是很灵活的。每条指令可指定多个来源,空格分开。而一条 CSP 规则可由多条指令组成,指令间用分号隔开。各指令间没有顺序的要求,因为每条指令都是各司其职。甚至一次响应中, <code>Content-Security-Policy</code> 响应头都可以重复设置。</p> <p>我们来看这些情形下 CSP 的表现。</p> <ul> <li>对于设置了多次响应头的情况,最严格的规则会生效。比如下面两条响应头中,虽然 第二条中设置 <code>connect-src</code> 允许 <code>http://example.com/</code>,但第一条里面设置了 <code>connect-src</code> 为 <code>none</code>,所以更加严格的 <code>none</code> 会生效。参见 <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy#Multiple_content_security_policies" rel="nofollow">Multiple content security policies</a>。</li> </ul> <pre><code>Content-Security-Policy: default-src ''self'' http://example.com; connect-src ''none''; Content-Security-Policy: connect-src http://example.com/; script-src http://example.com/ </code></pre> <ul> <li>同一指令多次指定,以第一个为准,后续的会被忽略。</li> </ul> <p><em>csp_test.html</em></p> <div><pre><!<span>DOCTYPE</span> <span>html</span>> <<span>html</span> <span>lang</span>=<span><span>"</span>en<span>"</span></span>> <<span>head</span>> <<span>meta</span> <span>http-equiv</span>=<span><span>"</span>Content-Security-Policy<span>"</span></span> <span>content</span>=<span><span>"</span>default-src ''self'';default-src ''unsafe-inline'';<span>"</span></span>> <<span>title</span>>CSP Test</<span>title</span>> <<span>style</span>><span></span> <span> <span>body</span>{</span> <span> <span><span>color</span></span>:<span>red</span>;</span> <span> }</span> <span> </span><span><</span>/<span>style</span>> </<span>head</span>> <<span>body</span>> <<span>h1</span>>Hello, World!</<span>h1</span>> <<span>script</span>><span></span> <span> <span>window</span>.<span>onload</span><span>=</span><span>function</span>(){</span> <span> <span>alert</span>(<span><span>''</span>hi jack!<span>''</span></span>)</span> <span> }</span> <span> </span><span><</span>/<span>script</span>> </<span>body</span>> </<span>html</span>></pre></div> <p><a target="_blank" rel="noopener noreferrer" href="https://user-images.githubusercontent.com/3783096/44004528-6a4a9f5a-9e96-11e8-88b6-6aee3342ed08.png"><img src="https://user-images.githubusercontent.com/3783096/44004528-6a4a9f5a-9e96-11e8-88b6-6aee3342ed08.png" alt="重复配置同一指令时效果展示"></a><br> <em>重复配置同一指令时效果展示</em></p> <p>很智能地, 浏览器不仅会将检测不过的资源及指令打印出来,重复配置时被忽略的指令也会提示出来。</p> <ul> <li>指定 <code>default-src</code> 的情况下,它会充当 <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy#Fetch_directives" rel="nofollow">Fetch 类指令</a> 的默认值。即 <code>default-src</code> 并不对所有指令生效,其他指令默认值仍是 <code>*</code>。</li> </ul> <h3>发送报告</h3> <p>当检测到非法资源时,除了控制台看到的报错信息,也可以让浏览器将日志发送到服务器以供后续分析使用。接收报告的地址可在 <code>Content-Security-Policy</code> 响应头中通过 <code>report-uri</code> 指令来配置。当然,服务端需要编写相应的服务来接收该数据。</p> <pre><code>Content-Security-Policy: default-src ''self''; ...; report-uri /my_amazing_csp_report_parser; </code></pre> <p>服务端拿到的是以 JSON 形式传来的数据。</p> <div><pre>{ <span><span>"</span>csp-report<span>"</span></span><span>:</span> { <span><span>"</span>document-uri<span>"</span></span><span>:</span> <span><span>"</span>http://example.org/page.html<span>"</span></span>, <span><span>"</span>referrer<span>"</span></span><span>:</span> <span><span>"</span>http://evil.example.com/<span>"</span></span>, <span><span>"</span>blocked-uri<span>"</span></span><span>:</span> <span><span>"</span>http://evil.example.com/evil.js<span>"</span></span>, <span><span>"</span>violated-directive<span>"</span></span><span>:</span> <span><span>"</span>script-src ''self'' https://apis.google.com<span>"</span></span>, <span><span>"</span>original-policy<span>"</span></span><span>:</span> <span><span>"</span>script-src ''self'' https://apis.google.com; report-uri http://example.org/my_amazing_csp_report_parser<span>"</span></span> } }</pre></div> <h3>报告模式</h3> <p>CSP 提供了一种报告模式,该模式下资源不会真的被限制加载,只会对检测到的问题进行上报 ,以 JSON 数据的形式发送到 <code>report-uri</code> 指定的地方。</p> <p>通过指定 <code>Content-Security-Policy-Report-Only</code> 而不是 <code>Content-Security-Policy</code>,则开启了报告模式。</p> <pre><code>Content-Security-Policy-Report-Only: default-src ''self''; ...; report-uri /my_amazing_csp_report_parser; </code></pre> <p>当然,你也可以同时指定两种响应头,各自里的规则还会正常执行,不会互相影响。比如:</p> <pre><code>Content-Security-Policy: img-src *; Content-Security-Policy-Report-Only: img-src ‘none’; report-uri http://reportcollector.example.com/collector.cgi </code></pre> <p>这里图片还是会正常加载,但是 <code>img-src ‘none’</code> 也会检测到并且发送报告。</p> <p>报告模式对于测试非常有用。在开启 CSP 之前肯定需要对整站做全面的测试,将发现的问题及时修复后再真正开启,比如上面提到的对内联代码的改造。</p> <h3>推荐的做法</h3> <p>这样的安全措施当然是能尽快启用就尽快。以下是推荐的做法:</p> <ul> <li>先只开启报告模式,看影响范围,修改问题。</li> <li>添加指令时从 default-src ‘none’ 开始,查看报错,逐步添加规则直至满足要求。</li> <li>上线后观察一段时间,稳定后再由报告模式转到强制执行。</li> </ul> <h3>浏览器兼容性</h3> <p>目前发布的<a href="https://www.w3.org/TR/CSP3/" rel="nofollow"> Level 3 规范</a> 中大部分还未被浏览器实现,通过 <a href="https://caniuse.com/#search=CSP" rel="nofollow">Can I Use 的数据</a> 来看,除 IE 外,Level 2 的功能已经得到了很好的支持。这里还有一分来自 W3C 跟踪的各浏览器实现情况的统计:<a href="https://w3c.github.io/webappsec/implementation_reports/CSP2_implementation_report.html" rel="nofollow">Implementation Report for Content Security Policy Level 2</a>。</p> <p>对于浏览器不支持的情况,也不必担心,会回退到同源策略的限制上。</p> <h3>相关资源</h3> <ul> <li><a href="https://security.stackexchange.com/questions/8264/why-is-the-same-origin-policy-so-important" rel="nofollow">Why is the same origin policy so important?</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP" rel="nofollow">Content Security Policy (CSP)</a></li> <li><a href="https://developers.google.com/web/fundamentals/security/csp/" rel="nofollow">Content Security Policy from Web Fundamentals</a></li> <li><a href="https://blog.twitter.com/engineering/en_us/a/2011/improving-browser-security-with-csp.html" rel="nofollow">Improving Browser Security with CSP</a></li> </ul> </td> </tr> </tbody> </table>
关于Webpack开发服务器React Content Security Policy错误和webpack起服务的介绍已经告一段落,感谢您的耐心阅读,如果想了解更多关于Apache Tomcat 8.5.51是否支持content-security-policy标头、Content Security Policy、Content Security Policy (CSP) 中的 frame-ancestors ''self'' 指令介绍、Content Security Policy (CSP) 介绍的相关信息,请在本站寻找。
本文标签: