SameSite 쿠키 및 OWIN(Open Web Interface for .NET)

작성자: Rick Anderson

SameSite 는 CSRF(교차 사이트 요청 위조) 공격에 대한 일부 보호를 제공하도록 설계된 IETF 초안입니다. SameSite 2019 초안:

  • 쿠키를 기본적으로 처리 SameSite=Lax 합니다.
  • 사이트 간 배달을 사용하도록 설정하기 위해 명시적으로 어설션 SameSite=None 하는 쿠키를 로 Secure표시해야 합니다.

Lax 는 대부분의 앱 쿠키에 대해 작동합니다. OIDC(OpenID Connect) 및 WS-Federation과 같은 일부 형태의 인증은 기본적으로 POST 기반 리디렉션으로 설정됩니다. POST 기반 리디렉션은 브라우저 보호를 트리거 SameSite 하므로 SameSite 이러한 구성 요소에 대해 사용하지 않도록 설정됩니다. 대부분의 OAuth 로그인은 요청 흐름 방식의 차이로 인해 영향을 받지 않습니다. 다른 모든 구성 요소는 기본적으로 설정 SameSite되지 않으며 클라이언트 기본 동작(이전 또는 신규)을 사용합니다.

매개 변수는 None 이전 2016 초안 표준 (예: iOS 12)을 구현한 클라이언트와 호환성 문제를 일으킵니다. 이 문서의 이전 브라우저 지원을 참조하세요.

쿠키를 내보내는 각 OWIN 구성 요소는 적절한지 SameSite 여부를 결정해야 합니다.

이 문서의 ASP.NET 4.x 버전은 ASP.NET SameSite 쿠키 작업을 참조하세요.

SameSite를 통한 API 사용

Microsoft.Owin 에는 자체 SameSite 구현이 있습니다.

  • 이는 의 System.Web에 직접 종속되지 않습니다.
  • SameSite 는 패키지 .NET 4.5 이상에서 Microsoft.Owin 대상으로 지정할 수 있는 모든 버전에서 작동합니다.
  • SystemWebCookieManager 구성 요소만 클래스와 System.WebHttpCookie 직접 상호 작용합니다.

SystemWebCookieManager는 지원을 사용하도록 설정하는 SameSite .NET 4.7.2 System.Web API와 동작을 변경하는 패치에 따라 달라집니다.

사용 SystemWebCookieManager 이유는 OWIN 및 System.Web 응답 쿠키 통합 문제에 설명되어 있습니다. SystemWebCookieManager 에서 System.Web를 실행할 때 권장됩니다.

다음 코드는 을 로 설정합니다SameSite.Lax

owinContext.Response.Cookies.Append("My Key", "My Value", new CookieOptions()
{
    SameSite = SameSiteMode.Lax
});

다음 API는 를 사용합니다 SameSite.

기록 및 변경 내용

Microsoft.OwinSameSite 2016 초안 표준을 지원하지 않았습니다.

SameSite 2019 초안에 대한 지원은 4.1.0 이상에서 Microsoft.Owin 만 사용할 수 있습니다. 이전 버전에 대한 패치는 없습니다.

사양의 SameSite 2019 초안:

  • 2016 초안과 이전 버전 호환이 되지 않습니다. 자세한 내용은 이 문서의 이전 브라우저 지원을 참조하세요.
  • 쿠키가 기본적으로 처리됨을 SameSite=Lax 지정합니다.
  • 사이트 간 배달을 사용하도록 설정하기 위해 명시적으로 어설션 SameSite=None 하는 쿠키를 로 Secure표시하도록 지정합니다. None은 옵트아웃할 새 항목입니다.
  • 2020년 2월에 기본적으로 Chrome에서 사용하도록 예약됩니다. 브라우저가 2019년의 이 표준으로 이동하기 시작했습니다.
  • KB 문서에 설명된 대로 발급된 패치에서 지원됩니다. 자세한 내용은 .NET Framework SameSite를 지원하는 KB 문서를 참조하세요.

이전 브라우저 지원

2016 SameSite 표준에서는 알 수 없는 값을 값으로 SameSite=Strict 처리해야 합니다. 2016 SameSite 표준을 지원하는 이전 브라우저에서 액세스한 앱은 값None이 인 SameSite 속성을 가져올 때 중단될 수 있습니다. 웹앱은 이전 브라우저를 지원하려는 경우 브라우저 검색을 구현해야 합니다. User-Agents 값은 휘발성이 높고 자주 변경되기 때문에 ASP.NET 브라우저 검색을 구현하지 않습니다. ICookieManager의 확장 지점을 사용하면 User-Agent 특정 논리를 연결할 수 있습니다.

Startup.Configuration에서 다음과 유사한 코드를 추가합니다.

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.UseOpenIdConnectAuthentication(
             new OpenIdConnectAuthenticationOptions
             {
                 // … Your preexisting options … 
                 CookieManager = new SameSiteCookieManager(
                                     new SystemWebCookieManager())
             });

        // Remaining code removed for brevity.

위의 코드에는 .NET 4.7.2 이상 SameSite 패치가 필요합니다.

다음 코드는 의 구현 예제를 SameSiteCookieManager보여줍니다.

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 == Microsoft.Owin.SameSiteMode.None 
                             && DisallowsSameSiteNone(context))
        {
            options.SameSite = null;
        }
    }

앞의 샘플에서 는 DisallowsSameSiteNone 메서드에서 호출됩니다 CheckSameSite . DisallowsSameSiteNone 는 사용자 에이전트가 를 지원하지 SameSiteNone않는지 검색하는 사용자 메서드입니다.

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

다음 코드는 샘플 DisallowsSameSiteNone 메서드를 보여 줍니다.

경고

다음 코드는 데모용으로만 사용할 수 있습니다.

  • 완료되지 않은 것으로 간주됩니다.
  • 유지 관리되거나 지원되지 않습니다.
public static bool DisallowsSameSiteNone(IOwinContext context)
{
    var userAgent = context.Request.Headers["User-Agent"];
    
    if (string.IsNullOrEmpty(userAgent))
    {
        return 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"))
    {
        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;
}

SameSite 문제에 대한 앱 테스트

타사 로그인 등 원격 사이트와 상호 작용하는 앱은 다음 작업을 수행해야 합니다.

SameSite 동작에 옵트인할 수 있는 클라이언트 버전을 사용하여 웹앱을 테스트합니다. Chrome, Firefox 및 Chromium Edge에는 테스트에 사용할 수 있는 새 옵트인 기능 플래그가 있습니다. 앱이 패치를 적용한 SameSite 후 이전 클라이언트 버전, 특히 Safari에서 테스트합니다. 자세한 내용은 이 문서의 이전 브라우저 지원을 참조하세요.

Chrome으로 테스트

Chrome 78+는 일시적인 완화를 제공하기 때문에 잘못된 결과를 제공합니다. Chrome 78 이상 임시 완화를 사용하면 쿠키가 2분 미만인 것을 허용합니다. 적절한 테스트 플래그를 사용하도록 설정하면 Chrome 76 또는 77에서 더 정확한 결과를 얻을 수 있습니다. 새 SameSite 동작을 테스트하려면 사용으로 전환 chrome://flags/#same-site-by-default-cookies 합니다. Chrome(75 이하) 이전 버전이 새 None 설정에 실패했음이 보고됩니다. 이 문서의 이전 브라우저 지원을 참조하세요.

Google은 이전 Chrome 버전을 사용하도록 설정할 수 없습니다. Chromium 다운로드의 지침에 따라 이전 버전의 Chrome을 테스트합니다. 이전 버전의 Chrome을 검색하여 제공된 링크에서 Chrome을 다운로드하지 마세요.

Safari를 사용한 테스트

Safari 12는 이전 초안을 엄격하게 구현했으며 새 None 값이 쿠키에 있으면 실패합니다. None은 이 문서에서 이전 브라우저를 지원하는 브라우저 검색 코드를 통해 방지됩니다. MSAL 또는 사용 중인 라이브러리를 사용하여 Safari 12, Safari 13 및 WebKit 기반 OS 스타일 로그인을 테스트합니다. 문제는 기본 OS 버전에 따라 달라집니다. OSX Mojave(10.14) 및 iOS 12는 새 SameSite 동작과 호환성 문제가 있는 것으로 알려져 있습니다. OS를 OSX Catalina(10.15) 또는 iOS 13으로 업그레이드하면 문제가 해결됩니다. Safari에는 현재 새 사양 동작을 테스트하기 위한 옵트인 플래그가 없습니다.

Firefox로 테스트

새 표준에 대한 Firefox 지원은 기능 플래그 network.cookie.sameSite.laxByDefault를 사용하여 about:config 페이지에서 옵트인하여 버전 68 이상에서 테스트할 수 있습니다. 이전 버전의 Firefox와의 호환성 문제에 대한 보고서가 없습니다.

Edge 브라우저를 사용한 테스트

Edge는 이전 SameSite 표준을 지원합니다. Edge 버전 44에는 새로운 표준과의 알려진 호환성 문제가 없습니다.

Edge(Chromium)를 사용한 테스트

SameSite 플래그는 페이지에 edge://flags/#same-site-by-default-cookies 설정됩니다. Edge Chromium에서 호환성 문제가 검색되지 않았습니다.

Electron을 사용하여 테스트

Electron 버전에는 이전 버전의 Chromium이 포함되어 있습니다. 예를 들어 Teams에서 사용하는 Electron 버전은 이전 동작을 나타내는 Chromium 66입니다. 제품이 사용하는 Electron 버전과 고유한 호환성 테스트를 수행해야 합니다. 다음 섹션에서 이전 브라우저 지원을 참조하세요.

추가 자료