CSP内容安全策略
关于csp的入门介绍,在 Content Security Policy 入门教程中已经介绍的非常清晰明了了,所以在这边仅仅是做一个试验,用 meta 标签和最常用的 script-src 选项写一个demo
- 使用最基本的
script-src 'self';
限制所有的外部资源,都只能从当前域名加载。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"
http-equiv="Content-Security-Policy"
content="script-src 'self';">
<title>phoeny</title>
</head>
<body>
<p id="test2">使用script马上弹出hi</p>
<p id="test3">使用img马上弹出123</p>
<script>
var dom = document.getElementById('test2')
dom.innerHTML= "<p>我的第二个段落。</p><script>alert('hi')<\/script>"
</script>
<script>
var dom = document.getElementById('test3')
dom.innerHTML= "<img src='x' onerror='alert(123)'/>"
</script>
</body>
</html>
根据我们所想,结果应该是立刻弹出123,但不会弹出 hi,因为HTML5 中指定不执行由 innerHTML
插入的 <script>
,这个话题在 22/10/12 xss攻击中提过。
但实际上它报错了:
报错内容告诉我们,csp 限制了这两个标签的执行,要加上一些配置才可以,所以我们试着将 meta 标签改成
<meta charset="utf-8"
http-equiv="Content-Security-Policy"
content="script-src 'self' 'unsafe-inline' ;">
再次运行,完美契合了我们最初的想法,也就是允许运行了unsafe-inline
不安全的行内脚本。
- 让我们试一试
appendChild
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"
http-equiv="Content-Security-Policy"
content="script-src 'self' 'unsafe-inline';">
<title>phoeny</title>
</head>
<body>
<p id="test">使用append马上弹出xss</p>
<script>
var dom = document.getElementById('test')
var sc = document.createElement('script')
sc.innerHTML=alert('xss')
dom.appendChild(sc)
</script>
</body>
</html>
可以成功弹出 xss
,也就是说用appendChild
可以避开html5对于script
的安全处理。
- 当我试着用 jquery 来实现这一切的时候,结果又看不懂了!
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"
http-equiv="Content-Security-Policy"
content="script-src 'self' 'unsafe-inline'">
<title>phoeny</title>
<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
</head>
<body>
<p id="test0">点我!使用jquery弹出haha</p>
<p id="test1">我会被jquery替换</p>
<script>
$(document).ready(function(){
$("#test0").click(function(){
$("#test1").html("<script>alert('haha')<\/script>")
});
});
</script>
</body>
</html>
首先,它会报错:
这是因为它无法加载
jquery
,我们很快会想到将这个域名加到白名单中,也就是将将 meta 标签改成
<meta charset="utf-8"
http-equiv="Content-Security-Policy"
content="script-src 'self' 'unsafe-inline' https://cdn.staticfile.org">
ok,没有报错啦。
已知,jquery
中是用appendChild
添加script
标签的,所以我们合理猜测,点击之后会弹出haha
。但是,当我们真的点击test0
时,又又又报错了:
这个报错真的是百思不得其解,和 eval
又有什么关系呢,好吧,原来jquery
中的html
方法的实现有些与众不同,jquery
在找到 script
标签的时候,会先将其取出来不运行,推进一个列表中,最后循环这个列表用 eval
再去运行...
所以我们为了让它运行,不得不加一个 unsafe-eval
<meta charset="utf-8"
http-equiv="Content-Security-Policy"
content="script-src 'self' 'unsafe-inline' https://cdn.staticfile.org 'unsafe-eval'">
而且,这只有在低版本的jquery
才会出现,当我们将jquery
的版本换到更高,就和我们预料的结果是一样的。
<script src="https://cdn.staticfile.org/jquery/3.6.1/jquery.min.js"></script>
好啦,这就是在试验 csp 的时候踩得一些坑呀,还真是挺麻烦哒!