CSP: Content-Security-Policy详解
前言
跨域脚本攻击(XSS)是最常见、危害最大的网页安全漏洞。
为了防止它,要采取很多编程措施(比如大多数人都知道的转义、过滤HTML)。很多人提出,能不能根本上解决问题,即浏览器自动禁止外部注入恶意脚本?
这就是"内容安全策略"(Content Security Policy
,缩写 CSP)的由来。
两种方法可以启用 CSP:
- 设置 HTTP 的
Content-Security-Policy
头部字段 - 设置网页的<meta>标签。
网上的资料都有讲到它们怎么使用,但是很少有代码演示,不敲一遍就不够理解,下面我会直接上些例子。
(1)使用HTTP的 Content-Security-Policy
头部
在服务器端使用 HTTP的 Content-Security-Policy
头部来指定你的策略,像这样:
Content-Security-Policy: policy
policy参数是一个包含了各种描述CSP策略指令的字符串。
例1 禁止内联js、css
// index.html
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<script type="text/javascript">
console.log('inline js.');
</script>
</body>
</html>
// index.js
const http = require('http');
const fs = require('fs');
http.createServer((req, res) => {
const html = fs.readFileSync('index.html', 'utf8');
res.writeHead(200, {
'Content-Type': 'text-html',
'Content-Security-Policy': 'default-src http: https:'
});
res.end(html);
}).listen(9000);
console.log('server listening on 9000');
上面代码使用原生nodejs起了个服务,然后设置响应头部
'Content-Security-Policy': 'default-src http: https:'
表示只能通过外联的方式来引用js和css,如果使用内联的将报错:
<style type="text/css">
* { background-color: red; }
</style>
例2
只能在指定的域下加载文件,这里表示只能从同域下加载,斜杠为转义符:
'Content-Security-Policy': 'default-src \'self\''
<script type="text/javascript" src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
打开控制台也可以看到请求在浏览器就已经被限制了:
如果要允许请求到这个域,添加进策略即可:
'Content-Security-Policy': 'default-src \'self\' https://cdn.bootcss.com/'
例3
上面的策略是无法限制form表单的提交的,如下列表单,点击后直接跳到了百度页面:
<form action="https://baidu.com">
<button>click me</button>
</form>
这时候就要设置form-action
策略:
'Content-Security-Policy': 'default-src \'self\' https://cdn.bootcss.com/; form-action \'self\''
例4
在例子1中,设置了default-src
的限制,这时img的src也会受到限制。
<img src="https://www.baidu.com/img/baidu_jgylogo3.gif">
default-src
设置的是全局,如果我只想限制js的请求,可以将default-src
改为script-src
(2) 启用违例报告
默认情况下,违规报告并不会发送。为启用发送违规报告,你需要指定 report-uri
策略指令,并提供至少一个URI地址去递交报告:
'Content-Security-Policy': 'script-src \'self\'; report-uri /report'
这里的报告我们可以直接在浏览器看到,它会自动发送一个请求出去:
如果我只想收集报告,但是不真正的去限制请求,那怎么办?除了Content-Security-Policy
,还有一个Content-Security-Policy-Report-Only
字段,表示不执行限制选项,只是记录违反限制的行为。将头部改为这个即可。
(3)使用meta标签
以上规则可以在浏览器端设置,如:
<meta http-equiv="Content-Security-Policy" content="form-action 'self';">
效果是一样的!现在终于理解了meta标签 http-equiv
和 content
属性的意思了,TT。。。
但与服务器端设置有点不同的是,meta无法使用report,这样只能在服务器端设置了:
参考
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CSP
http://www.ruanyifeng.com/blog/2016/09/csp.html