Práce s weby SameSite cookie v ASP.NET Core

Autor: Rick Anderson

SameSite je koncept standardu IETF navržený tak, aby poskytoval určité ochrany proti útokům CSRF (Cross-Site Request Forgery). Koncept byl původně v roce 2016aktualizován v roce 2019. Aktualizovaný standard není zpětně kompatibilní s předchozím standardem, z následujících je patrnější rozdíl:

  • CookieS bez hlavičky SameSite se ve SameSite=Lax výchozím nastavení zachází jako s hlavičkou .
  • SameSite=None musí být použit k povolení použití mezi cookie weby.
  • CookieTento kontrolní SameSite=None výraz musí být také označený jako Secure .
  • U aplikací, které používají , může docházet k problémům s nebo , protože se s nimi zachází <iframe> sameSite=Lax jako se sameSite=Strict cookie <iframe> scénáři mezi weby.
  • Standard roku SameSite=None 2016 hodnotu nepomáhou a způsobí, že některé implementace zachází cookie jako s SameSite=Strict . Viz Podpora starších prohlížečů v tomto dokumentu.

Nastavení SameSite=Lax funguje pro většinu cookie aplikací. Některé formy ověřování, jako je OpenID Připojení (OIDC) a WS-Federation, jsou ve výchozím nastavení na přesměrování založená na protokolu POST. Přesměrování na základě POST aktivují ochranu prohlížeče SameSite, takže pro tyto komponenty je zakázaná možnost SameSite. Většina přihlášení OAuth není ovlivněná kvůli rozdílům v tocích požadavků.

Každá ASP.NET Core komponenta, která generuje cookie , musí rozhodnout, jestli je sameSite vhodné.

SameSite a Identity

IdentityASP.NET Core s výjimkou pokročilých cookie scénářů, jako je nebo integrace, do značné míry IFrames nejsou ovlivněny weby OpenIdConnect SameSite.

Pokud používáte Identity , nepřidejte žádné cookie zprostředkovatele ani nevolejte services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) , postará se o Identity to.

Ukázkový kód testu SameSite

Následující ukázku si můžete stáhnout a otestovat:

Ukázka Dokument
Stránky .NET Razor Core Razorukázka SameSite stránek 3,1 cookie ASP.NET Core

Podpora .NET Core pro stejný atributSite

.NET Core 2.2 a novější podporují koncept standardu SameSite z roku 2019 od vydání aktualizací v prosinci 2019. Vývojáři mohou programově řídit hodnotu atributu sameSite pomocí HttpCookie.SameSite vlastnosti . Nastavení vlastnosti SameSite na Strict, Lax nebo None má za výsledek zápis hodnot v síti pomocí cookie . Nastavení rovny značí, že v síti by neměl být zahrnutý žádný (SameSiteMode)(-1) stejný atributSite. cookie

var cookieOptions = new CookieOptions
{
    // Set the secure flag, which Chrome's changes will require for SameSite none.
    // Note this will also require you to be running on HTTPS.
    Secure = true,

    // Set the cookie to HTTP only which is good practice unless you really do need
    // to access it client side in scripts.
    HttpOnly = true,

    // Add the SameSite attribute, this will emit the attribute with a value of none.
    // To not emit the attribute at all set
    // SameSite = (SameSiteMode)(-1)
    SameSite = SameSiteMode.None
};

// Add the cookie to the response cookie collection
Response.Cookies.Append("MyCookie", "cookieValue", cookieOptions);

.NET Core 3.1 a novější podporují aktualizované hodnoty SameSite a přidávají do výčtu SameSiteMode.Unspecified další SameSiteMode hodnotu výčtu. Tato nová hodnota značí, že by se s . cookie

Změny chování prosincové opravy

Konkrétní změna chování pro .NET Framework a .NET Core 2.1 je způsob, jakým SameSite vlastnost interpretuje None hodnotu. Před opravou se hodnota znamená "Vůbec nevysílat atribut", znamená to za opravou None "Emitovat atribut s hodnotou None ". Po SameSite opravě hodnota (SameSiteMode)(-1) způsobí, že atribut nebude emitován.

Výchozí hodnota SameSite pro ověřování pomocí formulářů a stav relace se změnila cookie z None na Lax .

Využití rozhraní API se sameSite

HttpContext.Response. Cookie s.Append má výchozí hodnotu , což znamená, že se do atributu SameSite nepřidá žádný atribut a klient použije jeho výchozí chování Unspecified (Lax pro nové prohlížeče, u starých cookie žádný). Následující kód ukazuje, jak změnit hodnotu cookie SameSite na SameSiteMode.Lax :

HttpContext.Response.Cookies.Append(
                     "name", "value",
                     new CookieOptions() { SameSite = SameSiteMode.Lax });

Všechny ASP.NET Core komponenty, které vysílají , přepíší předchozí výchozí hodnoty nastavením cookie vhodným pro jejich scénáře. Přepsané předchozí výchozí hodnoty se nezměnily.

Součást cookie Výchozí
CookieBuilder SameSite Unspecified
Session Možnosti relace.Cookie Lax
CookieTempDataProvider CookieTempDataProviderOptions.Cookie Lax
IAntiforgery AntiforgeryOptions.Cookie Strict
Cookie Ověřování CookieMožnosti ověřování.Cookie Lax
AddTwitter TwitterOptions.State Cookie Lax
RemoteAuthenticationHandler<TOptions> RemoteAuthenticationOptions.CorrelationCookie None
AddOpenIdConnect OpenIdConnectOptions.NonceCookie None
HttpContext.Response. Cookie s.Append CookieOptions Unspecified

ASP.NET Core verze 3.1 a novější poskytuje následující podporu SameSite:

  • Předefinuje chování pro SameSiteMode.None vysílání SameSite=None
  • Přidá novou hodnotu SameSiteMode.Unspecified pro vynechání atributu SameSite.
  • Všechna cookie rozhraní API jsou ve výchozím nastavení nastavená na Unspecified . Některé komponenty, které cookie používají sady hodnot, které jsou pro své scénáře konkrétnější. Příklady najdete v tabulce výše.

V ASP.NET Core verze 3.0 a novějších se výchozí hodnoty SameSite změnily, aby nedocházelo ke konfliktu s nekonzistentními výchozími nastaveními klientů. Následující rozhraní API změnila výchozí hodnotu z na , aby se zabránilo vysílání SameSiteMode.Lax -1 atributu SameSite pro tyto cookie s:

Historie a změny

Podpora SameSite byla poprvé implementovaná v ASP.NET Core ve verzi 2.0 pomocí konceptu standardu z roku 2016. Výslovný souhlas byl ve standardu 2016. ASP.NET Core se přihlásit nastavením několika cookie s na výchozí Lax hodnotu. Po několika problémech s ověřováním byla většina využití lokality SameSite zakázaná.

Opravy byly vydány v listopadu 2019 pro aktualizaci ze standardu z roku 2016 na standard z roku 2019. Koncept specifikace SameSite z roku 2019:

  • Není zpětně kompatibilní s konceptem z roku 2016. Další informace najdete v části Podpora starších prohlížečů v tomto dokumentu.
  • Určuje, cookie že s se ve výchozím nastavení SameSite=Lax zachází jako s .
  • Určuje, které explicitně prosoudí, aby bylo možné povolit doručování mezi cookie SameSite=None weby, by měly být označené jako Secure . None je nová položka pro odhlášení.
  • Je podporován opravami vydanými pro ASP.NET Core verze 2.1, 2.2 a 3.0. ASP.NET Core 3.1 má další podporu SameSite.
  • Chrome ve výchozím nastavení plánuje povolit v únoru 2020. V roce 2019 začaly na tento standard přechádovat prohlížeče.

Rozhraní API ovlivněná změnou z konceptu standardu SameSite z roku 2016 na koncept standardu z roku 2019

Podpora starších prohlížečů

Standard SameSite z roku 2016 vyžádá, aby neznámé hodnoty byly považovány za SameSite=Strict hodnoty. Aplikace, ke kterým se přistupuje ze starších prohlížečů, které podporují standard SameSite 2016, se mohou porušit, když zobrazí vlastnost SameSite s hodnotou None . Webové aplikace musí implementovat detekci prohlížeče, pokud mají v úmyslu podporovat starší prohlížeče. ASP.NET Core neimplementuje detekci prohlížeče, protože User-Agents hodnoty jsou vysoce nestálé a často se mění. Extension Point in Microsoft.AspNetCore.CookiePolicy umožňuje zapojení User-Agent logiky.

Do Startup.Configure přidejte kód, který volá před voláním , nebo UseCookiePolicy UseAuthentication libovolnou metodu, která zapisuje: cookie

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseCookiePolicy();
    app.UseAuthentication();
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}

Do Startup.ConfigureServices souboru přidejte kód podobný následujícímu:

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);
    });

    services.AddRazorPages();
}

private void CheckSameSite(HttpContext httpContext, CookieOptions options)
{
    if (options.SameSite == SameSiteMode.None)
    {
        var userAgent = httpContext.Request.Headers["User-Agent"].ToString();
        if (MyUserAgentDetectionLib.DisallowsSameSiteNone(userAgent))
        {
            options.SameSite = SameSiteMode.Unspecified;
        }
    }
}
public void ConfigureServices(IServiceCollection services)
{
    services.Configure<CookiePolicyOptions>(options =>
    {
        options.MinimumSameSitePolicy = (SameSiteMode)(-1);
        options.OnAppendCookie = cookieContext =>
            CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
        options.OnDeleteCookie = cookieContext =>
            CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
    });

    services.AddRazorPages();
}

private void CheckSameSite(HttpContext httpContext, CookieOptions options)
{
    if (options.SameSite == SameSiteMode.None)
    {
        var userAgent = httpContext.Request.Headers["User-Agent"].ToString();
        if (MyUserAgentDetectionLib.DisallowsSameSiteNone(userAgent))
        {
            options.SameSite = (SameSiteMode)(-1);
        }

    }
}

V předchozí ukázce je uživatelem dodaná knihovna, která zjišťuje, jestli uživatelský MyUserAgentDetectionLib.DisallowsSameSiteNone agent nepodporuje None SameSite:

if (MyUserAgentDetectionLib.DisallowsSameSiteNone(userAgent))
{
    options.SameSite = SameSiteMode.Unspecified;
}

Následující kód ukazuje ukázkovou DisallowsSameSiteNone metodu:

Upozornění

Následující kód je pouze pro ukázku:

  • Nemělo by se považovat za úplné.
  • Neudržuje se ani nepodporuje.
public static bool DisallowsSameSiteNone(string userAgent)
{
    // Check if a null or empty string has been passed in, since this
    // will cause further interrogation of the useragent to fail.
     if (String.IsNullOrWhiteSpace(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;
}

Testování aplikací pro problémy SameSite

Aplikace, které komunikují se vzdálenými weby, například prostřednictvím přihlášení třetí strany, musí:

Otestujte webové aplikace pomocí verze klienta, která se může přihlásit k novému chování SameSite. Chrome, Firefox a Chromium Edge mají nové příznaky funkcí pro výslovný souhlas, které je možné použít pro testování. Jakmile vaše aplikace použije opravy SameSite, otestujte ji se staršími verzemi klienta, zejména Safari. Další informace najdete v části Podpora starších prohlížečů v tomto dokumentu.

Testování pomocí Chromu

Chrome 78 nebo více poskytuje zavádějící výsledky, protože má dočasné omezení rizik. Dočasné omezení rizik pro Chrome 78 a více umožňuje cookie méně než dvě minuty. Chrome 76 nebo 77 s příslušnými povolenými testovacími příznaky poskytuje přesnější výsledky. Pokud chcete otestovat nové chování SameSite, přepněte chrome://flags/#same-site-by-default-cookies přepínač na Povoleno. U starších verzí Chromu (75 a novějších) se hlásí selhání s novým None nastavením. Viz Podpora starších prohlížečů v tomto dokumentu.

Google neposkytuje starší verze chromu. Postupujte podle pokynů v tématu Stažení Chromium a otestujte starší verze Chromu. Nestahovat Chrome z odkazů poskytovaných vyhledáváním starších verzí chromu.

Počínaje kanárovou verzí je možné dočasné omezení rizik lax+POST zakázat pro účely testování pomocí nového příznaku, který umožňuje testování webů a služeb v koncovém stavu funkce, u které bylo omezení rizik 80.0.3975.0 --enable-features=SameSiteDefaultChecksMethodRigorously odebráno. Další informace najdete v tématu Aktualizace Chromium Projects SameSite Updates.

Testování pomocí Safari

Safari 12 striktně implementuje předchozí koncept a selže, pokud None je nová hodnota v cookie . None se vyhnete prostřednictvím kódu pro detekci prohlížeče Podpora starších prohlížečů v tomto dokumentu. Testujte přihlášení ve stylu operačního systému safari 12, Safari 13 a WebKit pomocí knihovny MSAL, ADAL nebo knihovny, kterou používáte. Problém závisí na základní verzi operačního systému. Je známo, že OSX Mojave (10.14) a iOS 12 mají problémy s kompatibilitou s novým chováním SameSite. Upgradem operačního systému na OSX Catalina (10.15) nebo iOS 13 se problém vyřeší. Safari v současné době nemá příznak výslovného souhlasu pro testování chování nové specifikace.

Testování pomocí Prohlížeče Firefox

Podporu Firefoxu pro nový standard je možné testovat na verzi 68 nebo novější tím, že se na stránce přihlásíte s about:config příznakem funkce network.cookie.sameSite.laxByDefault . U starších verzí Prohlížeče Firefox se nenachádnou žádné problémy s kompatibilitou.

Testování pomocí prohlížeče Edge

Edge podporuje starý standard SameSite. Edge verze 44 nemá žádné známé problémy s kompatibilitou s novým standardem.

Testování pomocí Edge (Chromium)

Na stránce jsou nastavené příznaky edge://flags/#same-site-by-default-cookies SameSite. U edgeové aplikace nebyly zjištěny žádné problémy s Chromium.

Testování pomocí Electron

Verze Electron zahrnují starší verze Chromium. Například verze , kterou používá Electron Teams, je Chromium 66, která vykazuje starší chování. Musíte provést vlastní testování kompatibility s Electron verzí, kterou váš produkt používá. Další informace najdete v části Podpora starších prohlížečů.

Další zdroje informací