재우니의 블로그

ASP.NET 및 ASP.NET Core에서 예정된 SameSite 쿠키 변경 사항

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

 

ASP.NET Blog | Upcoming SameSite Cookie Changes in ASP.NET and ASP.NET Core

Breaking changes to ASP.NET SameSite Cookie behavior.

devblogs.microsoft.com

SameSite는 HTTP 쿠키에 대한 2016 확장입니다CSRF (Cross Site Request Forgery)를 완화하기위한 것입니다. 원래 디자인은 쿠키에 새로운 SameSite 속성을 추가하여 사용할 수있는 옵트 인 기능이었습니다. Lax와 Strict의 두 값이있었습니다. 값을 Lax로 설정하면 쿠키가 동일한 사이트 내 탐색시 또는 다른 사이트에서 사이트로 GET 탐색을 통해 전송되어야 함을 나타냅니다. Strict 값은 쿠키를 동일한 사이트에서만 발생하는 요청으로 제한했습니다. 속성을 전혀 설정하지 않으면 요청에서 쿠키가 흐르는 방식에 제한이 없습니다. OpenIdConnect 인증 작업 (예 : 로그인, 로그 아웃) 및 외부 사이트에서 작업을 요청하는 사이트로 POST 요청을 보내는 기타 기능은 상관 및 / 또는 CSRF 보호를 위해 쿠키를 사용할 수 있습니다. 이러한 작업은 속성을 전혀 설정하지 않음으로써 SameSite를 옵트 아웃해야합니다.

Google은 이제 표준을 업데이트하고 있습니다예정된 Chrome 버전에서 제안 된 변경 사항을 구현합니다. 변경하면 새 SameSite 값인 "없음"이 추가되고 기본 동작이 "Lax"로 변경됩니다. 이로 인해 OpenIdConnect 로그인 및 웹 사이트가 신뢰할 수있는 다른 기능이 손상 될 수 있습니다. 이러한 기능은 SameSite 속성 값이 "None"으로 설정된 쿠키를 사용해야합니다. 그러나 원래 표준을 준수하고 새 값을 인식하지 못하는 브라우저는 SameSite 표준에 따라 새 표준을 사용하는 브라우저와는 다른 동작을합니다. 브라우저가 SameSite에 대한 값을 볼 경우 해당 값을 "엄격한". 즉, .NET 웹 사이트에서 새 없음 값을 보낼지 또는 속성을 전혀 보내지 않을지를 결정하기 위해 사용자 에이전트 스니핑을 추가해야합니다.

.NET은 .NET 4.7.2 및 .NET Core 2.1 이상에서 SameSite 속성 동작의 동작을 변경하여 Google의 새로운 가치 도입을 반영하기 위해 업데이트를 발행합니다. .NET Framework의 업데이트는 12 월 10 일에 제공 될 예정입니다. .NET Core 업데이트는 11 월 초 미리보기 1부터 .NET Core 3.1에서 사용할 수 있습니다. .NET 3.0 및 2.1 업데이트는 11 월 19 일에 출시 될 예정입니다.

.NET Core 3.1에는 SameSite 속성을 설정하지 않는 업데이트 된 열거 정의 SameSite.Unspecified가 포함됩니다.

Microsoft.Owin v4.1 및 .NET Core 용 OpenIdConnect 미들웨어는 .NET Framework 및 .NET 업데이트와 동시에 업데이트되지만 사용자 에이전트 스니핑 코드를 프레임 워크에 도입 할 수는 없습니다. 사이트 코드. 에이전트 스니핑의 구현은 사용중인 ASP.NET 또는 ASP.NET Core 버전과 지원하려는 브라우저에 따라 다릅니다.

Microsoft.Owin 4.1.0이 포함 된 ASP.NET 4.7.2의 경우 에이전트 스니핑은 ICookieManager를 사용하여 구현할 수 있습니다 .

public class SameSiteCookieManager : ICookieManager
{
  private readonly ICookieManager _innerManager;

  public SameSiteCookieManager() : this(new CookieManager())
  {
  }

  public SameSiteCookieManager(ICookieManager innerManager)
  {
    _innerManager = innerManager;
  }

  public void AppendResponseCookie(IOwinContext context, string key, string value,
                                   CookieOptions options)
  {
    CheckSameSite(context, options);
    _innerManager.AppendResponseCookie(context, key, value, options);
  }

  public void DeleteCookie(IOwinContext context, string key, CookieOptions options)
  {
    CheckSameSite(context, options);
    _innerManager.DeleteCookie(context, key, options);
  }

  public string GetRequestCookie(IOwinContext context, string key)
  {
    return _innerManager.GetRequestCookie(context, key);
  }

  private void CheckSameSite(IOwinContext context, CookieOptions options)
  {
    if (options.SameSite == SameSiteMode.None && DisallowsSameSiteNone(context))
    {
        options.SameSite = null;
    }
  }

  public static bool DisallowsSameSiteNone(IOwinContext context)
  {
    // TODO: Use your User Agent library of choice here.
    var userAgent = context.Request.Headers["User-Agent"];
    return userAgent.Contains("BrokenUserAgent") ||
           userAgent.Contains("BrokenUserAgent2")
  }
}

그런 다음 새로운 CookieManager를 사용하도록 OpenIdConnect 설정을 구성하십시오.

app.UseOpenIdConnectAuthentication(
    new OpenIdConnectAuthenticationOptions
    {
    // … Your preexisting options … 
    CookieManager = new SameSiteCookieManager(new SystemWebCookieManager())
});

SystemWebCookieManager가 제대로 작동하려면 .NET 4.7.2 이상의 SameSite 패치가 설치되어 있어야합니다.

ASP.NET Core의 경우 패치를 설치 한 다음 쿠키 정책 내에 에이전트 스니핑 코드를 구현해야합니다 . 3.1 이전 버전의 경우 SameSiteMode.Unspecified를 (SameSiteMode) (-1)로 바꿉니다.

private void CheckSameSite(HttpContext httpContext, CookieOptions options)
{
    if (options.SameSite == SameSiteMode.None)
    {
        var userAgent = httpContext.Request.Headers["User-Agent"].ToString();
        // TODO: Use your User Agent library of choice here.
        if (/* UserAgent doesn’t support new behavior */)
        {
               // For .NET Core < 3.1 set SameSite = (SameSiteMode)(-1)
               options.SameSite = SameSiteMode.Unspecified;
         }
    }
}

public void ConfigureServices(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);
    });
}

public void Configure(IApplicationBuilder app)
{
    app.UseCookiePolicy(); // Before UseAuthentication or anything else that writes cookies.
    app.UseAuthentication();
    // …
}

Azure Active Directory 팀에서 테스트 한 결과 Azure Active Directory에서 새 값을 이해하지 못하는 것으로 보이는 모든 일반 사용자 에이전트에 대해 다음 검사가 작동한다는 것을 알았습니다.

public static bool DisallowsSameSiteNone(string userAgent)
{
    // 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"))
    {
        return 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"))
    {
        return 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/5") || userAgent.Contains("Chrome/6"))
    {
        return true;
    }

    return false;
}

이 브라우저 목록은 결코 정식이 아니며 업데이트가 완료되면 시스템이 지원하는 공통 브라우저 및 기타 사용자 에이전트가 예상대로 작동하는지 확인해야합니다.

Chrome 80은 Chrome 79 베타에 추가 된 임시 완화를 포함하여 2020 년 2 월 또는 3 월에 새로운 동작 을 시작할 예정입니다. 완화없이 새로운 동작을 테스트하려면 Chromium 76을 사용하십시오. 이전 버전의 Chromium 을 다운로드 할 수 있습니다 .

Chrome이 2020 년 초에 새로운 동작을 수행 할 때까지 프레임 워크 버전을 업데이트 할 수없는 경우 ASP.NET 및 ASP.NET Core에서 사용하는 기본 암시 적 흐름 대신 OpenIdConnect 흐름을 코드 흐름으로 변경할 수 있습니다. 이는 임시 조치로 간주해야합니다.

업데이트 된 .NET Framework 및 .NET Core 버전이 11 월에 출시되면 Chrome의 변경 사항이 적용되기 전에 업데이트 계획을 시작하는 것이 좋습니다.

1 월 17 일 업데이트 : Azure는 .NET Same-Site Framework 업데이트 계획을 발표했습니다 .