安全 – CSP (Content Security Policy)
前言
之前讲过 CSRF。防 Cookie hacking 的。
也介绍过防 XSS 的 HtmlSanitizer。
今天再介绍 CSP。
参考
CSP (Content Security Policy) 介绍
它是游览器其中一种防 hack 机制。除 IE 以外,modern browser 老早就全部支持了,所以可以安心用。
它主要是防 html 里要加载的 resource。
比如 HTML 想加载 JavaScript, Image 等等。
首先游览器会去检查 CSP config,然后验证这些 resource 是否符合 config 要求,如果 ok 才加载,不 ok 就报错,不加载。
此外它还可以防 inline JavaScript 的执行,还有网页被 ifame 嵌套等等。算是满全面的防 hack 机制。
Config CSP
same origin resource
CSP 可以设置在 header,也可以放到 HTML 的 meta 里。
<meta http-equiv="Content-Security-Policy" content="default-src 'self'">
这是一个用 meta 定义 CSP 的例子。所有的 config 都会写到 content 里。分隔符是空格和分号。
用 header 的话,key 是 Content-Security-Policy,value 是 default-src 'self'。
CSP 可以配置不同 src 的条件,比如 script-src 指的是 JavaScript,img-src 指的是图片,而 default-src 指的是所有 src 默认的条件。
上面这句 default-src 'self' 意思是 HTML 里所有要加载的 resource 必须来自于 self / 同域 / same-origin。
<script src="/script.js"></script>
<script src="https://192.168.1.152:44300/script.js"></script>
假设我的 origin 是 http://localhost:5148,上面 /script.js 可以加载,但是 https://192.168.1.152:44300/script.js 就不行,因为它不是 same origin。
运行的结果就是游览器会报错。
wss: 和 https:
除了 https://192.168.1.152:44300/script.js,还有一个 resource 也被拒绝了 wss://localhost:61341,这个是 ASP.NET Core development mode 情况下开启的 websocket,作用是自动刷新 browser。
如果我们想 allow 它,可以这样配置。
<meta http-equiv="Content-Security-Policy" content="default-src 'self' wss:">
加了一个 wss:,我没有声明完整的 origin,只声明了 protocol,所有只要是 websocket 请求,不管什么 origin 都被允许。类似的设置还有 https: 表示只要是 https 安全请求就允许。
inline script
'self' 并不能 bypass inline script。
<script>alert('inline script');</script>
CSP 防御下,inline script 会报错。
unsafe-inline
<meta http-equiv="Content-Security-Policy" content="default-src 'self' wss: 'unsafe-inline'">
添加 unsafe-inline 就可以 bypass inline script 了,但是这个方法是相对不安全的操作,除非我们可以完全信赖 inline script。
更安全的 by pass 方式是通过 sha256。我们把 inline script 拿去 sha256 + base64 得到 hash。
然后这样配置 CSP
<meta http-equiv="Content-Security-Policy" content="default-src 'self' wss: 'sha256-HgfVE1WaRXdD1n+LcUazTiP/FMatVgqvpPh9iAxr2qE='">
只要 inline script 的内容 sha256 后和 CSP 匹配,那么游览器才允许执行代码。
要得到这个 sha256 有很多种方式
2. Chrome 报错的时候会提供 sha256 的 hash,参考上面的 error。
3. 通过 C#
var script = "alert('inline script');";
var sha256Script = SHA256.HashData(Encoding.UTF8.GetBytes(script));
var base64Hash = Convert.ToBase64String(sha256Script);
Console.WriteLine(base64Hash);
third party resource
<meta http-equiv="Content-Security-Policy" content="default-src 'self' wss: https://192.168.1.152:44300">
<meta http-equiv="Content-Security-Policy" content="default-src 'self' wss: https://192.168.1.152:44300/script.js"> <script src="https://192.168.1.152:44300/script.js"></script>
我们可以指定信任的 origin,比如 https://192.168.1.152:44300 表示所有这个 origin 的 resource 都可以加载运行。
如果只是单个 resource 就写完整 URL,https://192.168.1.152:44300/script.js
如果我们不是很信任这个 origin 的 script,我们还可以添加一个 sha256 验证。
<script src="https://192.168.1.152:44300/script.js" integrity="sha256-tZpBEqmrY4CizbfYTAoo3wFhDJOpv6HGhMzwex2TTMs=" crossorigin="anonymous" ></script>
只要 resource 的内容和 hash 不匹配,那就会报错。
best practice
最起码可以 set 一个 https:,确保所有通信是加密的
<meta http-equiv="Content-Security-Policy" content="default-src https:">
‘self’,只相信自己也是一个好习惯。
<meta http-equiv="Content-Security-Policy" content="default-src 'self'">
对你相信的 thrid party 开放
<meta http-equiv="Content-Security-Policy" content="default-src 'self' https://192.168.1.152:44300">
只开放一些 third party resource
<meta http-equiv="Content-Security-Policy" content="default-src 'self' https://192.168.1.152:44300/script.js">
用 sha256 确保 script 是预期中的
<meta http-equiv="Content-Security-Policy" content="default-src 'self' wss: 'sha256-HgfVE1WaRXdD1n+LcUazTiP/FMatVgqvpPh9iAxr2qE='"> <script src="https://192.168.1.152:44300/script.js" integrity="sha256-tZpBEqmrY4CizbfYTAoo3wFhDJOpv6HGhMzwex2TTMs=" crossorigin="anonymous" ></script>
<script>alert('inline script');</script>
nonce
参考:MDN – nonce
nonce 是一个比较弱的防 hack 机制。用上面完整的 CSP 会更理想。
我是看到 Facebook Page Embed generate 出来的 code 有放,所以这里才顺便提一下。
假设我们没有用 sha256,'self' 这些 CSP 来防 hack,并且我们被 XSS 了。hacker 插入了一个 inline script 到我们的页面。
nonce 的防 hack 方式是这样,首先后端需要 generate nonce 随机数。
这里给一个 ASP.NET Core Razor Pages 的例子
public void OnGet()
{
static string GenerateCryptoNonce()
{
var rng = RandomNumberGenerator.Create(); byte[] bytes = new byte[16];
rng.GetBytes(bytes); string nonce = Convert.ToBase64String(bytes); return nonce;
} Nonce = GenerateCryptoNonce(); Response.Headers.Append("Content-Security-Policy", $"default-src 'self' wss: 'nonce-{Nonce}'");
}
nonce 需要用 cryptographically 128 bit (16 bytes) 生成,然后转 base64。
然后把 nonce 放到 CSP config 里,还有每一个 script 中。
<script nonce="@Model.Nonce">
alert('ok')
</script>
游览器在执行 script 之前,会先看它是否有 nonce,并且需要和 response header 中的 CSP nonce 匹配。
如果有匹配就执行,没有就不报错。
hacker 通过 XSS 插入的 script 没办法知道 nonce 随机数,所以最终 hacker script 不会被游览器执行,网页也就安全了。
了解了它的原理,确实,它也没有很安全,所以大家还是按上面 best practice 做会更理想。
frame-ancestors and X-Frame-Options
frame-ancestors 是用来取代 X-Frame-Options 的,它们的作用是声明网页是否允许被其它网页 iframe 嵌入。通常是不允许的啦。
注意:它只可以通过 HTTP header 方式去声明,HTML meta 不可以哦。
我的 Index 想嵌套 About 进来 iframe。如果没有 CSP 这个操作是 ok 的。
现在我们去配置 CSP 阻止它。
在 about 的 response header 加上 CSP frame-ancestors 'none' 完全不允许任何网页嵌入。
效果
只允许同域嵌入
把 'none' 换成 'self' 就可以了。
允许指定的 origin 嵌入
放入指定的 origin 就可以了,可以放多个,分隔符是空格。
defualt-src + frame-ancestors 的写法是
default-src 'self'; frame-ancestors https://192.168.1.152:44300 https://192.168.1.152:4200
分隔符是分号。
总结
CSP 是游览器的一种安全机制。可以用来限制 HTML 加载的 resource (e.g. script, img)。
比如限制 resource 只能是同域,或者指定可信赖的 origin。甚至可以通过 sha256 确保加载的内容是预期的。
另外它还可以防 XSS inline script 还有防网页被其它网页 ifram 嵌入等等。
这个是 Apple 官网返回的 CSP
安全 – CSP (Content Security Policy)的更多相关文章
- CSP(Content Security Policy) 入门教程
参考: http://www.ruanyifeng.com/blog/2016/09/csp.html https://developer.mozilla.org/en-US/docs/Web/HTT ...
- Content Security Policy (CSP) 介绍
当我不经意间在 Twitter 页面 view source 后,发现了惊喜. <!DOCTYPE html> <html lang="en"> <h ...
- 网页安全政策"(Content Security Policy,缩写 CSP)
作者:阿里聚安全链接:https://www.zhihu.com/question/21979782/answer/122682029来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载 ...
- Content Security Policy (CSP)内容安全策略
CSP简介 Content Security Policy(CSP),内容(网页)安全策略,为了缓解潜在的跨站脚本问题(XSS攻击),浏览器的扩展程序系统引入了内容安全策略(CSP)这个概念. CSP ...
- Content Security Policy (CSP)内容安全策略总结
跨域脚本攻击 XSS 是最常见.危害最大的网页安全漏洞. 为了防止它们,要采取很多编程措施,非常麻烦.很多人提出,能不能根本上解决问题,浏览器自动禁止外部注入恶意脚本?这就是"网页安全政策& ...
- Refused to execute inline event handler because it violates the following Content Security Policy directive: "xxx". Either the 'unsafe-inline' keyword, a hash ('sha256-...'), or a nonce ('nonce-...')
/********************************************************************************* * Refused to exec ...
- Content Security Policy的学习理解
以下内容转载自 http://www.cnblogs.com/alisecurity/p/5924023.html 跨域脚本攻击 XSS 是最常见.危害最大的网页安全漏洞. 为了防止它们,要采取很多编 ...
- Content Security Policy减少劫持
Content Security Policy减少劫持 什么是CSP? CSP是由单词 Content Security Policy 的首单词组成,是HTML5带给我们的一套全新主动防御的体系,旨在 ...
- Content Security Policy 入门教程
阮一峰文章:Content Security Policy 入门教程
- Content Security Policy介绍
Content Security Policy https://content-security-policy.com/ The new Content-Security-Policy HTTP re ...
随机推荐
- Cush:从辞职自学编程到被 Apple、PriceTag推荐
名字:Cush 开发者 / 团队:ShaSha 平台:iOS.macOS 请简要介绍下这款产品 也许你听过记账可以帮助省钱,但总是浅尝辄止? 快试试 Cush!它精简了记账中所有复杂繁琐的步骤,简单精 ...
- Go微服务开发指南
在这篇深入探讨Go语言在微服务架构中的应用的文章中,我们介绍了选择Go构建微服务的优势.详细分析了主要的Go微服务框架,并探讨了服务发现与注册和API网关的实现及应用. 关注TechLead,复旦博士 ...
- [oeasy]python0133_[趣味拓展]颜文字_流石兄弟_表情文字_2ch_kaomoji
颜文字 回忆上次内容 上次我们了解unicode 里面有各种字体 甚至还有emoji emoji 本质上也是文字 按照unicode的方式编码 存储时按照utf-8的方式编码 显示时按照系统定义的 ...
- oeasy教您玩转vim - 1 - # 存活下来 🥊
存活下来 更新 apt 源,升级 vim vim 是什么 vim 是类 unix 系统上的一个文本编辑神器,在 Linux 系统环境中也被许多程序员使用,书写程序和文档. 我们本次课程将围绕 Vim ...
- SQL Server 新增函数大全(各版本)
SQL Server 2017 CONCAT_WS ( separator, argument1, argument2 [, argumentN]... ) --采用可变数量的字符串自变量,并将它们串 ...
- TIER 2: Oopsie
TIER 2: Oopsie Web 渗透 此次靶机结合前面知识,非常简单: nmap 扫描,发现 22 和 80 端口开放 服务 80 的 HTTP 服务 之后使用继续 Web 渗透: 使用 Wap ...
- Linux 基于flock命令实现多进程并发读写文件控制
基于flock命令实现多进程并发读写文件控制 需求描述 实际项目中,需要在Linux下通过shell脚本并发读写同一个文件,但是希望同一时刻,只有一个进程可以在读.写目标文件. 解决方案 使用floc ...
- 暑假java自学进度总结03
一.今日所学: 1.标识符命名规则: 必须: 1>由数字,字母,下划线,美元符组成: 2>不能以数字开头: 3>不能是关键字: 4>区分大小写: 建议: 1>命名方法,变 ...
- 2024-07-31:用go语言,给定两个正整数数组arr1和arr2,我们要找到属于arr1的整数x和属于arr2的整数y组成的所有数对(x, y)中,具有最长公共前缀的长度。 公共前缀是指两个数的
2024-07-31:用go语言,给定两个正整数数组arr1和arr2,我们要找到属于arr1的整数x和属于arr2的整数y组成的所有数对(x, y)中,具有最长公共前缀的长度. 公共前缀是指两个数的 ...
- 【Java】MultiThread 多线程 Re02 线程通讯
一.等待与唤醒 /** * 线程通讯问题 * Object wait, notify, notifyAll * Condition await signal signAll * CountDownLa ...