• Cookie的SameSite策略


    SameSite是2016年对HTTP cookie的扩展旨在减轻跨站点请求伪造(CSRF)。原始设计是一种选择加入功能,可以通过向cookie添加新的SameSite属性来使用。Google发布的新版本将实施SameSite策略,下面将针对SameSite做个了解。

    一、CSRF

    1、CSRF是什么?

    跨站请求伪造(英语:Cross-site request forgery),也被称为 one-click attack 或者 session riding,通常缩写为 CSRF 或者 XSRF, Cookie 往往用来存储用户的身份信息,恶意网站诱导用户在当前已登录的Web应用程序上执行操作,获取Cookie中的信息,发送恶意请求。跟跨网站脚本(XSS)相比,XSS 利用的是用户对指定网站的信任,CSRF 利用的是网站对用户网页浏览器的信任。

    简单地说,是攻击者通过一些技术手段欺骗用户的浏览器去访问一个自己曾经认证过的网站并运行一些操作(如发邮件,发消息,甚至财产操作如转账和购买商品)。由于浏览器曾经认证过,所以被访问的网站会认为是真正的用户操作而去运行。这利用了web中用户身份验证的一个漏洞:简单的身份验证只能保证请求发自某个用户的浏览器,却不能保证请求本身是用户自愿发出的。

    2、CSRF示例

    假如一家银行用以运行转账操作的URL地址如下:
    http://www.examplebank.com/withdraw?account=AccoutName&amount=1000&for=PayeeName
    那么,一个恶意攻击者可以在另一个网站上放置如下代码: 
    <img src="http://www.examplebank.com/withdraw?account=Alice&amount=1000&for=Badman">

    如果有账户名为Alice的用户访问了恶意站点,而她之前刚访问过银行不久,登录信息尚未过期,那么她就会损失1000资金。

    这种恶意的网址可以有很多种形式,藏身于网页中的许多地方。此外,攻击者也不需要控制放置恶意网址的网站。例如他可以将这种地址藏在论坛,博客等任何用户生成内容的网站中。这意味着如果服务端没有合适的防御措施的话,用户即使访问熟悉的可信网站也有受攻击的危险。透过例子能够看出,攻击者并不能通过CSRF攻击来直接获取用户的账户控制权,也不能直接窃取用户的任何信息。他们能做到的,是欺骗用户浏览器,让其以用户的名义运行操作。

    3、CSRF的原理

      

    从上图可以看出,要完成一次CSRF攻击,受害者必须依次完成两个步骤:

      1.登录银行affectedBank.com,并在本地生成Cookie。

      2.在不登出affectedBank.com的情况下,访问危险网站Sns.com。   

    4、CSRF的防御

    CSRF的防御可以从服务端和客户端两方面着手,现在一般的CSRF防御都在服务端进行。

    (1)检查Referer字段

    • 原理

    HTTP头中有一个Referer字段,这个字段用以标明请求来源于哪个地址。以上文银行操作为例,Referer字段地址通常应该是转账按钮所在的网页地址,应该也位于www.examplebank.com之下。而如果是CSRF攻击传来的请求,Referer字段会是包含恶意网址的地址,不会位于www.examplebank.com之下,这时候服务器就能识别出恶意的访问。
    • 优点

    简单易行,工作量低,仅需要在关键访问处增加一步校验。
    • 缺点

    这种办法也有其局限性,因其完全依赖浏览器发送正确的Referer字段。虽然http协议对此字段的内容有明确的规定,但并无法保证来访的浏览器的具体实现,亦无法保证浏览器没有安全漏洞影响到此字段。并且也存在攻击者攻击某些浏览器,篡改其Referer字段的可能。

    (2)添加校验token

    由于CSRF的本质在于攻击者欺骗用户去访问自己设置的地址,所以如果要求在访问敏感数据请求时,要求用户浏览器提供不保存在cookie中,并且攻击者无法伪造的数据作为校验,那么攻击者就无法再运行CSRF攻击。这种数据通常是窗体中的一个数据项。服务器将其生成并附加在窗体中,其内容是一个伪随机数。当客户端通过窗体提交请求时,这个伪随机数也一并提交上去以供校验。正常的访问时,客户端浏览器能够正确得到并传回这个伪随机数,而通过CSRF传来的欺骗性攻击中,攻击者无从事先得知这个伪随机数的值,服务端就会因为校验token的值为空或者错误,拒绝这个可疑请求。

    二、SameSite 属性

    Cookie 的SameSite属性用来限制第三方 Cookie,从而减少安全风险。谷歌浏览器已经实施SameSite策略。它可以设置如下三个值:Strict、Lax、None

    1、Strict

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

    Set-Cookie: CookieName=CookieValue; SameSite=Strict;

    这个规则过于严格,可能造成非常不好的用户体验。比如,当前网页有一个 GitHub 链接,用户点击跳转就不会带有 GitHub 的 Cookie,跳转过去总是未登陆状态。

    2、Lax

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

    Set-Cookie: CookieName=CookieValue; SameSite=Lax;

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

    请求类型示例正常情况Lax
    链接 <a href="..."></a> 发送 Cookie 发送 Cookie
    预加载 <link rel="prerender" href="..."/> 发送 Cookie 发送 Cookie
    GET 表单 <form method="GET" action="..."> 发送 Cookie 发送 Cookie
    POST 表单 <form method="POST" action="..."> 发送 Cookie 不发送
    iframe <iframe src="..."></iframe> 发送 Cookie 不发送
    AJAX $.get("...") 发送 Cookie 不发送
    Image <img src="..."> 发送 Cookie 不发送

    设置了StrictLax以后,基本就杜绝了 CSRF 攻击。当然,前提是用户浏览器支持 SameSite 属性。新谷歌浏览器支持SameSite策略,并默认采用“Lax”

    3、None

    Chrome 计划将Lax变为默认设置。这时,网站可以选择显式关闭SameSite属性,将其设为None。不过,前提是必须同时设置Secure属性(Cookie 只能通过 HTTPS 协议发送),否则无效。

    下面的设置无效:

    Set-Cookie: widget_session=abc123; SameSite=None

    下面的设置有效:

    Set-Cookie: widget_session=abc123; SameSite=None; Secure

    三、Chrome禁用掉SameSite

    Google决定推进这项特性的使用。谷歌浏览器将支持SameSite策略。如果你使用的是谷歌浏览器,如果想保持之前处理cookie的方式,Chrome要求显示指定SameSite=None。否则Chrome默认将视作SameSite=Lax。

    如果你想禁用SameSite策略,请注意需要同时设置Secure属性。谷歌浏览器上的禁用操作如下:

    1. 在chrome浏览器地址栏输入chrome://flags并回车
    2. 在搜索栏中输入SameSite by default cookies搜索,并禁用如图中的两项设置,改为Disabled即可
    3. 点击右下键ReLaunch重启浏览器即可

    四、Chrome的SameSite策略对Ids4的影响以及解决方案

    1、影响

    如果你有一个单页应用(SPA),使用另一域名的认证服务(比如IdentityServer4)进行身份认证,并且使用了所谓的静默令牌刷新的话,你将受影响。登录到认证服务的时候,它会为当前用户设置会话cookie,这个cookie属于认证服务域名。认证流程结束之后,另一域名会收到认证服务颁发的access token,有效期通常不会太长。当access token过期之后,应用无法访问api,用户需要频繁的登录,体验十分差。

    2、解决方案

    为了避免这一情况,我们可以使用refresh_token实现静默刷新。应用创建一个用户不可见的iframe,在iframe中进行新的认证流程。iframe中加载了认证服务站点,当浏览器发送会话cookie的时候,认证服务识别出当前用户然后颁发新的token。但是SPA网站使用iframe嵌入了认证服务站点的内容,这就是一个跨站请求,只有将iframe中属于认证服务站点的cookie设置为SameSite=None,Chrome才会将iframe中的cookie发送到认证服务。否则,token静默刷新将无法正常运行。

    五、ASP.NET Core 中的 SameSite

    1、定义类SameSiteExtention

    using Microsoft.AspNetCore.Builder;
    using Microsoft.AspNetCore.Http;
    using Microsoft.Extensions.DependencyInjection;
    
    namespace HyIdentityServer.Extention
    {
        // 文档说明 https://devblogs.microsoft.com/aspnet/upcoming-samesite-cookie-changes-in-asp-net-and-asp-net-core/
        public static partial class Extention
        {
            public static IServiceCollection AddSameSiteCookiePolicy(this IServiceCollection services)
            {
                services.Configure<CookiePolicyOptions>(options =>
                {
                    options.MinimumSameSitePolicy = SameSiteMode.Unspecified;
                    options.OnAppendCookie = cookieContext => CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
                    options.OnDeleteCookie = cookieContext => CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
                });
                return services;
            }
            private static void CheckSameSite(HttpContext httpContext, CookieOptions options)
            {
                if (options.SameSite == SameSiteMode.None)
                {
                    var userAgent = httpContext.Request.Headers["User-Agent"].ToString();
                    if (DisallowsSameSiteNone(userAgent))
                    {
                        // For .NET Core < 3.1 set SameSite = (SameSiteMode)(-1)
                        options.SameSite = SameSiteMode.Unspecified;
                    }
                }
            }
            private static bool DisallowsSameSiteNone(string userAgent)
            {
                bool result = false;
                // Cover all iOS based browsers here.This includes:
                // - Safari on iOS 12 for iPhone, iPod Touch, iPad
                // - WkWebview on iOS 12 for iPhone, iPod Touch, iPad
                // - Chrome on iOS 12 for iPhone, iPod Touch, iPad
                // All of which are broken by SameSite=None, because they use the iOS networking stack
                if (userAgent.Contains("CPU iPhone OS 12") || userAgent.Contains("iPad; CPU OS 12"))
                {
                    result = true;
                }
    
                // Cover Mac OS X based browsers that use the Mac OS networking stack. This includes:
                // - Safari on Mac OS X.
                // This does not include:
                // - Chrome on Mac OS X
                // Because they do not use the Mac OS networking stack.
                if (userAgent.Contains("Macintosh; Intel Mac OS X 10_14") &&
                    userAgent.Contains("Version/") && userAgent.Contains("Safari"))
                {
                    result = true;
                }
    
                // Cover Chrome 50-69, because some versions are broken by SameSite=None, 
                // and none in this range require it.
                // Note: this covers some pre-Chromium Edge versions, 
                // but pre-Chromium Edge does not require SameSite=None.
                if (userAgent.Contains("Chrome"))
                {
                    result = true;
                }
                return result;
            }
        }
    }
    

    2、Startup.cs中的注入

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSameSiteCookiePolicy();
    }
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        app.UseCookiePolicy();
    }

    参考资料:

    1、https://docs.microsoft.com/zh-cn/aspnet/core/security/samesite?view=aspnetcore-3.1

    2、https://devblogs.microsoft.com/aspnet/upcoming-samesite-cookie-changes-in-asp-net-and-asp-net-core/

    3、https://www.cnblogs.com/holdengong/p/12591645.html

    4、http://www.ruanyifeng.com/blog/2019/09/cookie-samesite.html

  • 相关阅读:
    Mysql(7) _常用函数
    Mysql(6)_ 帮助的使用
    Mysql(5)_ 基本数据类型-时间
    Mysql(4)_整型和浮点型
    1 HTTP请求头Header及其作用详解
    Java(35) _JDBC批量插入数据二
    Java(34)_ 用JDBC批量向数据库插入语句
    Java(33)_ JDBC指针移动
    Mysql(3)_ Mycat简介
    Mysql(2)_ binlog文件
  • 原文地址:https://www.cnblogs.com/qtiger/p/14592476.html
Copyright © 2020-2023  润新知