HTTP Security
HTTP CSP3
目标
- 减少内容注入攻击的风险,包括:
1) 嵌入文档的资源(worker/iframe)
2)内联脚本
3)动态脚本(eval)
4) 内联样式 - 提供能力控制嵌入资源可以使用哪些源(origin)
- 提供一个report机制
Directives
指令相关执行检查的时机:
- Pre-request check
- Post-request check
- Inline check
- Initialization
- Pre-navigation check
- Navigation response check
可以配置的Source List
- 关键字none和self(只匹配当前URL的Origin)
- URL(例如: https://example.com/path/to/f...,特定的文件;https://example.com/,Origin下所有的资源)
- 协议(例如: https:)
- 域名(例如:example.com,*.example.com)
- Nonces (例如:nonce-ch4hvvbHDpv7xCSvXCs3BrNggHdTzxUA,匹配页面上特定的元素例如: <script nonce=“ch4hvvbHDpv7xCSvXCs3BrNggHdTzxUA” …></script>)
- Digests (例如:sha256-abcd,匹配页面上特定的元素: 例如<script integrity=“sha256-abcd”….><script>)
Policy Delivery
- 可以在HTTP返回头Content-Security-Policy声明
- 也可以在页面上的meta元素http-equiv属性上声明
Content-Security-Policy-Report-Only响应头
可以允许开发者收集页面上违反policy的报告
但是这个响应头是不支持在meta标签上配置的
支持meta标签配置
例如:
<meta http-equiv="Content-Security-Policy" content="script-src 'self'">
但是Content-Security-Policy-Report-Only,report-uri, frame-ancestors,sandbox也是不支持
如何捕获和上报违规行为
当发生违规行为时,就会在element或者windows触发一个SecurityPolicyViolationEvent事件,
js可以通过以下代码来进行捕获
if ('SecurityPolicyViolationEvent' in window) { // Check browser support
window.addEventListener('securitypolicyviolation', function(e) {
console.log( e.violatedDirective, e.originalPolicy );
});
}
所有指令
Fetch Directives
- child-src
可以控制iframe,frame和worker的请求加载 - connect-src
控制fetch(),xhr, eventsource, beacon, a标签, websocket的请求加载 - default-src
可以作为其他fetch directive的默认值 - font-src
可以控制字体资源的请求加载 - frame-src
可以控制ifream, frame的请求加载 - Img-src
控制图片的请求加载 manifest-src
控制manifest的请求加载<link rel="manifest" href="https://example.org/manifest">
media-src
控制video,audio还有track等请求加载<audio src="https://example.org/audio"></audio> <video src="https://example.org/video"> <track kind="subtitles" src="https://example.org/subtitles"> </video>
- object-src
控制embed,object的请求加载 prefetch-src
<link rel="prefetch" src="https://example.org/"></link> <link rel="prerender" src="https://example.org/"></link>
script-src
不单止控制script元素的请求加载,还包括:- 内联script block,除非script-src或者default-src没有设置为“unsafe-inline” 或者 nonce-source, hash-source
- eval(),Function(), setTimeout和setInterval第一个参数不是函数,除非script-src或者default-src设置为“unsafe-eval”
- 类似javascript: 的url必须通过script-src inline check
- script-src-elem
控制所有的script请求和script block;但是类似<div onclick=“alert(1)”></div> 内联事件处理器是script-src-attr处理控制的 - script-src-attr
控制类似元素上内联事件处理器 style-src
主要控制以下几点:- 所有的style请求,包括style元素,@import
- 内联style block,除非style-src或者default-src没有设置为“unsafe-inline” 或者 nonce-source, hash-source
- 修改style的cssText和其他insertRule方法,除非script-src或者default-src设置为“unsafe-eval”
- style-src-elem
控制style元素,但是不包括元素上的内联style - style-src-attr
控制元素上的内联style - worker-src
控制Worker, ShareWorker和ServiceWorker的请求加载
Document Directives
- base-url
控制base元素上的url设置 - sandbox
可以让页面上的iframe设置了sandbox属性一样
Navigation Directives
- form-action
控制表单的提交路径 frame-ancestors
可以控制资源能否在frame,iframe, object, embed等元素上加载展示
这个指令是跟X-Frame-Options响应头功能是相似的,frame-ancestors X-Frame-Options 意义
none DENY 禁止在frame,iframe等元素上加载展示
self SAMEORIGIN 只有是同源的时候才可以在frame,iframe上进行展示唯一不一样的是X-Frame-Options的SAMEORIGIN,只会匹配最顶层页面的URL;而frame-ancestors会检查所有的祖先元素也就是frame,iframe, object, embed;
而且frame-ancestors会覆盖X-Frame-Options- navigate-to
控制整个页面的跳转,包括a, form, window.loacation, window.open等等方式的跳转
Reporting Directives
- report-to
可以设置上报的地址(但是感觉还是使用捕获SecurityPolicyViolationEvent方式有更高的可控性)
CSP规则的继承性
所有iframe加载时会复制一份CSP的规则,所以iframe也是不能绕过CSP的安全策略
HSTS(Strict-Transport-Security)
背景虽然目前大部分网站都支持https,但是仍然不代表绝对的安全,其中之一场景就是浏览器与服务器之间建立链接时会先用发起http请求(如果没有使用https的url),然后再重定向到https的url,而发起http到重定向https过程中就会容易出现中间人的攻击,所以这里就提供一种方式去规避这个问题:
Strict-Transport-Security响应头可以强制浏览器和服务器从一开始就建立https链接,而不是经过http请求再重定向https,所以在第一次请求服务器成功建立https链接并接收到Strict-Transport-Security响应头;那么浏览器在下一次请求服务器时就会直接发起https请求。
但是HSTS的方式还有一个漏洞就是必须与服务器先建立起第一次https链接(中间就有可能从http再重定向到https的过程),这意味着攻击者还是有机会可乘,而谷歌这里维护着一个 HSTS preload service,只要在这上面成功提交域名就会被硬编码到浏览器中,当浏览器对这些域名第一次发起请求时会直接走https;但是这个是硬编码配置也就是意味只有等chrome更新版本才会生效,只能用作一个补充手段。
以前一直有一个错误想法,HSTS会记录网站的证书然后建立链接时会进行对比(忘了网站的证书也是会更新的,所以没有意义)
一些跟安全相关的响应头
- X-Content-Type-Options
因为浏览器存在一种内容嗅探行为,只要在Content-Type没有设置或者Content-Type设置的类型跟实际内容不相符的时候就会出现这种行为尝试去猜测实际的内容;
而X-Content-Type-Options会禁止这种嗅探行为,让浏览器按照Content-Type设置的类型去解释内容,而如果script/style请求返回的内容不是JavaScript MIME type或者text/css也会阻塞这些请求 - X-Frame-Options
可以控制页面上的frame,iframe,embed和object元素的加载,有效避免点击劫持等攻击
Cookie安全相关属性
- Security
可以限制cookie只能在https链接下传输, 会话token应该设置为security, 防止中间人攻击获取token - HttpOnly
可以限制cookie不能通过document.cookie直接获取,防止xss攻击窃取token SameSite
可以控制哪些cookie可以在跨站请求中传输(限制第三方cookie),可以抵御csrf攻击,目前chrome默认SameSite=Lax什么是跨站请求?
首先要理解同域和同站区别,因为两者容易混淆同域:两个Origin的scheme+host+port完全相等
同站:一个站点完整的名称是eTLD+1,eTLD就是有效 TLD,而TLD(顶级域名)也就是.com和.org,eTLD就是类似.co.jp或者.github.io,这些域在公共后缀列表中进行定义;eTLD+1就是eTLD加上前面一部分。
例如:
www.taobao.com 和 www.baidu.com 是跨站
www.a.taobao.com 和 www.b.taobao.com 是同站
a.github.io 和 b.github.io 是跨站(注意是跨站)所以在浏览器怎么判断一个请求是跨站请求
就是根据请求的目标站点和发起请求的站点是否同站,否则就是跨站请求了例如在exampleA.com页面使用<form action=“exampleB.com” method=“post”></form>提交给exampleB.com是不可以携带exampleB.com上设置了SameSite的cookie
对于服务端我们仍然可以通过HTTP请求头Sec-Fetch-Site来判断请求来源(浏览器支持率并不是很高),Sec-Fetch-Site有以下属性值cross-site,same-site,same-origin,none
SameSite不同属性值的区别:
如果SameSite属性值是“Strict” 只能允许在同站请求上发送cookie;
如果属性值是“Lax”,那么除了同站请求上仍然可以发送cookie,跨站的导航("cross-site" top-level navigations)且请求方法是GET时也会发送cookie
如果属性值是“None”,必须同时设置Secure属性才会生效,因为等于去掉SameSite的保护,所以必须在https链接环境下确信没有中间人攻击那么什么是top-level navigations,例如:从exampleA.com点击a标签跳转到exampleB.com
所以意味着“Lax”条件下,仍然可能存在漏洞,在攻击者的网站可以:
- 使用链接跳转
- 使用<link rel='prerender'>
- 使用<form method="GET" action="...">
都会触发一次成功的同站请求
SameSite在ShareWorker和ServiceWorker环境下的效果:
首先确定worker当前的site- ShareWorker因为可以绑定多个document,所以计算当前"site for cookies”算法是:
1)设置worker_site为worker注册的domain
2) 遍历绑定worker的document列表,如果document列表上存在一个document的site与worker_site不匹配,则返回字符串为空
3)否则返回worker_site - ServiceWorker返回的是worker注册的domain
然后根据计算的site来跟请求的origin对比确定是否是跨站或者同站请求,然后再应用SameSite
ajax请求中的withCredentials属性与samesite
samesite控制的跨站请求能否传输cookie
withCredentials控制的是跨域请求中能否传输cookie
当一个请求既是跨域又是跨站请求,cookie先会受到samesite属性影响,再受到ajax里面的withCredentials影响SameParty
因为SameSite对于第三方Cookie限制太大,某些业务场景下难以实现(例如登陆淘宝taobao.com后应该可以跟天猫tmall.com共享登陆信息,所以就需要一个第三方cookie去共享)First-Party Sets policy
首先我们一种策略把不同的站点标记成为同一方的站点,这样后面被标记为SameParty的cookie在这些站点之间传输才是合情合理
怎么定义First-Party Sets?
例如有brandx.site,fly-brandx.site,drive-brandx.site;brandx.site作为最顶层的域名,必须在/.well-known/first-party-set路径下定义一下内容:{ "owner": "brandx.site", "version": 1, "members": ["fly-brandx.site", "drive-brandx.site"] }
而fly-brandx.site,drive-brandx.site也分别在https://fly-brandx.site/.well...,https://drive-brandx.site/.we...下定义
{ "owner": "brandx.site" }
那么他们之间关系就可以明确定下来了
First-Party Sets policy如何影响cookie
如果在brandx.site设置以下cookie:
Set-Cookie: session=123; Secure; SameSite=Lax; SameParty
那么现在从fly-brandx.site跳转到brandx.site就会自动带上这个cookie(没有SameParty仍然会受限制)但是注意:
- SameParty设置必须与Secure一起
SameParty不能与SameSite=Strict同时设置
CORS与CSRF
可以通过Access-Control-Allow-Origin设置,来限制跨域请求(很多时候为了图方便设置为“*”,其实很危险)
Access-Control-Allow-Methods限制跨域可以使用的请求方法
Access-Control-Allow-Credentials限制跨域是否允许携带cookie
本质上我们对跨域的请求是不信任的,因为不敢确定是否是csrf攻击,只能对跨域请求多加限制
参考资料
HTTP State Management Mechanism
SameSite
同站同源区别
CORS
SameParty
关于cookie的 samesite和xHr 的withCredentials的思考
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。