CSP: Content-Security-Policy详解

0.096字数 757阅读 6065

跨域脚本攻击(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
// 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,如果使用内联的将报错:

image.png
    <style type="text/css">
        * { background-color: red; }
    </style>
image.png
例2

只能在指定的域下加载文件,这里表示只能从同域下加载,斜杠为转义符:
'Content-Security-Policy': 'default-src \'self\''

<script type="text/javascript" src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
image.png

打开控制台也可以看到请求在浏览器就已经被限制了:


image.png

如果要允许请求到这个域,添加进策略即可:

'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\''
image.png
例4

在例子1中,设置了default-src的限制,这时img的src也会受到限制。

<img src="https://www.baidu.com/img/baidu_jgylogo3.gif">

image.png

default-src设置的是全局,如果我只想限制js的请求,可以将default-src改为script-src

(2) 启用违例报告

默认情况下,违规报告并不会发送。为启用发送违规报告,你需要指定 report-uri策略指令,并提供至少一个URI地址去递交报告:

'Content-Security-Policy': 'script-src \'self\'; report-uri /report'

这里的报告我们可以直接在浏览器看到,它会自动发送一个请求出去:


image.png

如果我只想收集报告,但是不真正的去限制请求,那怎么办?除了Content-Security-Policy,还有一个Content-Security-Policy-Report-Only字段,表示不执行限制选项,只是记录违反限制的行为。将头部改为这个即可。

(3)使用meta标签

以上规则可以在浏览器端设置,如:

<meta http-equiv="Content-Security-Policy" content="form-action 'self';">

效果是一样的!现在终于理解了meta标签 http-equivcontent 属性的作用了,TT。。。

但与服务器端设置有点不同的是,meta无法使用report,这样只能在服务器端设置了:

image.png
参考

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CSP
http://www.ruanyifeng.com/blog/2016/09/csp.html

推荐阅读更多精彩内容