ajax跨域请求并写入Cookie兼谈Chrome SameSite策略

2022年 6月 10日 68点热度 0人点赞

CRSF 攻击

什么是 CSRF

CSRF(Cross-Site Request Forgery) 跨站请求伪造: 攻击者诱导受害者进入第三方网站, 在第三方网站中, 向被攻击网站发送跨站请求. 利用受害者在被攻击网站已经获取的注册凭证, 绕过后台的用户验证, 达到冒充用户对被攻击的网站执行某项操作的目的.

一个典型的 CSRF 攻击有着如下的流程:

  1. 有一天你在银行网站 bank.com, 登录了并保留了登录凭证 (Cookie)
  2. 后来你寻找刺激进了伪装不健康网站的诈骗网站 defraud.com
  3. 诈骗网站返回的内容中有一个【同城交友】的按钮, 它会对银行的网站 bank.com 发起转账请求
  4. 出于找乐子的想法, 你点击了这个按钮
  5. 诈骗网站 defraud.com 向银行网站 bank.com 发起了转账请求, 浏览器会默认携带 bank.com 的 Cookie
  6. 银行网站 bank.com 接收到请求后, 对请求进行验证, 并确认是你的凭证, 误以为是用户自己发送的请求
  7. 银行网站 bank.com 以你的名义执行了 转账 100w 给骗子的账户
  8. 诈骗完成, 骗子在你不知情的情况下, 冒充你, 让银行网站 bank.com 执行了自己定义的操作

大致的时序图可以见下面这个:

file

当然现在的银行肯定没有这么差劲, 发个请求就把你的钱给转走了, 但是这种风险确实是存在的. 你要是有兴趣的话可以自己找个老旧一点的 Chrome 浏览器, 找几个不那么有名的网站, 分析分析协议, 我相信肯定可以找到类似的漏洞.

为什么会有这个风险?

根本原因是, 诈骗网站向银行网站发起请求时带上了银行给用户在浏览器留下的凭据, 比如 Cookie.

什么是跨域?

同源策略

说到跨域, 首先需要解释下为什么会出现这样的跨域问题. 这其实都源于浏览器的同源策略.

同源策略是浏览器中的一个重要的安全策略, 是 Netscape 公司在 1995 年引入. 同源策略的作用就是为了限制不同源之间的交互, 从而能够有效避免 XSS,CSFR 等浏览器层面的攻击.

同源指的是两个请求接口 URL 的协议 (protocol), 域名 (host) 和端口 (port) 一致.

以 HTTP 地址 http://www.havefun.com:8080/api/smile?a=23333#showmeyourcode 为例讲解下:

http  ://   www.havefun.com   :  8080    /api/smile    ?a=23333   #showmeyourcode
协议        域                    端口    请求路径       请求参数   锚点

跨域

跨源资源共享 (CORS)(或通俗地译为跨域资源共享) 是一种基于 HTTP 头的机制, 该机制通过允许服务器标示除了它自己以外的其它 origin(域, 协议和端口), 使得浏览器允许这些 origin 访问加载自己的资源. 跨源资源共享还通过一种机制来检查服务器是否会允许要发送的真实请求, 该机制通过浏览器发起一个到服务器托管的跨源资源的"预检"请求. 在预检中, 浏览器发送的头中标示有 HTTP 方法和真实请求中会用到的头.

跨源 HTTP 请求的一个例子: 运行在 https://domain-a.com 的 JavaScript 代码使用 XMLHttpRequest 来发起一个到 https://domain-b.com/data.json 的请求.

出于安全性, 浏览器限制脚本内发起的跨源 HTTP 请求. 例如,XMLHttpRequest 和 Fetch API 遵循同源策略. 这意味着使用这些 API 的 Web 应用程序只能从加载应用程序的同一个域请求 HTTP 资源, 除非响应报文包含了正确 CORS 响应头.

以上内容来自:跨源资源共享 (CORS)

有几点可以总结一下:

  1. 什么情况下跨域: 协议, 域或者端口有任意一个不同则跨域
  2. XMLHttpRequest 和 Fetch API 遵循同源策略: 要么你只请求同一个域下的接口 (前后端一起部署或者代理), 要么被请求的接口在返回的 HTTP Header 中设置跨域
  3. 即使域名指向了 IP, 使用域名和使用 IP 依然会跨域

Chrome 的 SameSite 策略

SameSite 属性介绍

SameSite 是 Cookie 的一个属性, 用来限制第三方 Cookie.

  • Strict(禁止第三方 cookie)
  • Lax(稍微严格一点)
  • None (注意,Cookie 的 SameSite 设置为 None 以后,Secure 需要同时设置为 true, 这意味着你的网站必须支持 https)

为了防止这种攻击行为,Chrome 很早就推出了 Cookie 的 SameSite 属性来限制第三方 Cookie, 但是大家伙都不理不睬. 所以 Chrome 干脆一不做二不休, 在 Chrome 80 版本以后默认把 Cookie 的 SameSite 属性设置为 Lax, 以此来对第三方 Cookie 做一些限制, 这样就能大大地降低被 CSRF 攻击的风险了.

file

SameSite 属性介绍和上图都来自于: [高级]浏览器的 SameSite 策略, 个人觉得图画的很棒!

我的经历

Ajax 发起请求的代码如下:

url = url.trim();
$.ajax({
    type: "get",
    async: true,
    url: url + "?type=apple&code=" + window.code,
    xhrFields: {
        withCredentials: true
    },
    crossDomain: true,

    beforeSend: function () {
        //请求前的处理
    },

    success: function (data) {
        window.location.href = window.redirectUrl
    },

    complete: function () {
        //请求完成的处理
    },

    error: function () {
        //请求出错处理
        window.location.href = window.redirectUrl
    }
});

不遵循 SameSite 策略,Chrome 只能跟你说抱歉了:

file

这个情况是我在浏览器用 Ajax 请求公司另一个应用的接口时, 浏览器的警告. 当时调用这个接口主要是为了能将那个应用的 Cookie 写进来.

解决这个问题有两种方法:

  1. 第一种: 将这个被调用接口的应用和发起请求的应用放在同一个域下面, 这样就不存在跨域问题了;或者对接口进行代理, 后端去访问这个接口
  2. 第二种: 对方必须是 HTTPS 的接口, 并且 Cookie 标识中要设置 SameSite=None;Secure 才能回写 Cookie, 二者缺一不可.

因为那个接口是我们一个内部应用的, 而且 HTTPS 相对来说比较麻烦 (我现在的公司是项目型的公司), 所以最好的方法就是使用代理.

参考

rainbow

这个人很懒,什么都没留下

文章评论