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尽量写在最前面,保证能够对所有资源请求进行约束。
指令 | 说明 | 示例 |
---|---|---|
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>等标签的加载策略 | |
media-src | 定义<audio> <video>等多媒体html标签资源加载策略 | |
frame-src | 【已废弃】定义iframe标签资源加载策略(新指令:child-src) | |
sandbox | 对请求的资源启用sandbox,类似于iframe中的sandbox功能 | allow-scripts |
report-uri | 定义上报地址。当有资源被拦截的时候,浏览器带着被拦截的资源信息请求这个uri。(只在响应头中定义才能生效) | https://csp.test.com/report |
child-src | 定义子窗口(iframe、弹窗等)的加载策略 | 'self' *.test.com |
form-action | 定义表单提交的源规则 | |
frame-ancestors | 定义当前页面可以被哪些页面使用ifram、object进行加载 | |
plugin-types | 定义页面允许加载哪些插件 |
指令 | 说明 | 示例 |
---|---|---|
* | 所有内容都正常加载 | 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规则的部署。
整理资源地址
web页面中,浏览器有提供performance.getEntries()接口,用于获取网页加载的资源信息,其中initiatorType(资源类型)属性可以知道资源属于哪个指令,name(资源地址)可以定义指令值有哪些。
为了简便,下面将只定义default-src这一个指令,所有资源加载检测都直接走default-src定义的规则。
const entries = window.performance.getEntries()
const names = entries.map(info => info.name);
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(' ');
参考
- Content Security Policy 介绍 | JerryQu 的小站 (imququ.com)
- Content Security Policy 入门教程 - 阮一峰的网络日志 (ruanyifeng.com)
- Content Security Policy Level 2 介绍 | JerryQu 的小站 (imququ.com)
- Content Security Policy (CSP) - HTTP | MDN (mozilla.org)
- performance.getEntries() - Web APIs | MDN (mozilla.org)
- CSP: connect-src (CSP) - HTTP 中文开发手册 - 开发者手册 - 腾讯云开发者社区-腾讯云 (tencent.com)
- HTTP 响应头Content-Security-Policy_istan1ey的博客-CSDN博客
- Content Security Policy_小段777的博客-CSDN博客_content_security_policy
- 前端安全配置之Content-Security-Policy(csp) - 紫日残月 - 博客园 (cnblogs.com)
- Content-Security-Policy设置_weixin_45923962的博客-CSDN博客_content-security-policy 设置