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 ...
随机推荐
- react ReactDOMServer
此文章是翻译ReactDOMServer这篇React(版本v15.4.0)官方文档. ReactDOMServer 如果你用script 标签来使用React,这些顶级APIs 将会在全局React ...
- Vue数据绑定(一)
Contents Vue作为当下炙手可热的前端三大框架之一,一直都想深入研究一下其内部的实现原理,去学习MVVM模式的精髓.如果说MVVM是当下最流行的图形用户界面开发模式,那么数据绑定则是这一模式的 ...
- JavaScript中的innerHTML属性的使用
*/ * Copyright (c) 2016,烟台大学计算机与控制工程学院 * All rights reserved. * 文件名:text.html * 作者:常轩 * 微信公众号:Worldh ...
- Java入门教程二(语言基础)
常量与变量 常量值又称为字面常量,它是通过数据直接表示 常量 实型常量值 Java 的实型常量值主要有如下两种形式 十进制数形式:由数字和小数点组成,且必须有小数点,如 12.34.-98.0 科学记 ...
- 在命令行中使用pushd和popd进行快速切换目录
当频繁的切换三个或三个以上的目录的时候,可以使用pushd命令.每次使用目录路径被存储在栈中,然后用pushd和popd操作在目录之间切换. 例如: [root@gameserver1 ~]# pus ...
- AI:拿来主义——预训练网络(二)
上一篇文章我们聊的是使用预训练网络中的一种方法,特征提取,今天我们讨论另外一种方法,微调模型,这也是迁移学习的一种方法. 微调模型 为什么需要微调模型?我们猜测和之前的实验,我们有这样的共识,数据量越 ...
- Vue双向绑定的实现原理系列(三):监听器Observer和订阅者Watcher
监听器Observer和订阅者Watcher 实现简单版Vue的过程,主要实现{{}}.v-model和事件指令的功能 主要分为三个部分 github源码 1.数据监听器Observer,能够对数据对 ...
- tensorflow feature_column踩坑合集
踩坑内容包含以下 feature_column的输入输出类型,用一个数据集给出demo feature_column接estimator feature_column接Keras feature_co ...
- AOP和spring AOP学习记录
AOP基本概念的理解 面向切面AOP主要是在编译期或运行时,对程序进行织入,实现代理, 对原代码毫无侵入性,不破坏主要业务逻辑,减少程序的耦合度. 主要应用范围: 日志记录,性能统计,安全控制,事务处 ...
- AX2012/D365 SSRS报表开发
大家好,好久没有做SSRS报表了,近期刚好有做2张,就整理起来供初学者参考. AX中SSRS报表开发的框架,父类非常多,这里跟大家简单分享2种比较常用的场景供大家使用. 1.简单的过滤字段,无特殊过滤 ...