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()