WEB跨域请求无法传递(携带)第三方Cookie的问题剖析(你一定不知道的SameSite)_程序员Daddy的博客-程序员宅基地_携带第三方cookie

技术标签: 技术分享  Cookie  浏览器  SameSite  跨域请求  

一、前言

最近在实际开发过程中遇到一个关于跨域请求无法传递Cookie的问题。该场景大致为:我们在一个web页面a下(假如该页面的网址为a.csdn.com),然后再改页面中使用ajax请求跨域访问了一个服务器b(假如其域名为b.baidu.comm)的接口。这就是一个普通的跨域请求,在这个跨域请求中,我们期望页面a在请求服务器b的接口的时候,浏览器能够将服务器b下的cookie(baidu.com下的cookie)都携带上。这样服务器b再收到请求之后能够从cookie中获取一些C端用的信息,如pin等。大致图示如下。

我们都知道这种跨域请求默认是不会成功的,我们需要做如下两件事情,才能够确保跨域请求成功地同时携带上baidu.com下的Cookie。

1、需要在服务端B开启CORS,这样页面a的跨域请求才能够被正常处理。

2、需要web页面a在请求的参数中添加withCredentials=true属性,这样浏览器才会携带cookie到服务端B。

然而事实却不是这样,通过上述操作之后,当我们在跨域请的时候,请求能够正常达到服务端B,服务端B返回的数据浏览器端也能够正常处理。但是跨域请求的过程中浏览器没有携带Cookie到服务端B,导致部分基于C端用户信息的逻辑出错。

看到这里我也很纳闷,按照之前的经验通过上述两步处理之后。服务端B是可能能够拿到Cookie的。那么为什么这里没有传递Cookie去服务端呢?通过一些列Google操作,我终于找到了具体原因。接下来就给大家详细分析下具体原因。

二、根因分析

通过一些列Google之后,终于找到了为什么上述跨域场景下CORS和withCredentials=true都设置的场景下,Cookie仍然不传递的原因。

这是因为Google去年在Chrome开始支持Cookie的新属性SameSite(该属性目前已经得到了业界各类大众浏览器的支持)。该属性提出的目的是为了解决接口Cookie被滥用,以及CSRF的问题(PS:在SameSite推出之前,上述跨域场景确实可以正常携带Cookie到b.baidu.com中)。

接下来我就为大家大致介绍一下什么SameSite属性。

1、SameSite属性简介

SameSite是Cookie的一个属性,其和path,domain一样,是一个普通的Cookie属性。其作用是限制该Cookie的在请求的时候是否被传递到Cookie所属服务的场景。

它一共有三个值,其基本含义分别如下:

Strict

Strict最为严格,完全禁止第三方 Cookie。即在跨站点时,任何情况下都不会发送 Cookie。换言之,只有当前网页的 URL 与请求目标一致,才会带上 Cookie。

设置方式为:Set-Cookie: CookieName=CookieValue; SameSite=Strict;

Lax

Lax规则稍稍放宽,大多数情况也是不发送第三方 Cookie,但是导航到目标网址的 Get 请求除外( top-level navigations)。

所有浏览器的Cookie默认SameSite属性都为Lax,即SameSite设置为空(未设置),则表示为Lax。

设置方式为:Set-Cookie: CookieName=CookieValue; SameSite=Lax;

导航到目标网址的 GET 请求,只包括三种情况:链接,预加载请求,GET 表单。详见下表。

设置了Strict或Lax以后,基本就杜绝了 CSRF 攻击。当然,前提是用户浏览器支持 SameSite 属性。

None

如果设置为None(前提是必须同时设置Secure属性(Cookie 只能通过 HTTPS 协议发送),否则无效)。此时就表示Cookie不受约束在任何跨域场景下,只要设置了withCredentials=true都会发送到三方服务端。

设置方式为:Set-Cookie: CookieName=CookieValue; SameSite=None; Secure;

2、如何设置SameSite

大家看到上面介绍SameSite属性的时候,细心的同学应该注意到一个问题,SameSite属性的设置方式我们都是介绍的通过Set-Cookie这个Header来实现的。那么为什么我们不能通过Java中的Cookie对象来添加呢?

原因是因为SameSite是一个新兴的属性,而我们当前主流的JDK版本(jdk7和jdk8)从年代来讲都是比较老的代码了。因此其并不能够从接口层面支持新兴的SameSite属性。于是我们都只能够通过Set-Cookie的方式来来实现(样例如下)。

3、上述场景为什么无法携带Cookie

但我们认识了SameSite属性之后,我们自然而然就能够想到上述场景不携带Cookie的原因多半是因为SameSite被设置为了Lax或者Strict。于是我们查看浏览器中服务端B所在域名对应的Cookie发现,其确实所有Cookie都没有设置SameSite属性(如下图)。根据浏览器的默认策略,我们知道没有设置就表示SameSite=Lax。因此在ajax场景下SameSite=Lax的Cookie是无法进行传递的。

所以我们上述场景下无法传递Cookie到服务端。

三、解决办法

由于SameSite属性的支持导致了我们原来可以传递Cookie的场景都无法传递Cookie了。那么我们现在需要如何才能解决这个问题呢?这里我们给大家提供了如下三种方法。

1、取消跨域

这种方式解决起来比较简单,即将我们上述服务器B的域名修改为b.csdn.com。这样就不存在跨域的问题,也就轻松的解决了跨域问题。这种办法只适合服务端的域名可有有自己控制的场景了。

2、修改SameSite属性

这个方式也比较简单,我们只需要让Cookie生成方将将自己的需要的Cookie的SameSite属性设置为None即可。这样就可以让浏览器在任何跨域场景都发送该Cookie。

3、修改跨域请求方式

这种方式比较简单一点,且比较好由调用方操作。我们只需要将原来的ajax请求转换为如下三种请求类型(前提是业务上我们可以这样做)。

 

四、惯例

如果你对本文有任何疑问或者高见,欢迎添加公众号lifeofcoder共同交流探讨(添加公众号可以获得楼主最新博文推送以及”Java高级架构“上10G视频和图文资料哦)。

 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/hilaryfrank/article/details/112200461

智能推荐

解决Hash碰撞冲突方法总结_zeb_perfect的博客-程序员宅基地

Hash碰撞冲突我们知道,对象Hash的前提是实现equals()和hashCode()两个方法,那么HashCode()的作用就是保证对象返回唯一hash值,但当两个对象计算值一样时,这就发生了碰撞冲突。如下将介绍如何处理冲突,当然其前提是一致性hash。1.开放地址法开放地执法有一个公式:Hi=(H(key)+di) MOD m i=1,2,…,k(k其中,m为哈希表的表长。d

03.使用python的第三方库itchat获取全部微信好友头像,并拼接成大图_zhangMY12138的博客-程序员宅基地

目的为第四步过滤非人脸图片做准备。安装第三方库itchatpip install itchat代码注意,首先项目目录下要创建一个user目录,用来保存获取的微信好友头像。#导入对应的包import itchatimport PIL.Image as Imagefrom os import listdirdef get_imgs():#完成主要的下载头像的任...

javascript中new Date()的问题Invalid Date、NaN-NaN的问题_BigBug----的博客-程序员宅基地

在工作中多次遇到使用 new Date() 的问题,记录一下吧!在IE,safari, ios中的微信环境下..new Date('2016-01-01 00:00:00') //却返回这个值Invalid Date,转换失败new Date('2016/01/01 00:00:00') //这下就转换正确了Wed Jan 1 00:00:00 UTC+0800 2014 ...

2021MySql-8.0.26安装详细教程(保姆级)_ylb呀的博客-程序员宅基地_mysql8.0.26

MySql-8.0.26安装详细教程保姆级下载安装包安装配置配置环境变量下载安装包下载安装包:下载网址:https://dev.mysql.com/downloads/选择这个进入后选择直接下载第一个点击这里,开始下载安装配置解压安装包我这里解压到d盘打开编写MySQL配置文件在解压目录下新建my.ini文件将下面文本拷贝进my,ini文件中[mysqld]# 设置3306端口port=3306# 设置mysql的安装目录 ----------是你的文件路径-

阿里巴巴java开发手册-泰山版 下载_java金融的博客-程序员宅基地

泰山版《Java开发手册泰山版》获取方式:关注JAVA金融公众号,然后回复泰山二字即可得到下载链接。

随便推点

mysql exists/not exists/in/not in 的用法和差别_yinghuacao_dong的博客-程序员宅基地

以一个简单的查询为例子,涉及到的表如下:User表 薪资表 关联关系:user.user_id = salary.user_id1. existsexists查询先进行外查询,再进行内查询,内查询做一个行检测,如果返回值为true放入结果集,如果没匹配到就继续循环。sql语句如下: 先查询的是SELECT * FROM `user`,结果是三条记录,循环遍历外查询结果,内查询SELECT * FR...

FFMPEG小白-day10(sdl项目播放视频进阶)_黑键手记的博客-程序员宅基地

首先,向雷神,雷霄骅致敬!星河战队.png我们上篇文章已经介绍了sdl的播放视频的知识了,但是不知道试验过的同学有没有发现,我们在播放视频时的状态是这样的细心的同学应该能看到,鼠标现在是加载中的一个状态,知道我们关闭程序,鼠标才能恢复到可用的状态,那么为什么是这种情况呢?拿到程序一跑起来电脑就卡掉了?因为是mac下放的虚拟机,暂时无法截到鼠标忙碌的状态,大家脑补一下吧~~~乖做过编程的朋友都知道,...

Python教程:zipfile和tarfile模块_Python 学习者的博客-程序员宅基地

zipfile压缩解压缩形参 mode 应当为 ‘r’ 来读取一个存在的文件,‘w’ 来截断并写入新的文件, ‘a’ 来添加到一个存在的文件。ZipFile 也是一个上下文管理器,也支持with语句。解压时可指定密码,密码必须是bytes类型。import zipfile# 压缩z = zipfile.ZipFile('t.zip', 'w') # t.zip表示压缩后的文件名z.write('a.log') # 要打包压缩的文件z.write('data.data')z.close()

小白的JAVA之路-1_Summer_KR的博客-程序员宅基地

charAt() 方法用于返回指定索引处的字符。索引范围为从 0 到 length() - 1。语法public char charAt(int index)参数index – 字符的索引。返回值返回指定索引处的字符。实例public class Test {public static void main(String args[]) { String s = "www....

git远程删除分支后,本地git branch -a 依然能看到的解决办法_W8023Y2014的博客-程序员宅基地

http://blog.csdn.net/qq_16885135/article/details/52777871使用 git branch -a 命令可以查http://blog.csdn.net/qq_16885135/article/details/52777871看所有本地分支和远程分支(git branch -r 可以只查看远程分支) 发现很多在远程仓库已经删除的分支

免费双因素身份认证服务_普通网友的博客-程序员宅基地_简单双因素服务期

原创安当加密安当加密2022-03-2414:53合规性要求与双因素身份认证随着等保2.0的普及,越来越多的WEB应用登录开始采用双因素或多因素身份验证,如何简单、便捷、快速的实现用户安全登录对于软 件应用开发者来说至关重要。身份认证和登录的区别身份认证和登录是两个不同的概念,登录指从识别用户身份,到允许用户访问其权限相应的资源的过程。在登录的过程中,“鉴权”与“授 权”是两个最关键的过程。而身份认证只是其中的一个环节,即“鉴权”。身份认证的常用方法身份认证的形式...

推荐文章

热门文章

相关标签