Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SameSite问题记录 #5

Open
Kehao opened this issue Apr 9, 2020 · 0 comments
Open

SameSite问题记录 #5

Kehao opened this issue Apr 9, 2020 · 0 comments

Comments

@Kehao
Copy link
Owner

Kehao commented Apr 9, 2020

CSRF 攻击是什么

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

Set-Cookie:id=a3fWa;

用户后来又访问了恶意网站malicious.com,上面有一个表单。

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

用户一旦被诱骗发送这个表单,银行网站就会收到带有正确 Cookie 的请求。为了防止这种攻击,表单一般都带有一个随机 token,告诉服务器这是真实请求。

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

这种第三方网站引导发出的 Cookie,就称为第三方 Cookie。它除了用于 CSRF 攻击,还可以用于用户追踪。
比如,Facebook 在第三方网站插入一张看不见的图片。

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

浏览器加载上面代码时,就会向 Facebook 发出带有 Cookie 的请求,从而 Facebook 就会知道你是谁,访问了什么网站。

SameSite是什么

Cookie 的SameSite属性用来限制第三方 Cookie,从而减少安全风险。
可以设置三个值。

  • Strict: 最为严格,完全禁止第三方 Cookie。
  • Lax: 大多数情况也是不发送第三方 Cookie,Get 请求除外。
  • None: 网站可以选择显式关闭SameSite属性,将其设为None。不过,前提是必须同时设置Secure属性(Cookie 只能通过 HTTPS 协议发送),否则无效。

问题描述

  • 以前设置Access-Control-Allow-Credentials: true和xhr.withCredentials = true,可以实现跨域传递Cookie,达到维持用户登录态等目的,但是会有CSRF的风险。所以,从Chrome 51开始,浏览器的Cookie新增加了一个SameSite属性,用来防止CSRF攻击和用户追踪, 默认是关闭的。
  • Chrome 80开始,浏览器的CookieSameSite属性会默认开启,用来防止CSRF攻击和用户追踪
  • Chrome 80的用户会出现set cookie失败的情况

前端暂时解决方案

  • 打开Chrome设置,chrome://flags

  • 禁用SameSite

  • 副作用:会出现warning提示

后端解决方案

  • 后端服务域名必需使用https协议访问

  • SameSite属性的值改为None

  • secure属性设置为true

  • 后端要判断浏览器的user-agent属性,Chrome58前,没有SameSite属性,要注意!

代码示例

private static void setSameSite(HttpServletResponse response){
  Collection<String> headers = response.getHeaders(HttpHeaders.SET_COOKIE);

  boolean firstHeader = true;

  // there can be multiple Set-Cookie attributes
  for (String header : headers) {
    if (firstHeader) {
      response.setHeader(HttpHeaders.SET_COOKIE, String.format("%s; %s", header, "SameSite=None"));
      firstHeader = false;
      continue;
    }
    response.addHeader(HttpHeaders.SET_COOKIE, String.format("%s; %s", header, "SameSite=None"));
  }
}

Cookie cookie = new Cookie("CSESSIONID", csessionid);
cookie.setMaxAge(-1);
cookie.setPath("/");

//解决chrome 78版以上跨域问题
cookie.setSecure(true);

// 并写回浏览器
response.addCookie(cookie);

setSameSite(response);

使用Nginx的proxy_cookie_path功能

如果站点Cookie所在目录在根目录/下,设置如下:

proxy_cookie_path / “/; secure; SameSite=None”;

如果站点Cookie所在目录在abc目录下,设置如下:

proxy_cookie_path /abc/ “/abc/; secure; SameSite=None”;

如果无法确定站点Cookie目录,可使用Chrome开发者工具,监测Network下网络请求,找到 Response Headers中set-cookie属性值,该值中有path属性值即为Cookie目录,也即上文要替换的/或者/abc/值。

因为设置sameSite为None之后,CSRF的风险又回来了。所以,换成token的检验方式而不依赖Cookie,才是最好的解决方式。
20200409142832

相关文档

@Kehao Kehao changed the title 当跨域遇到Cookie与SameSite SameSite问题记录 Apr 9, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant