关于java:Cookies的SameSite属性

59次阅读

共计 6276 个字符,预计需要花费 16 分钟才能阅读完成。

自 Chrome 51 版本开始,浏览器的 Cookies 新增了一个 SameSite 属性,用来避免 CSRF 攻打和信息透露,更多信息参考 chrome Feature: ‘SameSite’ cookie attribute。

简略回顾什么是 CSRF 攻打

Cookies往往用来存储用户的身份信息,歹意网站通过设法伪造带有正确 Cookies 进行 HTTP 申请,这就是 CSRF 攻打。

举例来说,用户登陆了银行网站your-bank.com,银行服务器发来了一个 Cookie。

Set-Cookie: session_id=abc123;

用户起初又拜访了歹意网站malicious-site.com,歹意网站总是千方百计让你在歹意站点发送一个表单申请。

伎俩:中奖填写分割信息、通明的 form 表单提交按钮、附加在引诱图片上的超链接

<form action="your-bank.com/transfer" method="POST">
  ...
</form>

用户一旦被诱骗发送这个表单,银行网站就会收到带有正确 Cookie 的申请。为了避免 CSRF 攻打,银行网站表单会设置一个暗藏域,表单提交时一起带上一个随机 token 至服务器,通知服务器这是实在申请。

<form action="your-bank.com/transfer" method="POST">
  <input type="hidden" name="token" value="dad3weg34">
  ...
</form>

之所以被 CSRF 攻打,是因为歹意网站诱导你在其页面上发送了第三方 cookie(此时的银行网站 cookie 为第三方 cookie),它除了用于 CSRF 攻打,还能够用于用户追踪。

第三方是一种绝对概念,规定假设你正在拜访的站点为第一方站点,则浏览器为第二方,其余网站就是第三方站点,第三方站点诱导你发送第一方站点的 cookie 时,咱们就说此时的 cookie 为第三方 cookie。

比方,Facebook 在第三方网站插入一张看不见的图片。

<img src="facebook.com" style="visibility:hidden;">

浏览器加载下面代码时,就会向 Facebook 收回带有 Cookie 的申请,从而 Facebook 就会晓得你是谁,拜访了什么网站。

SameSite

cookies 机制始终被认为是不平安的,随着技术的更新,界内始终在欠缺 cookies 的平安机制,SameSite属性是谷歌浏览器为欠缺 cookies 平安机制出的个性之一。

Cookie 的 SameSite 属性用来限度第三方 Cookie 的行为。

它能够设置三个值。

  • Strict
  • Lax
  • None

Strict

Strict最为严格,齐全禁止第三方 Cookie,当以后站点与申请指标站点是 跨站 关系时,总是不会发送 Cookie。换言之,只有以后站点 与申请指标站点是 同站 关系时,才会带上 Cookie。

Set-Cookie: CookieName=CookieValue; SameSite=Strict;

这个规定过于严格,可能造成十分不好的用户体验。

举例说明:

假设你以后所处站点地址为 https://obmq.com/index.html,该站须要通过 XHR 申请获取某天气站点的将来 7 天的天气信息https://weather-forecast.org/api/weather?future=7,该接口要求必须携带 cookieSet-Cookie: vip=true; Path=/; HttpOnly; SameSite=Strict;,这种状况下,你无论如何都无奈在https://obmq.com 站点下发送这个 XHR 申请时还能携带上这个 cookie,换句话说,你发送的接口申请的 cookie 申请头肯定不会有vip=true,即便你当初曾经是该天气网站的 vip。

None

None在 Chrome 85 版本之前是 SameSite 的默认设置值,即 Set-Cookie: key=value; SameSite=None 等于Set-Cookie: key=value

在 Chrome 85 版本之前,显示设置 SameSite=None 不须要设置 Secure 属性,具体参见:Reject insecure SameSite=None cookies

在 Chrome 85 版本当前,站点抉择显式敞开 SameSite 属性时,在将其值设为 None 的同时。必须同时设置 Secure 属性(示意 Cookie 只能通过 HTTPS 协定发送),否则有效。

上面的设置无效。

Set-Cookie: widget_session=abc123; SameSite=None; Secure

上面的设置有效。

Set-Cookie: widget_session=abc123; SameSite=None

Lax

Chrome 在 85 版本后将 Lax 设为 SameSite 的默认值,即 Set-Cookie: key=value; SameSite=Lax 等于Set-Cookie: key=value,具体参见:Cookies default to SameSite=Lax。

Lax规定比拟宽松,大多数状况也不发送第三方 Cookie,然而导航到指标站点的 Get 申请除外。

Set-Cookie: CookieName=CookieValue; SameSite=Lax;

导航到指标站点的 GET 申请,只包含三种状况:链接,预加载申请,GET 表单。详见下表。

申请类型 示例 SameSite=None;Secure Lax
链接 <a href=”…”></a> 发送 Cookie 发送 Cookie
预加载 <link rel=”prerender” href=”…”/> 发送 Cookie 发送 Cookie
GET 表单 <form method=”GET” action=”…”> 发送 Cookie 发送 Cookie
POST 表单 <form method=”POST” action=”…”> 发送 Cookie 不发送
iframe <iframe src=”…”></iframe> 发送 Cookie 不发送
xhr/fetch $.get(“…”) 发送 Cookie 不发送
Image <img src=”…”> 发送 Cookie 不发送
Script <script src=”…”> 发送 Cookie 不发送

设置了 StrictLax当前,根本就杜绝了 CSRF 攻打。当然,前提是用户浏览器反对 SameSite 属性。

Schemeful Same-Site

自 Chrome 86 版本开始,思考到不平安的 http:// 协定依然为网络攻击者提供了篡改 cookie 的机会,而后将这些 cookie 用于站点平安的 https://。谷歌浏览器批改了 cookie 的Same Site 的定义,将在雷同域名的平安(https://)协定和不平安(http:…跨站 的判断因素之一。详情参见 Feature: Schemeful same-site

如果您的站点全面降级到 https 协定,那么上面的内容不适宜您;如果您的站点是 https 协定和 http 协定混存,那么您须要关注。

常见的 “cross-scheme” Cookies 携带状况

超链接

Schemeful Same-Site 禁止时,从 http:// site.example 链接到 https://site.example 时,即便SameSite=Strict 仍然会携带上 cookie。

Schemeful Same-Site 启用时,从 http:// site.example 链接到 https://site.example 时,SameSite=Strict 的 cookies 会被锁定,其余 cookies 携带的体现如下图和下表:

<figcaption style=”text-align: center;”>Cross-scheme navigation from HTTP to HTTPS.</figcaption>

<br/>

HTTP → HTTPS HTTPS → HTTP
SameSite=Strict ⛔ Blocked ⛔ Blocked
SameSite=Lax ✓ Allowed ✓ Allowed
SameSite=None;Secure ✓ Allowed ⛔ Blocked
加载子资源

加载子资源的形式包含 images, iframes, 和XHR or Fetch 的网络申请。

加载子资源分为 http 加载 https 子资源https 加载子 http 资源,携带 cookies 的体现如下图和下表:

Schemeful Same-Site 禁止时,加载子资源时,SameSite=Strict 或者 SameSite=Lax 的 cookie 会被携带上。

Schemeful Same-Site 启用时,加载子资源时,SameSite=Strict或者 SameSite=Lax 的 cookies 会被锁定,其余 cookies 携带的体现如下图和下表:

<figcaption style=”text-align: center;”>An HTTP page including a cross-scheme subresource via HTTPS.</figcaption>

<br/>

HTTP → HTTPS HTTPS → HTTP
SameSite=Strict ⛔ Blocked ⛔ Blocked
SameSite=Lax ⛔ Blocked ⛔ Blocked
SameSite=None;Secure ✓ Allowed ⛔ Blocked
POST 表单

Schemeful Same-Site 禁止时,发送 POST 表单时,SameSite=Strict 或者 SameSite=Lax 的 cookie 会被携带上。

Schemeful Same-Site 启用时,发送 POST 表单时,只有 SameSite=None 的 cookies 会被携带,其余 cookies 携带的体现如下图和下表:

<figcaption style=”text-align: center;”>Cross-scheme form submission from HTTP to HTTPS.</figcaption>

<br/>

HTTP → HTTPS HTTPS → HTTP
SameSite=Strict ⛔ Blocked ⛔ Blocked
SameSite=Lax ⛔ Blocked ⛔ Blocked
SameSite=None;Secure ✓ Allowed ⛔ Blocked
对 WebSockets 的影响?

如果 WebSocket 连贯与页面的安全性雷同,则仍将被视为同站。

https://连贯 wss:// 被视为同站;http://连贯 ws:// 被视为同站,否则视为跨站。具体如下:

Same-site:

  • wss://https:// 连贯
  • ws://http:// 连贯

Cross-site:

  • wss://http:// 连贯
  • ws://https:// 连贯

最佳实际

仍然应用 token 机制避免 CSRF 攻打

设置了 SameSite 属性值为 StrictLax当前,根本杜绝了 CSRF 攻打。然而 SameSite 是 Cookies 属性之一,所以存在以下诸多限度:

  • 要求浏览器必须兼容 Cookies 的 SameSite 属性
  • 要求客户端利用必须反对 Cookies 机制,比方 APP 和微信小程序并不反对 Cookies

限度如上所列,但不限于所列。

因为 SameSite 属性存在以上限度,所以须要服务器端仍然采纳 token 机制来避免 CSRF 攻打。

显示指定 SameSite 属性值为 LaxStrict

总应该设置一个显式的 SameSite 属性,而不是依赖浏览器为您利用的默认设置。这使您对 Cookie 的应用用意更加明确,并进步了跨浏览器取得统一体验的机会。

不兼容的客户端的解决

对于 SameSite 属性的兼容性在不同浏览器和雷同浏览器的不同版本之间是不同的,能够参考 chromium.org 上的更新页面的已知的不兼容客户端以理解以后已知的问题,然而无奈确定是否详尽无遗。只管这不是现实的抉择,但能够在此过渡阶段中采纳一些解决办法。

形式一:同时设置兼容 SameSite 属性的客户端和不兼容 SameSite 属性的客户端

// ~ 同时设置兼容 SameSite 属性的客户端和不兼容 SameSite 属性的客户端

// ~ 对于兼容 SameSite 属性的客户端,显示指定 SameSite 属性值以明确应用用意
Set-cookie: 3pcookie=value; SameSite=None; Secure

// ~ 对于不兼容 SameSite 属性的客户端,不设置 SameSite 属性
Set-cookie: 3pcookie-legacy=value; Secure

上面的示例显示了如何应用 Express 框架及其 cookie-parser 中间件在 Node.js 中执行此操作。

const express = require('express');
const cp = require('cookie-parser');
const app = express();
app.use(cp());

app.get('/set', (req, res) => {
  // Set the new style cookie
  res.cookie('3pcookie', 'value', { sameSite: 'none', secure: true});
  // And set the same value in the legacy cookie
  res.cookie('3pcookie-legacy', 'value', { secure: true});
  res.end();});

app.get('/', (req, res) => {
  let cookieVal = null;

  if (req.cookies['3pcookie']) {
    // check the new style cookie first
    cookieVal = req.cookies['3pcookie'];
  } else if (req.cookies['3pcookie-legacy']) {
    // otherwise fall back to the legacy cookie
    cookieVal = req.cookies['3pcookie-legacy'];
  }

  res.end();});

app.listen(process.env.PORT);

形式二:判断客户端的user-agent

在发送 Set-Cookie 相应头时,您能够抉择通过 user-agent 字符串检测客户端。请参阅不兼容客户端的列表,建议您找一个工具库来解决user-agent,因为您很可能不想本人编写这些正则表达式。

这种办法的益处在于,它只须要在设置 cookie 时进行一次更改即可。然而,此处必须指出是 user-agent 嗅探自身是不牢靠的,并且可能无奈捕捉所有受影响的用户。

无论抉择哪种形式,倡议确保有一种记录低版本客户端比例的办法。一旦比例降落到网站可承受的阈值以下,请确保您有揭示或警报以删除此代替办法。

谷歌打算推出 ”Privacy Sandbox”

谷歌打算齐全禁止第三方 cookie,毕竟 cookie 真的不是很平安,具体参考 this

参考链接

  • SameSite cookies explained
  • SameSite cookies recipes
  • Schemeful Same-Site
  • Cookie 的 SameSite 属性 – 阮一峰的网络日志

文章同步公布在各大支流常识共享平台,所以设 github 为对立的反馈区

疑难、探讨、问题反馈:https://github.com/weixsun/di…


关注微信公众号 obmq 及时理解最新动静

正文完
 0