本文为《白帽子Web讲安全(第2版)》——Cookie和会话安全章节的阅读总结及摘录,详述了Cookie的定义及Cookie的相关属性,概述了安全使用Cookie的方法等。
一、Cookie与会话的定义
- Cookie是Web服务端发送给用户浏览器的一小段数据,浏览器会存储这些数据,并在后续发往服务器的请求中带上它们。
- 会话的概念
- 会话的普遍概念是指:从用户登录直到退出期间,客户端与服务器的交互过程,会话的英文单词是session。
- 会话的另一个概念是指:在开发语言中,服务器端存储的会话数据也称为session,一般前者基于后者实现。
二、第一方Cookie与第三方Cookie
2.1 第一方Cookie
- 第一方cookie指用户当前访问的网站直接植入的cookie,通常是网站用于正常功能的cookie,如表示用户身份、记住用户的语言设置等。
2.2 第三方Cookie
- 当用户访问一个网站时,如果这个网站加载了其他网站的资源,此时由其它网站植入的cookie就称为第三方Cookie。
- 当不同的网站嵌入了同一个第三方网站资源时,用户访问这些网站时会带上相同的第三方cookie去加载第三方资源,因此第三方网站通过这个第三方cookie就可以实现用户在不同网站的访问行为分析,从而实现更精准的广告投放。
- 第一方cookie和第三方cookie是相对的概念,我们根据用户是直接访问网站还是通过外部网站嵌入访问的,来决定该网站的cookie是第一方的还是第三方的,而不是cook根据ie自身属性决定。
三、Cookie属性
- Cookie相当于服务器端颁发给用户的身份凭证,如果攻击者获取了用户的凭证,就相当于获取了用户的身份,即不需要账号与密码就可登录该账号(cookie未过期时),因此cookie的安全很重要。
3.1 Domain属性
- Domain属性用于指定cookie在哪些域名中生效,即访问哪些域名时浏览器会发送这个cookie。
- 该属性也决定了哪些域名的网页可以通过JavaScript访问这个cookie。
- 如果域名前面带了一个点号“.”,就表示该cookie对当前域名及其子域名都有效,浏览器访问该域名及其子域名时都会带上这个cookie;若不带点号,则仅访问当前域名时携带cookie,但同时子域名的JavaScript代码可访问该cookie;若不指定Domain属性,则该cookie为host-only-cookie即只对当前域名有效且子域名无法访问该cookie。
- 注意:部分网站中,服务器端设置cookie的Domain属性为父域名时会收到浏览器的拒绝【受到公共后缀列表影响】。
- 注意:Domain属性不包含端口信息,即Cookie的域名隔离不受端口的限制!因此如果一个域名同时在不同的端口运行了多个Web应用,使用cookie存储重要数据时需要评估每个应用的安全性防止cookie通过其中某个应用的安全漏洞被泄露出去。
- 注意:其他子域名的应用或其他端口的应用除了可以读取当前应用的cookie,也能写入特定名称的cookie,从而干扰当前应用,使其读取到错误的cookie。
3.2 Path属性
- Path属性用于指定cookie的生效路径,即只有访问这个路径及其子路径时,浏览器才会携带这个cookie。
- 若不设置该属性,则path属性默认值就是当前页面所在的路径。
- 如果一个域名中不同路径有很多不同的应用,同名的Cookie会造成干扰,这时可以设置cookie的Path属性将它们区分开来。
- 重要:不能依赖Path属性来做安全隔离,因为在浏览器中一个路径的页面可以使用iframe嵌入另一个路径的页面,而这两个页面是同源的,因此他们之间的DOM可以互访问,一个路径的页面便可以读取另一个路径页面的Cookie,所以在一个域名的不同路径下运行互相不信任的Web应用是危险的做法。示例如下
<ifram id="test" src="/admin/" width=0 height=0></iframe>
<script>
window.onload = function() {alert(document.getElementById('test').contentDocument.cookie);
}
</script>
3.3 Expires属性
- 服务端可以通过该属性设置cookie的有效期,浏览器会在这个cookie到期后自动将其删除。
- 如果没有指定expires属性。则该cookie叫做“临时cookie(也叫会话Cookie即仅在当前会话有效)”,当关闭浏览器后将自动删除该cookie。
- 注意:浏览器为了保证下次启动时用户体验的连续性(即每次启动时“打开上一次浏览的网页”),即使关闭浏览器也不会删除临时cookie。
- 浏览器对每个站点有最大cookie数量的限制,超限则会删除旧的cookie(不管该cookie到没到期),攻击者可利用这一点,通过植入多个cookie,“挤掉”受害者正常的cookie。
3.4 HTTPOnly属性
- 该属性的作用是:让该cookie只能用于HTTP/HTTPS传输,使得客户端JavaScript脚本无法读取cookie,这在一定程度上减少了XSS漏洞带来的危害。
3.5 Secure属性
- 给Cookie设置Secure属性后,该cookie只会被包含在HTTPS请求中。
- 在客户端通过JavaScript设置cookie或者在服务端通过set-cookie头来设置cookie时,如果当前网站使用的是HTTP协议,则写入带Secure属性的Cookie就会失败。
3.6 SameSite属性
- 服务端在Set-Cookie响应头中通过SameSite属性指示是否可以在跨站请求中发送该Cookie,即该cookie是否能作为第三方cookie。
- 当cookie没有指定SameSite属性时,现代浏览器的表现与SameSite=LAX时一致。
- 该属性的三个值
- None
- 不做限制,但当SameSite被设置为None时,要求cookie带上secure属性,即只能在HTTPS协议中发送该cookie。
- LAX
- 在普通的跨站请求中不发送cookie,但是导航到其他网站时(如点击链接)会发送cookie。
- Strict
- 完全禁止在跨站请求中发送cookie。
- 由于过于严格,因此实际中使用较少。
- 下表列举了常见的几种跨站请求在cookie的SameSite设置成什么值时才会发送。
- 除了影响cookie的发送,SameSite还会影响跨站点cookie的写入。
- 跨站点cookie的写入分以下两种情况
- 客户端通过JavaScript写入
- 跨站写入cookie时,若脚本未指定SameSite属性,则浏览器默认SameSite=LAX,因此浏览器会拒绝跨站点写入该cookie。
- 服务端通过Set-cookie写入
- 与客户端写入同理。
- 注意:这里的“同(跨)站点”的概念并不等同于同源策略中的“同(跨)源”的概念。它不像同源策略中的“同源”那样有严格的定义。
3.7 SameParty属性
- 如果一个企业运营了多个不同站点,这时即使将SameSite属性设置为LAX还是过于严格,会给跨站访问带来很多不便。
- 浏览器厂商提出SameParty属性的概念,允许企业将多个网站定义成一个可信站点集合,称为First-Part Sets第一方站点集合。
- 网站服务器将可信站点集合定义在./well-known/first-part-set文件中,当一个网站的页面要请求另一个网站资源时,浏览器会检测这两个网站是否处于一个First-Part Sets中,如果是,那么带有SameParty属性的第三方cookie将会被请求报文携带而不受SameSite属性的影响。
四、安全使用Cookie
4.1 Cookie前缀
- _Host-
- 如果一个cookie的名称中有这个前缀,服务端通过set-cookie头设置cookie或通过客户端脚本设置cookie时,只有满足以下四个条件,浏览器才会接受这个cookie
- 带有Secure属性:确保该cookie实在安全连接环境下写入的,不存在网络中间人的篡改。
- 不包含Domain属性:将该cookie与该域名绑定,只能由当前域名植入,不能对子域名生效。
- Path属性值为“/”
- 当前为HTTPS连接
- _Secure-
- 如果一个cookie的名称中有这个前缀,只有带有Secure属性且当前连接为HTTPS,浏览器才会接受这个cookie,相对“_Host-”前缀而言,它是约束更少的弱化版本。
- 如果要确保Cookie在安全的传输环境下被植入到客户端,可在cookie名称中加入“_Secure-”前缀;在子域名非常多的场景中,特别是子域名的安全不受控制时,建议在cookie名称中添加“_Host-”前缀,以确保该cookie不受其他域名影响。
4.2 保密性与完整性
- Web服务器应当把cookie当作不可信的外部输入数据,不能用cookie数据来做关键的判断。
五、会话安全
- 会话session的本质是标识不同的访问者并记录他们的状态。
5.1 会话管理
- 会话ID的随机性
- 会话ID(sessionID)最基本的要求是随机性。
- 会话ID也要足够长,防止枚举法。
- 过期与失效
- 超时机制应该在服务端实现,在时间到期后删除已存储的会话数据或标识该SessionID已失效。
- 绑定客户端
- 如果将会话与客户端绑定,即使攻击者窃取了SessionID,也无法在新的设备中登陆目标网站。
- 安全传输
- 现代Web应用基本上都是将SessionID写入Cookie中,并设置相应cookie的安全属性(如开启HTTPOnly、Secure属性)
- 客户端存储会话(使用JWT(JSON Web Token)机制用于会话管理)
- 上文所述的会话案例均为会话存储在服务端的场景,客户端只保存一个很短的SessionID。
- JWT本质上是带签名的JSON数据【类比SSH的签名】。
- 在用户登陆后,服务端将会话信息生成为一个带签名的JWT写入客户端。
- 客户端每次访问时都带上JWT,服务端可以验证签名的有效性并提取会话相关的信息。
- 使用这种机制可以将会话信息完全存储在客户端,使服务端无状态。
- 缺陷
- 已签发的会话Token无法吊销,因此需要在签发Token时加入有效期,并尽量使用短的有效期(防止有效期过长使发生安全隐患概率增加),可过短的有效期又会影响用户体验。
- 签名使用的密钥的安全管理也很重要,一旦密钥泄露,攻击者就可冒充服务器端签发任意账号的JWT,使所有账号受到威胁。
问题汇总
- Domain属性和Path属性功能没有重复吗?
- 答:注意!一个是域名及其子域名,一个是路径及其子路径
- 同(跨)站点与“同(跨)源”的概念区别?
- 解答
- 同(跨)站点概念较广,即只要是两个不同的网站,均为跨站点。
- 同(跨)源定义明确,如两个URL同源则必须要求两个URL的协议类型、域名、端口相同。
参考资料
- 《白帽子讲Web安全(第二版)》—— 吴翰清 叶敏
- 阮一峰:Cookie 的 SameSite 属性