Cookie SameSite属性介绍及其在ASP.NET项目中的应用
一、Cookie SameSite属性介绍
就像大家已经知道的,一旦设置Cookie之后,在Cookie失效之前浏览器会一直将这个Cookie在后续所有的请求中都传回到Server端。我们的系统会利用Cookie这个特性做很多事情,但通常我们会在Cookie中存放加密的用户身份,在Server端根据此身份检验用户是否有权限进行相应操作。
发送Cookie时,以往浏览器并不检测当前地址栏上的域(Domain)是不是和这个Cookie所属的域是否相同。恶意用户会利用这个问题巧妙设计一个站点,诱导用户点击从而造成跨站点请求伪造攻击(CSRF)。
为了解决这个问题,国际互联网工程任务组(IETF)提出了一个SameSite的草稿标准,Chrome 51开始支持此功能,但从Chrome 80 Stable版本开始启用一个较严格(Lax)的默认设置。
二、什么是跨站点请求伪造攻击(Cross-Site Request Forgery Attack,CSRF)
CSRF攻击简单而言就是恶意用户通过巧妙伪造请求从而盗用合法用户的身份进行恶意操作。
比如你开发了一个非常厉害的系统,系统中某些操作只有特定的人登录之后才有权限使用:
yourdomain.com/snap
[Authorize("Thanos")]
[HttpPost]
public ActionResult Snap()
{
///dangerous, will destroy the world.
}
因为系统要检验身份和权限,除非恶意用户能破解登录系统以Thanos身份登录,否则是没有办法调用这个方法的。
但是恶意用户可以伪造一个像下面这样的页面,恶意用户通过发邮件或者通过跨站点脚本攻击(XSS)等方式诱导具有权限的用户点击页面上的某些Button。如果具有权限的用户刚好已经登录,一旦点击按钮,系统则会以这个用户的身份触发上面危险的操作Snap()。
malicioususer.com/fancypage
...
<form action="yourdomain.com/snap">
<input type="Submit" value="This is cool, click me"/>
</form>
...
当然,微软 ASP.NET是通过AntiForgeryToken来解决这个问题,不过这个不是这篇blog讨论的主题。
三、Cookie的SameSite属性
为了解决上面到的Cookie的安全问题,Chrome从版本51增加了一个新的Cookie属性SameSite, 以控制Cookie是否能在跨站点的情况下传送。
Cookie所属的域名如果和浏览器地址栏中的域名不一致,则认为是跨站点。另外,当你的站点被iframe嵌在第三方站点时也被认为是跨站点。
这个属性有三个属性值:
None
如果你需要在任意跨站点情况下都使用某个Cookie,则需要将这个Cookie的SameSite设置为None. 但这里需要注意的是一定要同时设置Cookie的Secure,也就是需要使用https访问时才能关闭SameSite功能. 如果没有标明为secure, Chrome 80及以上会拒绝设置这个Cookie。
set-cookie: samesite=test; path=/; secure; SameSite=None
Strict
顾名思义,这是严格模式,就是在任何情况下都不允许跨站点发送Cookie。
这个设置显然是可以解决上面所提到的CSRF问题。因为当访问 malicioususer.com/fancypage 页面时,当前域是 malicioususer.com, 但user点击button提交时的action是指向另外一个域 yourdomain.com,这是两个不同的域,浏览器将不回传yourdomain.com下面的Cookie。这会极大的提高我们系统的安全性。
但这个严格模式也限制了一些被认为是安全的链接操作,比如:
- 你先登录了公司HR系统,假设该系统将所有Cookie的SameSite都设置为strict.
- 你用Web邮件系统收到了要求你到HR系统做审批操作的邮件,这封邮件带了一个link,直接链接到HR系统中审批的页面;
- 你点击这个link,但因为Cookie被设置为Strict模式,当到达审批页面时,HR系统没有收到任何Cookie,这时会认为你没有登录,而直接跳转到登录页面。在要求不是非常严格的情形下,可以认为这不是我们所期望的行为。因为只是跳到链接指向的页面并不是像POST操作修改数据。这需要通过下面的Lax属性解决这个问题。
Lax
Lax是比Strict稍宽松的模式,如果我们要允许跨站点链接传Cookie或FORM用GET Method提交时跨站点传Cookie, 则可以将这些Cookie的SameSite设置为Lax. Lax在Chrome 80成为默认设置,Lax既防止了CSRF也确保了正常的跨站点链接,是适合大多数站点的,可以解决上面HR系统安全中提到问题。
如果你的站点需要被iframe嵌套在第三方站点,这时你还是需要将Cookie设置为None。
这里也想到一点是,如果你的MVC Action只期望接受POST方法,那么一定要加上HttpPost Attribute,以避免造成意外的安全问题。
四、浏览器兼容性
如下图示目前主流浏览器都已经支持SameSite,虽然 IE 11不支持,但我测试之后发现这个Cookie本身还是没有丢失,只是缺失了安全保护功能。
https://developer.mozilla.org/en-US/docs/Web/HTTP/headers/Set-Cookie#Browser_compatibility
五、如何修改ASP.NET程序
下面总结的步骤是适用于基于ASP.NET开发的系统。微软官方白皮书对这些属性设置做了详细的说明,也可以参考官方白皮书。
.NET Framework 4.7.2 或4.8才开始支持SameSite, 在HttpCookie增加了SameSite的属性。所以需要安装.NET Framework 4.7.2以上SDK, 并且需要安装开发电脑和服务器上。
安装 Windows 2019/11/19累积更新补丁,请见KB Articles that support SameSite in .NET Framework,也需要安装在开发电脑和服务器上。没有安装这个补丁之前,如果SameSite为None, .NET Framework并不输出这个属性到Broswer, 但Chrome 80及以后将未设置默认为Lax,因此造成不一致的行为,所以需要安装这个补丁以明确输出None。
在Chrome地址栏输入: chrome://flags/, 将下面两项设置为Enabled。开启这两项设置是因为不是所有的Chrome都默认启用了这两项设置,Chrome只是在逐渐将这两项开启到Chrome的user. 所以开发时为了重现问题,最好是显式开启。
chrome://flags/#same-site-by-default-cookies
chrome://flags/#cookies-without-same-site-must-be-secure
修改项目文件属性, Target framework 4.7.2 或4.8。
根据需要修改web.config对Cookie的SameSite设置。
<configuration>
<system.web>
<httpCookies sameSite="[Strict|Lax|None|Unspecified]" requireSSL="[true|false]" />
<anonymousIdentification cookieRequireSSL="false" /> <!-- No config attribute for SameSite -->
<authentication>
<forms cookieSameSite="Lax" requireSSL="false" />
</authentication>
<sessionState cookieSameSite="Lax" /> <!-- No config attribute for Secure -->
<roleManager cookieRequireSSL="false" /> <!-- No config attribute for SameSite -->
<system.web>
<configuration>
修改说明:
httpCookies节点中的sameSite设置会影响系统中所有未指定sameSite Cookie的值, 但不覆盖forms/sessionState中设置的SameSite属性。
forms authentication的sessionState的默认Lax模式应该能满足常规需要, 并且保证网站的安全.
确实需要接受跨站点Cookie, 比如你的网站会嵌套在第三方网站的iframe里面,则需要将相关的Cookie 的SameSite改为None。需要注意的是为None的时候必须要将requireSSL改为true:
<configuration>
<system.web>
<httpCookies sameSite="None" requireSSL="true" />
<authentication>
<forms cookieSameSite="None" requireSSL="true" />
</authentication>
<sessionState cookieSameSite="None" />
<roleManager cookieRequireSSL="false" />
<system.web>
<configuration>
Cookie的SameSite都设置为None之后,需要防范CSRF. ,比如使用AntiForgeryToken。
如果某些Cookie需要使用与web.config中配置的不同SameSite属性,只需要在设置Cookie的时候明确指定其值.
var cookie = new HttpCookie("samesite", "test");
cookie.SameSite = SameSiteMode.None;
cookie.Secure = true;
Response.Cookies.Add(cookie);
因为有些老的浏览器并不支持SameSite这个属性,直接输出这个属性会造成老的浏览器忽略这个Cookie而造成Cookie丢失,请见已知的兼容问题. 如果确实需要支持这些老的浏览器,则需要根据user agent来检测浏览器,对于不支持SameSite的浏览器,我们需要将SameSite设置为(SameSiteMode)(-1).
private void CheckSameSite(HttpContext httpContext, HttpCookie cookie)
{
if (cookie.SameSite == SameSiteMode.None)
{
var userAgent = httpContext.Request.UserAgent;
if (BrowserDetection.DisallowsSameSiteNone(userAgent))
{
cookie.SameSite = (SameSiteMode)(-1);
}
}
}
BrowserDetection.DisallowsSameSiteNone()这个方法请见SampleSiteSupport.cs.
对于ASP.NET Core应用,微软也提供了详细的解决方案。
六、如何排查SameSite问题
SameSite默认为Lax已经从Chrome 80 Stable正式开始灰度启用,如果一个Cookie SameSite未指定,将会被默认为Lax,这可能会造成网站在某些情况下不能正常工作。
Chrome Developer Tools专门为SameSite问题提供了一个检测工具,在Network tab下有一个选项"Only show requests with SameSite issues". 找到有问题的request之后,可以在Response Headers下面找到哪个Cookie有问题。如下图示,因为我设置了SameSite为None,但没有设置Secure,所以Chrome会拒绝这个Cookie.
set-cookie: samesite=test; path=/; SameSite=None
在调试的时候如果有些跳转操作,为了看到跳转前后的请求记录,可以勾中Preserve log
七、参考
Cookies default to SameSite=Lax
Reject insecure SameSite=None cookies
Work with SameSite cookies in ASP.NET
Work with SameSite cookies in ASP.NET Core
作者:吴秀祥
2020/3/28
Cookie SameSite属性介绍及其在ASP.NET项目中的应用的更多相关文章
- win7,vs2010,asp.net项目中修改外部js文件,在调试时加载的还是旧文件
win7,vs2010,asp.net项目中修改外部js文件,在调试时加载的还是旧文件 我杀过 w3wp.exe和asp.net_state的进程,重启 iis admin的服务,都还是不行. 只是把 ...
- ASP.NET项目中引用全局dll
在ASP.NET项目中,有些dll是全局dll,也就是说,没有放在单个项目的引用中.它们一般存放在如下目录C:\Windows\assembly中 这个时候,我们需要在单个项目中引用他们,应该如何做呢 ...
- 如何在ASP.NET 项目中使用Silverlight页面
闲来无事,想写个网站玩玩,比较懒,不想写太多的样式来美化,看中了Silverlight,样式布局比较省事,但是又不想全部都用Silverlight 来写,所以才有此一文. 其实Silverlight最 ...
- VS的ASP.NET项目中cshtml关键词出错 红线,当前上下文中不存在名称
[参考]VS的ASP.NET项目中cshtml突然出错,当前上下文中不存在名称“ViewBag” 原因:web.config 配置错误 这种情况是因为两个web.config文件版本不匹配,需要进行修 ...
- selenium2 WebDriver 在asp.net项目中的应用
selenium2 WebDriver是一款跨平台的 自动化测试工具,它可以操纵浏览器,模拟用户行为,非常方便用户进行自动化测试. .net项目使用它,首先要通过 Visual Studio 的 nu ...
- 在ASP.NET项目中使用CKEditor +CKFinder实现图片上传功能
前言 之前的项目中一直使用的是FCKeditor,昨天突然有个想法:为什么不试一下新的CKEditor呢?于是花了大半天的时间去学习它的用法,现在把我的学习过程与大家分享一下. 谈起FCKeditor ...
- ASP.NET项目中使用CKEditor +CKFinder 实现上传图片
CKEditor是什么 CKEidtor是一个在线富文本编辑器,可以将让用户所见即所得的获得编辑在线文本,编辑器或自动将用户编辑的文字格式转换成html代码. 在ASP.NET工程中添加CKEdito ...
- 向asp.net项目中添加控件AspNetPager
1.打开项目,把.dll文件放入项目中: 2.在工具栏中添加一个自定义选项卡
- 在ASP.NET项目中使用CKEditor
CKEditor是什么 CKEidtor是一个在线富文本编辑器,可以将让用户所见即所得的获得编辑在线文本,编辑器或自动将用户编辑的文字格式转换成html代码. 在ASP.NET工程中添加CKEdito ...
随机推荐
- Opengl-法线贴图(用来细化表面的表现表现的凹凸)
我们通过这张图可以看出来,使用了法线贴图的物体表面更有细节更逼真,其实这就是发现贴图的作用,没什么钻牛角尖的. 其实表面没有凹凸的情况是因为我们把表面一直按照平整来做的,要想突出这个表面的凹凸就要用到 ...
- JavaScript是如何工作的(一)
简评:JavaScript 是越来越受欢迎了,很多团队都在采用这些语言工作.前端.后端.嵌入式设备等等,都可以看见它的身影.虽然我们知其然,但又知其所以然吗? 大家应该都知道 JavaScript 是 ...
- songCMS 3.15 cookie SQLINJ
./code/profile.php ... $db = new db(); $SQL = "SELECT * FROM `{$dbprefix}user` WHERE `ID` = {$_ ...
- 什么是SNAT
SNAT是源地址转换,其作用是将ip数据包的源地址转换成另外一个地址,可能有人觉得奇怪,好好的为什么要进行ip地址转换啊,为了弄懂这个问题,我们要看一下局域网用户上公网的原理,假设内网主机A(192. ...
- 【快速上手】Git的使用教程
创建Git仓库 git init 查看当前仓库情况 git status 添加修改 git add (file) or git add . 查看未提交的修改 git diff 撤销提交操作 git r ...
- 【OpenCv-Python】Getting Started with Images
1.1读入图像 使用函数 cv2.imread() 读入图像.这幅图像应该在此程序的工作路径,或者给函数提供一个完整的路径,第二个参数是要告诉函数应该如何读取这幅图片. cv2.IMREAD_COLO ...
- Ambari2.7.4+HDP3.1.4安装 Centos7离线安装
一. Ambari等简单介绍 1.1Ambari Ambari是一种基于Web的工具,支持Apache Hadoop集群的创建 .管理和监控. Ambari已支持大多数Hadoop组件,包括HDFS. ...
- CollectionUtils工具类
CollectionUtils工具类 这篇讲的CollectionUtils工具类是在apache下的,可以使代码更加简洁和安全. 使用前需导入依赖 <dependency> <gr ...
- 全差分运算放大器ADA4930的分析(2)
前面解释了在ADA4930组成的单端转差分电路的输入电阻RIN的大小,可知当RF=RG=1KΩ的时候,RIN=1.33KΩ. 图1单端转差分电路 如图1所示,假设信号源为2V VPP的信号,信号源的内 ...
- 关于HTTP那些事
写这篇文章的原因 记录前端性能优化用到的关键概念 简化大家对HTTP的学习 大家或许面试的时候可以用得到哦 HTTP是什么 Web的应用层协议(超文本传输协议HyperText Transfer Pr ...