Arbeiten mit SameSite-cookies in ASP.NET Core

Von Rick Anderson

SameSite ist ein IETF-Entwurfsstandard, der einen gewissen Schutz vor Angriffen durch siteübergreifende Anforderungsfälschung (Cross-Site Request Forgery, CSRF) bieten soll. Ursprünglich wurde der Entwurfsstandard in 2016 entworfen und in 2019 aktualisiert. Der aktualisierte Standard ist nicht abwärtskompatibel mit dem vorherigen Standard, wobei die folgenden Unterschiede am deutlichsten sind:

  • Cookies ohne SameSite-Header werden standardmäßig als SameSite=Lax behandelt.
  • SameSite=None muss verwendet werden, um eine siteübergreifende cookie-Verwendung zu ermöglichen.
  • Cookies, die SameSite=None bestätigen, müssen auch als Secure markiert werden.
  • Bei Anwendungen, die <iframe> verwenden, kann es zu Problemen mit sameSite=Lax oder sameSite=Strictcookies kommen, da <iframe> als siteübergreifende Szenarien behandelt wird.
  • Der Wert SameSite=None ist nach dem Standard von 2016 nicht zulässig und führt dazu, dass einige Implementierungen solche cookies als SameSite=Strict behandeln. Weitere Informationen finden Sie unter Unterstützung älterer Browser in diesem Dokument.

Die Einstellung SameSite=Lax funktioniert für die meisten Anwendungs-cookies. Einige Formen der Authentifizierung wie OpenID Connect (OIDC) und Webdiensteverbund verwenden standardmäßig POST-basierte Umleitungen. Die POST-basierten Umleitungen lösen die SameSite-Browserschutzmaßnahmen aus, sodass SameSite für diese Komponenten deaktiviert ist. Die meisten OAuth-Anmeldungen sind davon nicht betroffen, da die Anforderungen unterschiedlich verlaufen.

Jede ASP.NET Core-Komponente, die cookies ausgibt, muss entscheiden, ob SameSite angemessen ist.

SameSite und Identity

ASP.NET Core Identity ist von SameSite-cookies weitgehend unbeeinflusst, außer bei erweiterten Szenarien wie die IFrames- oder OpenIdConnect-Integration.

Wenn Sie Identity verwenden, fügen Sie keinecookie-Anbieter hinzu und rufen services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) nicht auf. Identity übernimmt dies.

SameSite-Testbeispielcode

Das folgende Beispiel kann heruntergeladen und getestet werden:

Beispiel Dokument
.NET Core Razor Pages ASP.NET Core 3.1 Razor Pages: Beispiel für SameSite-cookies

.NET Core-Unterstützung für das sameSite-Attribut

.NET Core unterstützt den Entwurfsstandard von 2019 für SameSite. Entwickler können den Wert des sameSite-Attributs mithilfe der Eigenschaft HttpCookie.SameSite programmgesteuert steuern. Wenn Sie die Eigenschaft SameSite auf Strict, Lax oder None festlegen, werden diese Werte mit dem cookie in das Netzwerk geschrieben. Das Festlegen auf SameSiteMode.Unspecified bedeutet, dass kein sameSite-Attribut mit dem cookie gesendet werden soll.

    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.
        SameSite = SameSiteMode.None

        // The client should follow its default cookie policy.
        // SameSite = SameSiteMode.Unspecified
    };

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

API-Verwendung mit SameSite

HttpContext.Response.Cookies.Append ist standardmäßig auf Unspecified festgelegt, d. h. es wird kein SameSite-Attribut an das cookie angefügt und der Client verwendet sein Standardverhalten („Lax“ für neue Browser, „None“ für alte). Der folgende Code zeigt, wie Sie den cookie SameSite-Wert in SameSiteMode.Lax ändern:

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

Alle ASP.NET Core-Komponenten, die cookies ausgeben, setzen die vorangehenden Standardwerte mit Einstellungen außer Kraft, die für ihre Szenarien geeignet sind. Die außer Kraft gesetzten vorangehenden Standardwerte haben sich nicht geändert.

Komponente cookie Standard
CookieBuilder SameSite Unspecified
Session SessionOptions.Cookie Lax
CookieTempDataProvider CookieTempDataProviderOptions.Cookie Lax
IAntiforgery AntiforgeryOptions.Cookie Strict
Cookie Authentication CookieAuthenticationOptions.Cookie Lax
AddTwitter TwitterOptions.StateCookie Lax
RemoteAuthenticationHandler<TOptions> RemoteAuthenticationOptions.CorrelationCookie None
AddOpenIdConnect OpenIdConnectOptions.NonceCookie None
HttpContext.Response.Cookies.Append CookieOptions Unspecified

ASP.NET Core 3.1 und höher bietet die folgende SameSite-Unterstützung:

  • Definiert das Verhalten von SameSiteMode.None neu, um SameSite=None auszugeben.
  • Fügt einen neuen SameSiteMode.Unspecified-Wert hinzu, um das SameSite-Attribut auszulassen.
  • Alle APIs für cookies sind standardmäßig auf Unspecified eingestellt. Einige Komponenten, die cookies verwenden, legen Werte fest, die spezifischer für ihre Szenarien sind. Beispiele finden Sie in der obigen Tabelle.

In ASP.NET Core 3.0 und höher wurden die SameSite-Standardwerte geändert, um Konflikte mit inkonsistenten Clientstandardwerten zu vermeiden. Die folgenden APIs haben den Standard von SameSiteMode.Lax in -1 geändert, um zu vermeiden, dass ein SameSite-Attribut für diese cookies ausgegeben wird:

Verlauf und Änderungen

Die SameSite-Unterstützung wurde erstmals in ASP.NET Core 2.0 mithilfe des Entwurfsstandards von 2016 implementiert. Der Standard von 2016 wurde abonniert. ASP.NET Core wurde abonniert, indem mehrere cookies standardmäßig auf Lax festgelegt wurden. Nachdem mehrere Probleme mit der Authentifizierung aufgetreten waren, wurde der Großteil der SameSite-Nutzung deaktiviert.

Patches wurden im November 2019 veröffentlicht, um vom Standard von 2016 auf den Standard von 2019 zu aktualisieren. Der Entwurf von 2019 der SameSite-Spezifikation:

  • Er ist nicht abwärtskompatibel mit dem Entwurf von 2016. Weitere Informationen finden Sie unter Unterstützung älterer Browser in diesem Dokument.
  • Gibt an, dass cookies standardmäßig als SameSite=Lax behandelt werden.
  • Gibt an, dass cookies, die explizit SameSite=None bestätigen, um eine siteübergreifende Zustellung zu ermöglichen, als Secure markiert werden sollen. None ist ein neuer Eintrag zum Kündigen des Abonnements.
  • Wird von Patches für ASP.NET Core 2.1, 2.2 und 3.0 unterstützt. ASP.NET Core 3.1 und höher bietet zusätzliche Unterstützung für SameSite.
  • Wurde von Chrome standardmäßig im Februar 2020 aktiviert. Die Browser werden seit 2019 auf diesen Standard umgestellt.

APIs, die von der Änderung des SameSite-Entwurfsstandards von 2016 zum Entwurfsstandard von 2019 betroffen sind

Unterstützung älterer Browser

Der SameSite-Standard von 2016 schreibt vor, dass unbekannte Werte als SameSite=Strict-Werte behandelt werden müssen. Apps, auf die von älteren Browsern aus zugegriffen wird, die den SameSite-Standard von 2016 unterstützen, können unterbrochen werden, wenn sie eine SameSite-Eigenschaft mit einem Wert von None erhalten. Web-Apps müssen eine Browsererkennung implementieren, wenn sie ältere Browser unterstützen wollen. ASP.NET Core implementiert keine Browsererkennung, da die Werte von Benutzer-Agents sehr veränderlich sind und sich häufig ändern. Ein Erweiterungspunkt in Microsoft.AspNetCore.CookiePolicy ermöglicht die Integration von Logik, die für Benutzer-Agents spezifisch ist.

Fügen Sie in Program.cs Code hinzu, der UseCookiePolicy aufruft, bevor Sie UseAuthentication oder irgendeine Methode aufrufen, die cookies schreibt:

var builder = WebApplication.CreateBuilder(args);

builder.Services.Configure<CookiePolicyOptions>(options =>
{
    options.MinimumSameSitePolicy = SameSiteMode.Unspecified;
    options.OnAppendCookie = cookieContext =>
        CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
    options.OnDeleteCookie = cookieContext =>
        CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
});

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

    builder.Services.AddRazorPages();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

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

app.UseRouting();

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

app.MapRazorPages();

app.Run();

Fügen Sie in Program.cs einen Code ähnlich dem folgenden hervorgehobenen Code ein:

var builder = WebApplication.CreateBuilder(args);

builder.Services.Configure<CookiePolicyOptions>(options =>
{
    options.MinimumSameSitePolicy = SameSiteMode.Unspecified;
    options.OnAppendCookie = cookieContext =>
        CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
    options.OnDeleteCookie = cookieContext =>
        CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
});

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

    builder.Services.AddRazorPages();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

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

app.UseRouting();

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

app.MapRazorPages();

app.Run();

Im vorangehenden Beispiel ist MyUserAgentDetectionLib.DisallowsSameSiteNone eine vom Benutzer bereitgestellte Bibliothek, die erkennt, ob der Benutzer-Agent SameSite None nicht unterstützt:

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

Der folgende Code zeigt ein Beispiel für eine DisallowsSameSiteNone-Methode:

Warnung

Der folgende Code dient nur zur Demonstration:

  • Er sollte nicht als vollständig betrachtet werden.
  • Er wird nicht verwaltet oder unterstützt.
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;
}

Testen von Apps für SameSite-Probleme

Apps, die mit Remotestandorten interagieren, z. B. über die Anmeldung über Drittanbieter, müssen folgende Aktionen ausführen:

Testen Sie Web-Apps mithilfe einer Clientversion, die das neue SameSite-Verhalten abonnieren kann. Chrome, Firefox und Chromium Edge verfügen über neue Featureflags, die für Tests verwendet werden können. Nachdem Ihre App die SameSite-Patches angewendet hat, testen Sie sie mit älteren Clientversionen, insbesondere Safari. Weitere Informationen finden Sie unter Unterstützung älterer Browser in diesem Dokument.

Testen mit Chrome

Chrome 78+ liefert irreführende Ergebnisse, da es eine vorübergehende Risikominderung aufweist. Die temporäre Risikominderung von Chrome 78+ gestattet cookies, die weniger als zwei Minuten alt sind. Chrome 76 oder 77 mit den entsprechenden aktivierten Testflags liefert genauere Ergebnisse. Um das neue SameSite-Verhalten zu testen, schalten Sie chrome://flags/#same-site-by-default-cookies auf Aktiviert um. Bei älteren Versionen von Chrome (75 und niedriger) wird gemeldet, dass mit der neuen None-Einstellung ein Fehler auftritt. Weitere Informationen finden Sie unter Unterstützung älterer Browser in diesem Dokument.

Google stellt keine älteren Chrome-Versionen zur Verfügung. Befolgen Sie die Anweisungen unter Herunterladen von Chromium, um ältere Versionen von Chrome zu testen. Laden Sie Chrome nicht über Links herunter, die bei der Suche nach älteren Versionen von Chrome bereitgestellt werden.

Ab der Canary-Version 80.0.3975.0 kann die temporäre Lax+POST-Entschärfung mithilfe des neuen --enable-features=SameSiteDefaultChecksMethodRigorously-Flags zu Testzwecken deaktiviert werden, um das Testen von Websites und Diensten im möglichen Endzustand des Features zu ermöglichen, in dem die Entschärfung entfernt wurde. Weitere Informationen finden Sie unter „The Chromium Projects“ SameSite Updates.

Testen mit Safari

Safari 12 hat den vorherigen Entwurf strikt umgesetzt und weist einen Fehler auf, wenn sich der neue None-Wert in einem cookie befindet. None wird über den Browsererkennungscode vermieden: Unterstützung älterer Browser in diesem Dokument. Testen Sie Anmeldungen im Stil von Safari 12, Safari 13 und WebKit-basierten Betriebssystemen mithilfe von MSAL, ADAL oder der von Ihnen verwendeten Bibliothek. Das Problem hängt von der zugrunde liegenden Betriebssystemversion ab. Bei OSX Mojave (10.14) und iOS 12 sind Kompatibilitätsprobleme mit dem neuen SameSite-Verhalten bekannt. Das Problem lässt sich mit einem Upgrade des Betriebssystems auf OSX Catalina (10.15) bzw. iOS 13 beheben. Safari verfügt derzeit nicht über ein Aktivierungsflag zum Testen des neuen Spezifikationsverhaltens.

Testen mit Firefox

Die Firefox-Unterstützung für den neuen Standard kann in Version 68+ getestet werden, indem Sie sich auf der Seite about:config mit dem Featureflag network.cookie.sameSite.laxByDefault anmelden. Es liegen keine Berichte über Kompatibilitätsprobleme mit älteren Versionen von Firefox vor.

Testen mit dem Edge-Browser

Edge unterstützt den alten SameSite-Standard. Die Edge-Version 44 weist keine bekannten Kompatibilitätsprobleme mit dem neuen Standard auf.

Testen mit Edge (Chromium)

SameSite-Flags werden auf der Seite edge://flags/#same-site-by-default-cookies festgelegt. Es wurden keine Kompatibilitätsprobleme mit Edge Chromium festgestellt.

Testen mit Electron

Die Versionen von Electron umfassen ältere Versionen von Chromium. Die von Teams verwendete Version von Electron ist z. B. Chromium 66, die das ältere Verhalten aufweist. Sie müssen Ihre eigenen Kompatibilitätstests mit der Version von Electron durchführen, die in Ihrem Produkt verwendet wird. Weitere Informationen finden Sie unter Unterstützung älterer Browser im folgenden Abschnitt.

Zusätzliche Ressourcen

Beispiel Dokument
.NET Core Razor Pages ASP.NET Core 3.1 Razor Pages: Beispiel für SameSite-cookies

Das folgende Beispiel kann heruntergeladen und getestet werden:

Beispiel Dokument
.NET Core Razor Pages ASP.NET Core 3.1 Razor Pages: Beispiel für SameSite-cookies

.NET Core-Unterstützung für das sameSite-Attribut

.NET Core 3.1 und höher unterstützt den Entwurfsstandard von 2019 für SameSite. Entwickler können den Wert des sameSite-Attributs mithilfe der Eigenschaft HttpCookie.SameSite programmgesteuert steuern. Wenn Sie die Eigenschaft SameSite auf „Strict“, „Lax“ oder „None“ festlegen, werden diese Werte mit dem cookie in das Netzwerk geschrieben. Das Festlegen auf (SameSiteMode)(-1) bedeutet, dass kein sameSite-Attribut im Netzwerk mit dem cookie einbezogen werden soll.

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 und spätere Versionen unterstützen die aktualisierten SameSite-Werte und fügen einen zusätzlichen Enumerationswert, SameSiteMode.Unspecified, zur SameSiteMode-Enumeration hinzu. Dieser neue Wert zeigt an, dass kein sameSite-Attribut mit dem cookie gesendet werden sollte.

API-Verwendung mit SameSite

HttpContext.Response.Cookies.Append ist standardmäßig auf Unspecified festgelegt, d. h. es wird kein SameSite-Attribut an das cookie angefügt und der Client verwendet sein Standardverhalten („Lax“ für neue Browser, „None“ für alte). Der folgende Code zeigt, wie Sie den cookie SameSite-Wert in SameSiteMode.Lax ändern:

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

Alle ASP.NET Core-Komponenten, die cookies ausgeben, setzen die vorangehenden Standardwerte mit Einstellungen außer Kraft, die für ihre Szenarien geeignet sind. Die außer Kraft gesetzten vorangehenden Standardwerte haben sich nicht geändert.

Komponente cookie Standard
CookieBuilder SameSite Unspecified
Session SessionOptions.Cookie Lax
CookieTempDataProvider CookieTempDataProviderOptions.Cookie Lax
IAntiforgery AntiforgeryOptions.Cookie Strict
Cookie Authentication CookieAuthenticationOptions.Cookie Lax
AddTwitter TwitterOptions.StateCookie Lax
RemoteAuthenticationHandler<TOptions> RemoteAuthenticationOptions.CorrelationCookie None
AddOpenIdConnect OpenIdConnectOptions.NonceCookie None
HttpContext.Response.Cookies.Append CookieOptions Unspecified

ASP.NET Core 3.1 und höher bietet die folgende SameSite-Unterstützung:

  • Definiert das Verhalten von SameSiteMode.None neu, um SameSite=None auszugeben.
  • Fügt einen neuen SameSiteMode.Unspecified-Wert hinzu, um das SameSite-Attribut auszulassen.
  • Alle APIs für cookies sind standardmäßig auf Unspecified eingestellt. Einige Komponenten, die cookies verwenden, legen Werte fest, die spezifischer für ihre Szenarien sind. Beispiele finden Sie in der obigen Tabelle.

In ASP.NET Core 3.0 und höher wurden die SameSite-Standardwerte geändert, um Konflikte mit inkonsistenten Clientstandardwerten zu vermeiden. Die folgenden APIs haben den Standard von SameSiteMode.Lax in -1 geändert, um zu vermeiden, dass ein SameSite-Attribut für diese cookies ausgegeben wird:

Verlauf und Änderungen

Die SameSite-Unterstützung wurde erstmals in ASP.NET Core 2.0 mithilfe des Entwurfsstandards von 2016 implementiert. Der Standard von 2016 wurde abonniert. ASP.NET Core wurde abonniert, indem mehrere cookies standardmäßig auf Lax festgelegt wurden. Nachdem mehrere Probleme mit der Authentifizierung aufgetreten waren, wurde der Großteil der SameSite-Nutzung deaktiviert.

Patches wurden im November 2019 veröffentlicht, um vom Standard von 2016 auf den Standard von 2019 zu aktualisieren. Der Entwurf von 2019 der SameSite-Spezifikation:

  • Er ist nicht abwärtskompatibel mit dem Entwurf von 2016. Weitere Informationen finden Sie unter Unterstützung älterer Browser in diesem Dokument.
  • Gibt an, dass cookies standardmäßig als SameSite=Lax behandelt werden.
  • Gibt an, dass cookies, die explizit SameSite=None bestätigen, um eine siteübergreifende Zustellung zu ermöglichen, als Secure markiert werden sollen. None ist ein neuer Eintrag zum Kündigen des Abonnements.
  • Wird von Patches für ASP.NET Core 2.1, 2.2 und 3.0 unterstützt. ASP.NET Core 3.1 bietet zusätzliche Unterstützung für SameSite.
  • Wurde von Chrome standardmäßig im Februar 2020 aktiviert. Die Browser werden seit 2019 auf diesen Standard umgestellt.

APIs, die von der Änderung des SameSite-Entwurfsstandards von 2016 zum Entwurfsstandard von 2019 betroffen sind

Unterstützung älterer Browser

Der SameSite-Standard von 2016 schreibt vor, dass unbekannte Werte als SameSite=Strict-Werte behandelt werden müssen. Apps, auf die von älteren Browsern aus zugegriffen wird, die den SameSite-Standard von 2016 unterstützen, können unterbrochen werden, wenn sie eine SameSite-Eigenschaft mit einem Wert von None erhalten. Web-Apps müssen eine Browsererkennung implementieren, wenn sie ältere Browser unterstützen wollen. ASP.NET Core implementiert keine Browsererkennung, da die Werte von Benutzer-Agents sehr veränderlich sind und sich häufig ändern. Ein Erweiterungspunkt in Microsoft.AspNetCore.CookiePolicy ermöglicht die Integration von Logik, die für Benutzer-Agents spezifisch ist.

Fügen Sie in Startup.Configure Code hinzu, der UseCookiePolicy aufruft, bevor Sie UseAuthentication oder irgendeine Methode aufrufen, die cookies schreibt:

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

Fügen Sie in Startup.ConfigureServices einen Code ähnlich dem folgenden hinzu:

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

Im vorangehenden Beispiel ist MyUserAgentDetectionLib.DisallowsSameSiteNone eine vom Benutzer bereitgestellte Bibliothek, die erkennt, ob der Benutzer-Agent SameSite None nicht unterstützt:

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

Der folgende Code zeigt ein Beispiel für eine DisallowsSameSiteNone-Methode:

Warnung

Der folgende Code dient nur zur Demonstration:

  • Er sollte nicht als vollständig betrachtet werden.
  • Er wird nicht verwaltet oder unterstützt.
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;
}

Testen von Apps für SameSite-Probleme

Apps, die mit Remotestandorten interagieren, z. B. über die Anmeldung über Drittanbieter, müssen folgende Aktionen ausführen:

Testen Sie Web-Apps mithilfe einer Clientversion, die das neue SameSite-Verhalten abonnieren kann. Chrome, Firefox und Chromium Edge verfügen über neue Featureflags, die für Tests verwendet werden können. Nachdem Ihre App die SameSite-Patches angewendet hat, testen Sie sie mit älteren Clientversionen, insbesondere Safari. Weitere Informationen finden Sie unter Unterstützung älterer Browser in diesem Dokument.

Testen mit Chrome

Chrome 78+ liefert irreführende Ergebnisse, da es eine vorübergehende Risikominderung aufweist. Die temporäre Risikominderung von Chrome 78+ gestattet cookies, die weniger als zwei Minuten alt sind. Chrome 76 oder 77 mit den entsprechenden aktivierten Testflags liefert genauere Ergebnisse. Um das neue SameSite-Verhalten zu testen, schalten Sie chrome://flags/#same-site-by-default-cookies auf Aktiviert um. Bei älteren Versionen von Chrome (75 und niedriger) wird gemeldet, dass mit der neuen None-Einstellung ein Fehler auftritt. Weitere Informationen finden Sie unter Unterstützung älterer Browser in diesem Dokument.

Google stellt keine älteren Chrome-Versionen zur Verfügung. Befolgen Sie die Anweisungen unter Herunterladen von Chromium, um ältere Versionen von Chrome zu testen. Laden Sie Chrome nicht über Links herunter, die bei der Suche nach älteren Versionen von Chrome bereitgestellt werden.

Ab der Canary-Version 80.0.3975.0 kann die temporäre Lax+POST-Entschärfung mithilfe des neuen --enable-features=SameSiteDefaultChecksMethodRigorously-Flags zu Testzwecken deaktiviert werden, um das Testen von Websites und Diensten im möglichen Endzustand des Features zu ermöglichen, in dem die Entschärfung entfernt wurde. Weitere Informationen finden Sie unter „The Chromium Projects“ SameSite Updates.

Testen mit Safari

Safari 12 hat den vorherigen Entwurf strikt umgesetzt und weist einen Fehler auf, wenn sich der neue None-Wert in einem cookie befindet. None wird über den Browsererkennungscode vermieden: Unterstützung älterer Browser in diesem Dokument. Testen Sie Anmeldungen im Stil von Safari 12, Safari 13 und WebKit-basierten Betriebssystemen mithilfe von MSAL, ADAL oder der von Ihnen verwendeten Bibliothek. Das Problem hängt von der zugrunde liegenden Betriebssystemversion ab. Bei OSX Mojave (10.14) und iOS 12 sind Kompatibilitätsprobleme mit dem neuen SameSite-Verhalten bekannt. Das Problem lässt sich mit einem Upgrade des Betriebssystems auf OSX Catalina (10.15) bzw. iOS 13 beheben. Safari verfügt derzeit nicht über ein Aktivierungsflag zum Testen des neuen Spezifikationsverhaltens.

Testen mit Firefox

Die Firefox-Unterstützung für den neuen Standard kann in Version 68+ getestet werden, indem Sie sich auf der Seite about:config mit dem Featureflag network.cookie.sameSite.laxByDefault anmelden. Es liegen keine Berichte über Kompatibilitätsprobleme mit älteren Versionen von Firefox vor.

Testen mit dem Edge-Browser

Edge unterstützt den alten SameSite-Standard. Die Edge-Version 44 weist keine bekannten Kompatibilitätsprobleme mit dem neuen Standard auf.

Testen mit Edge (Chromium)

SameSite-Flags werden auf der Seite edge://flags/#same-site-by-default-cookies festgelegt. Es wurden keine Kompatibilitätsprobleme mit Edge Chromium festgestellt.

Testen mit Electron

Die Versionen von Electron umfassen ältere Versionen von Chromium. Die von Teams verwendete Version von Electron ist z. B. Chromium 66, die das ältere Verhalten aufweist. Sie müssen Ihre eigenen Kompatibilitätstests mit der Version von Electron durchführen, die in Ihrem Produkt verwendet wird. Weitere Informationen finden Sie unter Unterstützung älterer Browser im folgenden Abschnitt.

Zusätzliche Ressourcen

Beispiel Dokument
.NET Core Razor Pages ASP.NET Core 3.1 Razor Pages: Beispiel für SameSite-cookies

Die folgenden Beispiele können heruntergeladen und getestet werden:

Beispiel Dokument
.NET Core MVC ASP.NET Core 2.1 MVC SameSite-cookie-Beispiel
.NET Core Razor Pages ASP.NET Core 2.1 Razor Pages: Beispiel für SameSite-cookies

Behavior Changes durch den Dezember-Patch

Die spezifische Behavior Change für .NET Framework und .NET Core 2.1 besteht darin, wie die Eigenschaft SameSite den None-Wert interpretiert. Vor dem Patch bedeutete ein Wert von None „Das Attribut überhaupt nicht ausgeben“, nach dem Patch bedeutet es „Das Attribut mit einem Wert von None ausgeben“. Nach dem Patch bewirkt ein SameSite-Wert von (SameSiteMode)(-1), dass das Attribut nicht ausgegeben wird.

Der SameSite-Standardwert für die Formularauthentifizierung und für Sitzungszustand-cookies wurde von None in Lax geändert.

API-Verwendung mit SameSite

HttpContext.Response.Cookies.Append ist standardmäßig auf Unspecified festgelegt, d. h. es wird kein SameSite-Attribut an das cookie angefügt und der Client verwendet sein Standardverhalten („Lax“ für neue Browser, „None“ für alte). Der folgende Code zeigt, wie Sie den cookie SameSite-Wert in SameSiteMode.Lax ändern:

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

Alle ASP.NET Core-Komponenten, die cookies ausgeben, setzen die vorangehenden Standardwerte mit Einstellungen außer Kraft, die für ihre Szenarien geeignet sind. Die außer Kraft gesetzten vorangehenden Standardwerte haben sich nicht geändert.

Komponente cookie Standard
CookieBuilder SameSite Unspecified
Session SessionOptions.Cookie Lax
CookieTempDataProvider CookieTempDataProviderOptions.Cookie Lax
IAntiforgery AntiforgeryOptions.Cookie Strict
Cookie Authentication CookieAuthenticationOptions.Cookie Lax
AddTwitter TwitterOptions.StateCookie Lax
RemoteAuthenticationHandler<TOptions> RemoteAuthenticationOptions.CorrelationCookie None
AddOpenIdConnect OpenIdConnectOptions.NonceCookie None
HttpContext.Response.Cookies.Append CookieOptions Unspecified

Verlauf und Änderungen

Die SameSite-Unterstützung wurde erstmals in ASP.NET Core 2.0 mithilfe des Entwurfsstandards von 2016 implementiert. Der Standard von 2016 wurde abonniert. ASP.NET Core wurde abonniert, indem mehrere cookies standardmäßig auf Lax festgelegt wurden. Nachdem mehrere Probleme mit der Authentifizierung aufgetreten waren, wurde der Großteil der SameSite-Nutzung deaktiviert.

Patches wurden im November 2019 veröffentlicht, um vom Standard von 2016 auf den Standard von 2019 zu aktualisieren. Der Entwurf von 2019 der SameSite-Spezifikation:

  • Er ist nicht abwärtskompatibel mit dem Entwurf von 2016. Weitere Informationen finden Sie unter Unterstützung älterer Browser in diesem Dokument.
  • Gibt an, dass cookies standardmäßig als SameSite=Lax behandelt werden.
  • Gibt an, dass cookies, die explizit SameSite=None bestätigen, um eine siteübergreifende Zustellung zu ermöglichen, als Secure markiert werden sollen. None ist ein neuer Eintrag zum Kündigen des Abonnements.
  • Wird von Patches für ASP.NET Core 2.1, 2.2 und 3.0 unterstützt. ASP.NET Core 3.1 bietet zusätzliche Unterstützung für SameSite.
  • Wurde von Chrome standardmäßig im Februar 2020 aktiviert. Die Browser werden seit 2019 auf diesen Standard umgestellt.

APIs, die von der Änderung des SameSite-Entwurfsstandards von 2016 zum Entwurfsstandard von 2019 betroffen sind

Unterstützung älterer Browser

Der SameSite-Standard von 2016 schreibt vor, dass unbekannte Werte als SameSite=Strict-Werte behandelt werden müssen. Apps, auf die von älteren Browsern aus zugegriffen wird, die den SameSite-Standard von 2016 unterstützen, können unterbrochen werden, wenn sie eine SameSite-Eigenschaft mit einem Wert von None erhalten. Web-Apps müssen eine Browsererkennung implementieren, wenn sie ältere Browser unterstützen wollen. ASP.NET Core implementiert keine Browsererkennung, da die Werte von Benutzer-Agents sehr veränderlich sind und sich häufig ändern. Ein Erweiterungspunkt in Microsoft.AspNetCore.CookiePolicy ermöglicht die Integration von Logik, die für Benutzer-Agents spezifisch ist.

Fügen Sie in Startup.Configure Code hinzu, der UseCookiePolicy aufruft, bevor Sie UseAuthentication oder irgendeine Methode aufrufen, die cookies schreibt:

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

Fügen Sie in Startup.ConfigureServices einen Code ähnlich dem folgenden hinzu:

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

    }
}

Im vorangehenden Beispiel ist MyUserAgentDetectionLib.DisallowsSameSiteNone eine vom Benutzer bereitgestellte Bibliothek, die erkennt, ob der Benutzer-Agent SameSite None nicht unterstützt:

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

Der folgende Code zeigt ein Beispiel für eine DisallowsSameSiteNone-Methode:

Warnung

Der folgende Code dient nur zur Demonstration:

  • Er sollte nicht als vollständig betrachtet werden.
  • Er wird nicht verwaltet oder unterstützt.
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;
}

Testen von Apps für SameSite-Probleme

Apps, die mit Remotestandorten interagieren, z. B. über die Anmeldung über Drittanbieter, müssen folgende Aktionen ausführen:

Testen Sie Web-Apps mithilfe einer Clientversion, die das neue SameSite-Verhalten abonnieren kann. Chrome, Firefox und Chromium Edge verfügen über neue Featureflags, die für Tests verwendet werden können. Nachdem Ihre App die SameSite-Patches angewendet hat, testen Sie sie mit älteren Clientversionen, insbesondere Safari. Weitere Informationen finden Sie unter Unterstützung älterer Browser in diesem Dokument.

Testen mit Chrome

Chrome 78+ liefert irreführende Ergebnisse, da es eine vorübergehende Risikominderung aufweist. Die temporäre Risikominderung von Chrome 78+ gestattet cookies, die weniger als zwei Minuten alt sind. Chrome 76 oder 77 mit den entsprechenden aktivierten Testflags liefert genauere Ergebnisse. Um das neue SameSite-Verhalten zu testen, schalten Sie chrome://flags/#same-site-by-default-cookies auf Aktiviert um. Bei älteren Versionen von Chrome (75 und niedriger) wird gemeldet, dass mit der neuen None-Einstellung ein Fehler auftritt. Weitere Informationen finden Sie unter Unterstützung älterer Browser in diesem Dokument.

Google stellt keine älteren Chrome-Versionen zur Verfügung. Befolgen Sie die Anweisungen unter Herunterladen von Chromium, um ältere Versionen von Chrome zu testen. Laden Sie Chrome nicht über Links herunter, die bei der Suche nach älteren Versionen von Chrome bereitgestellt werden.

Ab der Canary-Version 80.0.3975.0 kann die temporäre Lax+POST-Entschärfung mithilfe des neuen --enable-features=SameSiteDefaultChecksMethodRigorously-Flags zu Testzwecken deaktiviert werden, um das Testen von Websites und Diensten im möglichen Endzustand des Features zu ermöglichen, in dem die Entschärfung entfernt wurde. Weitere Informationen finden Sie unter „The Chromium Projects“ SameSite Updates.

Testen mit Safari

Safari 12 hat den vorherigen Entwurf strikt umgesetzt und weist einen Fehler auf, wenn sich der neue None-Wert in einem cookie befindet. None wird über den Browsererkennungscode vermieden: Unterstützung älterer Browser in diesem Dokument. Testen Sie Anmeldungen im Stil von Safari 12, Safari 13 und WebKit-basierten Betriebssystemen mithilfe von MSAL, ADAL oder der von Ihnen verwendeten Bibliothek. Das Problem hängt von der zugrunde liegenden Betriebssystemversion ab. Bei OSX Mojave (10.14) und iOS 12 sind Kompatibilitätsprobleme mit dem neuen SameSite-Verhalten bekannt. Das Problem lässt sich mit einem Upgrade des Betriebssystems auf OSX Catalina (10.15) bzw. iOS 13 beheben. Safari verfügt derzeit nicht über ein Aktivierungsflag zum Testen des neuen Spezifikationsverhaltens.

Testen mit Firefox

Die Firefox-Unterstützung für den neuen Standard kann in Version 68+ getestet werden, indem Sie sich auf der Seite about:config mit dem Featureflag network.cookie.sameSite.laxByDefault anmelden. Es liegen keine Berichte über Kompatibilitätsprobleme mit älteren Versionen von Firefox vor.

Testen mit dem Edge-Browser

Edge unterstützt den alten SameSite-Standard. Die Edge-Version 44 weist keine bekannten Kompatibilitätsprobleme mit dem neuen Standard auf.

Testen mit Edge (Chromium)

SameSite-Flags werden auf der Seite edge://flags/#same-site-by-default-cookies festgelegt. Es wurden keine Kompatibilitätsprobleme mit Edge Chromium festgestellt.

Testen mit Electron

Die Versionen von Electron umfassen ältere Versionen von Chromium. Die von Teams verwendete Version von Electron ist z. B. Chromium 66, die das ältere Verhalten aufweist. Sie müssen Ihre eigenen Kompatibilitätstests mit der Version von Electron durchführen, die in Ihrem Produkt verwendet wird. Weitere Informationen finden Sie unter Unterstützung älterer Browser im folgenden Abschnitt.

Zusätzliche Ressourcen

Beispiel Dokument
.NET Core MVC ASP.NET Core 2.1 MVC SameSite-cookie-Beispiel
.NET Core Razor Pages ASP.NET Core 2.1 Razor Pages: Beispiel für SameSite-cookies