前言
跨域腳本攻擊(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,這樣只能在服務器端設置了:
總結
可以看到,一經設置Content-Security-Policy
,對加載外部腳本限制較為嚴格。這個東西好不好用呢?似乎使用的人不多,目前我知道有知乎和github在用。
參考
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CSP
http://www.ruanyifeng.com/blog/2016/09/csp.html