Aktivieren ursprungsübergreifender Anforderungen (CORS) in ASP.NET Core

Hinweis

Dies ist nicht die neueste Version dieses Artikels. Informationen zum aktuellen Release finden Sie in der .NET 8-Version dieses Artikels.

Wichtig

Diese Informationen beziehen sich auf ein Vorabversionsprodukt, das vor der kommerziellen Freigabe möglicherweise noch wesentlichen Änderungen unterliegt. Microsoft gibt keine Garantie, weder ausdrücklich noch impliziert, hinsichtlich der hier bereitgestellten Informationen.

Informationen zum aktuellen Release finden Sie in der .NET 8-Version dieses Artikels.

Von Rick Anderson und Kirk Larkin

In diesem Artikel erfahren Sie, wie Sie die CORS (Cross-Origin Resource Sharing, ursprungsübergreifende gemeinsame Nutzung von Ressourcen) in einer ASP.NET Core-App aktivieren.

Die Browsersicherheit verhindert, dass eine Webseite Anforderungen an eine andere Domäne als diejenige stellt, die die Webseite versorgt hat. Diese Einschränkung wird als Richtlinie des gleichen Ursprungs bezeichnet. Die Richtlinie des gleichen Ursprungs verhindert, dass eine schädliche Website sensible Daten von einer anderen Website liest. Manchmal kann es sinnvoll sein, anderen Websites das Senden von ursprungsübergreifenden Anforderungen an Ihre App zu erlauben. Weitere Informationen finden Sie im Mozilla CORS-Artikel.

Ressourcenfreigabe zwischen verschiedenen Ursprüngen (Cross-Origin Resource Sharing, CORS):

  • ist ein W3C-Standard, der einem Server eine weniger strenge Anwendung der Richtlinie des gleichen Ursprungs ermöglicht.
  • ist kein Sicherheitsfeature, CORS lockert die Sicherheit. Eine API wird nicht sicherer, indem sie CORS zulässt. Weitere Informationen finden Sie unter Funktionsweise von CORS.
  • ermöglicht es einem Server, einige ursprungsübergreifende Anforderungen explizit zuzulassen und andere abzulehnen.
  • ist sicherer und flexibler als frühere Techniken wie etwa JSONP.

Anzeigen oder Herunterladen von Beispielcode (Vorgehensweise zum Herunterladen)

Gleicher Ursprung

Zwei URLs haben den gleichen Ursprung, wenn sie identische Schemas, Hosts und Ports aufweisen (RFC 6454).

Diese beiden URLs haben den gleichen Ursprung:

  • https://example.com/foo.html
  • https://example.com/bar.html

Diese URLs haben andere Ursprünge als die vorherigen beiden URLs:

  • https://example.net: andere Domäne
  • https://www.example.com/foo.html: andere Unterdomäne
  • http://example.com/foo.html: anderes Schema
  • https://example.com:9000/foo.html: anderer Port

Aktivieren von CORS

Es gibt es drei Möglichkeiten zum Aktualisieren von CORS:

Die Verwendung des [EnableCors]-Attributs mit einer benannten Richtlinie bietet die beste Kontrolle bei der Begrenzung von Endpunkten, die CORS unterstützen.

Warnung

UseCors muss in der richtigen Reihenfolge aufgerufen werden. Weitere Informationen finden Sie unter Middleware-Reihenfolge. Beispielsweise muss UseCors bei Verwendung von UseResponseCaching vor UseResponseCaching aufgerufen werden.

Jeder Ansatz wird in den folgenden Abschnitten ausführlich beschrieben.

CORS mit benannter Richtlinie und Middleware

CORS-Middleware verarbeitet ursprungsübergreifende Anforderungen. Der folgende Code wendet eine CORS-Richtlinie auf alle Endpunkte der App mit den angegebenen Ursprüngen an:

var  MyAllowSpecificOrigins = "_myAllowSpecificOrigins";

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy(name: MyAllowSpecificOrigins,
                      policy  =>
                      {
                          policy.WithOrigins("http://example.com",
                                              "http://www.contoso.com");
                      });
});

// services.AddResponseCaching();

builder.Services.AddControllers();

var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();

app.UseCors(MyAllowSpecificOrigins);

app.UseAuthorization();

app.MapControllers();

app.Run();

Der vorangehende Code:

  • Legt den Richtliniennamen auf _myAllowSpecificOrigins fest. Der Name der Richtlinie ist frei wählbar.
  • Ruft die Erweiterungsmethode UseCors auf und gibt die CORS-Richtlinie _myAllowSpecificOrigins an. UseCors fügt die CORS-Middleware hinzu. Der Aufruf von UseCors muss nach UseRouting, aber vor UseAuthorization platziert werden. Weitere Informationen finden Sie unter Middleware-Reihenfolge.
  • Ruft AddCors mit einem Lambdaausdruck auf. Der Lambdaausdruck nimmt ein CorsPolicyBuilder-Objekt an. Konfigurationsoptionen wie WithOrigins werden weiter unten in diesem Artikel beschrieben.
  • Aktiviert die CORS-Richtlinie _myAllowSpecificOrigins für alle Controllerendpunkte. Informationen zum Anwenden einer CORS-Richtlinie auf bestimmte Endpunkte finden Sie unter Endpunktrouting.
  • Wenn Sie Antworten zwischenspeichernde Middleware verwenden, rufen Sie UseCors vor UseResponseCaching auf.

Beim Endpunktrouting muss die CORS-Middleware für die Ausführung zwischen den Aufrufen von UseRouting und UseEndpoints konfiguriert werden.

Anweisungen zum Testen von Code ähnlich dem vorstehenden Code finden Sie unter Testen von CORS.

Der Methodenaufruf AddCors fügt dem Dienstcontainer der App CORS-Dienste hinzu:

var  MyAllowSpecificOrigins = "_myAllowSpecificOrigins";

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy(name: MyAllowSpecificOrigins,
                      policy  =>
                      {
                          policy.WithOrigins("http://example.com",
                                              "http://www.contoso.com");
                      });
});

// services.AddResponseCaching();

builder.Services.AddControllers();

var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();

app.UseCors(MyAllowSpecificOrigins);

app.UseAuthorization();

app.MapControllers();

app.Run();

Weitere Informationen finden Sie unter CORS-Richtlinienoptionen in diesem Dokument.

Die CorsPolicyBuilder-Methoden können verkettet werden, wie im folgenden Code gezeigt:

var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy(MyAllowSpecificOrigins,
                          policy =>
                          {
                              policy.WithOrigins("http://example.com",
                                                  "http://www.contoso.com")
                                                  .AllowAnyHeader()
                                                  .AllowAnyMethod();
                          });
});

builder.Services.AddControllers();

var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();

app.UseCors(MyAllowSpecificOrigins);

app.UseAuthorization();

app.MapControllers();

app.Run();

Hinweis: Die angegebene URL darf keinen nachgestellten Schrägstrich (/) enthalten. Wenn die URL mit / beendet wird, gibt der Vergleich false zurück, und es wird kein Header zurückgegeben.

Reihenfolge von UseCors und UseStaticFiles

In der Regel wird UseStaticFiles vor UseCors aufgerufen. Apps, die JavaScript zum websiteübergreifenden Abrufen statischer Dateien verwenden, müssen UseCors vor UseStaticFiles aufrufen.

CORS mit Standardrichtlinie und Middleware

Der folgende hervorgehobene Code aktiviert die CORS-Standardrichtlinie:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddDefaultPolicy(
        policy =>
        {
            policy.WithOrigins("http://example.com",
                                "http://www.contoso.com");
        });
});

builder.Services.AddControllers();

var app = builder.Build();

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

app.UseCors();

app.UseAuthorization();

app.MapControllers();

app.Run();

Der vorstehende Code wendet die CORS-Standardrichtlinie auf alle Controllerendpunkte an.

Aktivieren von Cors mit Endpunktrouting

Beim Endpunktrouting kann CORS mithilfe der RequireCors-Sammlung von Erweiterungsmethoden je Endpunkt aktiviert werden:

var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy(name: MyAllowSpecificOrigins,
                      policy =>
                      {
                          policy.WithOrigins("http://example.com",
                                              "http://www.contoso.com");
                      });
});

builder.Services.AddControllers();
builder.Services.AddRazorPages();

var app = builder.Build();

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

app.UseCors();

app.UseAuthorization();

app.UseEndpoints(endpoints =>
{
    endpoints.MapGet("/echo",
        context => context.Response.WriteAsync("echo"))
        .RequireCors(MyAllowSpecificOrigins);

    endpoints.MapControllers()
             .RequireCors(MyAllowSpecificOrigins);

    endpoints.MapGet("/echo2",
        context => context.Response.WriteAsync("echo2"));

    endpoints.MapRazorPages();
});

app.Run();

Für den Code oben gilt:

  • app.UseCors aktiviert die CORS-Middleware. Da keine Standardrichtlinie konfiguriert wurde, wird CORS nicht durch app.UseCors() allein aktiviert.
  • Die /echo- und Controllerendpunkte ermöglichen ursprungsübergreifende Anforderungen mithilfe der angegebenen Richtlinie.
  • Die /echo2- und Razor Pages-Endpunkte ermöglichen keine ursprungsübergreifenden Anforderungen, da keine Standardrichtlinie angegeben wurde.

Das Attribut [DisableCors] deaktiviert CORS nicht, wenn es durch Endpunktrouting mit RequireCors aktiviert wurde.

Anweisungen zum Testen von Code ähnlich dem vorstehenden finden Sie unter Testen von CORS mit dem [EnableCors]-Attribut und der RequireCors-Methode.

Aktivieren von CORS mit Attributen

Das Aktivieren von CORS mit dem [EnableCors]-Attribut und das Anwenden einer benannten Richtlinie lediglich auf die Endpunkte, die CORS erfordern, bietet die genaueste Steuerung.

Das Attribut [EnableCors] stellt eine Alternative zum globalen Anwenden von CORS dar. Das [EnableCors]-Attribut aktiviert CORS für ausgewählte Endpunkte anstelle aller Endpunkte:

  • [EnableCors] gibt die Standardrichtlinie an.
  • [EnableCors("{Policy String}")] gibt eine benannte Richtlinie an.

Das [EnableCors]-Attribut kann auf Folgendes angewendet werden:

  • Razor Page PageModel
  • Controller
  • Controlleraktionsmethode

Mit dem [EnableCors]-Attribut können verschiedene Richtlinien auf Controller, Seitenmodelle oder Aktionsmethoden angewendet werden. Wenn das [EnableCors]-Attribut auf einen Controller, ein Seitenmodell oder eine Aktionsmethode angewendet wird und CORS in Middleware aktiviert ist, werden beide Richtlinien angewendet. Wir raten davon ab, Richtlinien zu kombinieren. Verwenden Sie das [EnableCors]-Attribut oder Middleware, aber nicht beides in derselben App.

Der folgende Code wendet eine andere Richtlinie auf jede Methode an:

[Route("api/[controller]")]
[ApiController]
public class WidgetController : ControllerBase
{
    // GET api/values
    [EnableCors("AnotherPolicy")]
    [HttpGet]
    public ActionResult<IEnumerable<string>> Get()
    {
        return new string[] { "green widget", "red widget" };
    }

    // GET api/values/5
    [EnableCors("Policy1")]
    [HttpGet("{id}")]
    public ActionResult<string> Get(int id)
    {
        return id switch
        {
            1 => "green widget",
            2 => "red widget",
            _ => NotFound(),
        };
    }
}

Mit dem folgenden Code werden zwei CORS-Richtlinien erstellt:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy("Policy1",
        policy =>
        {
            policy.WithOrigins("http://example.com",
                                "http://www.contoso.com");
        });

    options.AddPolicy("AnotherPolicy",
        policy =>
        {
            policy.WithOrigins("http://www.contoso.com")
                                .AllowAnyHeader()
                                .AllowAnyMethod();
        });
});

builder.Services.AddControllers();

var app = builder.Build();

app.UseHttpsRedirection();

app.UseRouting();

app.UseCors();

app.UseAuthorization();

app.MapControllers();

app.Run();

Zum Erzielen der genauesten Kontrolle bei der Begrenzung von CORS-Anforderungen:

  • Verwenden Sie [EnableCors("MyPolicy")] mit einer benannten Richtlinie.
  • Definieren Sie keine Standardrichtlinie.
  • Verwenden Sie kein Endpunktrouting.

Der Code im nächsten Abschnitt entspricht der vorstehenden Liste.

Anweisungen zum Testen von Code ähnlich dem vorstehenden Code finden Sie unter Testen von CORS.

Deaktivieren von CORS

Das Attribut [DisableCors] deaktiviert CORS nicht, wenn es durch Endpunktrouting aktiviert wurde.

Im folgenden Code wird die CORS-Richtlinie "MyPolicy" definiert:

var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy(name: "MyPolicy",
        policy =>
        {
            policy.WithOrigins("http://example.com",
                                "http://www.contoso.com")
                    .WithMethods("PUT", "DELETE", "GET");
        });
});

builder.Services.AddControllers();
builder.Services.AddRazorPages();

var app = builder.Build();

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

app.UseCors();

app.UseAuthorization();

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

app.Run();

Der folgende Code deaktiviert CORS für die Aktion GetValues2:

[EnableCors("MyPolicy")]
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
    // GET api/values
    [HttpGet]
    public IActionResult Get() =>
        ControllerContext.MyDisplayRouteInfo();

    // GET api/values/5
    [HttpGet("{id}")]
    public IActionResult Get(int id) =>
        ControllerContext.MyDisplayRouteInfo(id);

    // PUT api/values/5
    [HttpPut("{id}")]
    public IActionResult Put(int id) =>
        ControllerContext.MyDisplayRouteInfo(id);


    // GET: api/values/GetValues2
    [DisableCors]
    [HttpGet("{action}")]
    public IActionResult GetValues2() =>
        ControllerContext.MyDisplayRouteInfo();

}

Der vorangehende Code:

Anweisungen zum Testen des vorstehenden Codes finden Sie unter Testen von CORS.

CORS-Richtlinienoptionen

In diesem Abschnitt werden die verschiedenen Optionen beschrieben, die in einer CORS-Richtlinie festgelegt werden können:

AddPolicy wird in Program.cs aufgerufen. Für einige Optionen kann es nützlich sein, zuerst den Abschnitt Funktionsweise von CORS zu lesen.

Festlegen der zulässigen Ursprünge

AllowAnyOrigin: Ermöglicht CORS-Anforderungen von allen Ursprüngen mit einem beliebigen Schema (http oder https). AllowAnyOrigin ist unsicher, da jede Website ursprungsübergreifende Anforderungen an die App vornehmen kann.

Hinweis

Die Angabe von AllowAnyOrigin und AllowCredentials stellt eine unsichere Konfiguration dar und kann zu siteübergreifender Anforderungsfälschung führen. Der CORS-Dienst gibt eine ungültige CORS-Antwort zurück, wenn eine App mit beiden Methoden konfiguriert ist.

AllowAnyOrigin wirkt sich auf Preflight-Anforderungen und den Access-Control-Allow-Origin-Header aus. Weitere Informationen finden Sie im Abschnitt Preflight-Anforderungen.

SetIsOriginAllowedToAllowWildcardSubdomains: Legt die IsOriginAllowed-Eigenschaft der Richtlinie als Funktion fest, die Ursprüngen bei der Prüfung des Ursprungs auf Zulässigkeit die Übereinstimmung mit einer konfigurierten Platzhalterdomäne ermöglicht.

var MyAllowSpecificOrigins = "_MyAllowSubdomainPolicy";

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy(name: MyAllowSpecificOrigins,
        policy =>
        {
            policy.WithOrigins("https://*.example.com")
                .SetIsOriginAllowedToAllowWildcardSubdomains();
        });
});

builder.Services.AddControllers();

var app = builder.Build();

Festlegen der zulässigen HTTP-Methoden

AllowAnyMethod:

  • Lässt jede HTTP-Methode zu:
  • Wirkt sich auf Preflight-Anforderungen und den Access-Control-Allow-Methods-Header aus. Weitere Informationen finden Sie im Abschnitt Preflight-Anforderungen.

Festlegen der zulässigen Anforderungsheader

Rufen Sie WithHeaders auf, und geben Sie die zulässigen Header an, um das Senden bestimmter Header, die als Autorenanforderungsheader bezeichnet werden, in einer CORS-Anforderung zuzulassen:

using Microsoft.Net.Http.Headers;

var MyAllowSpecificOrigins = "_MyAllowSubdomainPolicy";

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy(name: MyAllowSpecificOrigins,
       policy =>
       {
           policy.WithOrigins("http://example.com")
                  .WithHeaders(HeaderNames.ContentType, "x-custom-header");
       });
});

builder.Services.AddControllers();

var app = builder.Build();

Rufen Sie zum Zulassen aller AutorenanforderungsheaderAllowAnyHeader auf:

var MyAllowSpecificOrigins = "_MyAllowSubdomainPolicy";

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy(name: MyAllowSpecificOrigins,
        policy =>
        {
            policy.WithOrigins("https://*.example.com")
                   .AllowAnyHeader();
        });
});

builder.Services.AddControllers();

var app = builder.Build();

AllowAnyHeader wirkt sich auf Preflight-Anforderungen und den Header Access-Control-Request-Headers aus. Weitere Informationen finden Sie im Abschnitt Preflight-Anforderungen.

Eine Zuordnung einer CORS-Middleware-Richtlinie zu bestimmten Headern, die in WithHeaders angegeben werden, ist nur möglich, wenn die in Access-Control-Request-Headers gesendeten Header exakt mit den in WithHeaders angegebenen Headern übereinstimmen.

Betrachten Sie beispielsweise eine App, die wie folgt konfiguriert ist:

app.UseCors(policy => policy.WithHeaders(HeaderNames.CacheControl));

CORS Middleware lehnt eine Preflight-Anforderung mit dem folgenden Anforderungsheader ab, da Content-Language (HeaderNames.ContentLanguage) nicht in WithHeaders aufgeführt ist:

Access-Control-Request-Headers: Cache-Control, Content-Language

Die App gibt eine 200 OK-Antwort zurück, sendet die CORS-Header jedoch nicht zurück. Daher versucht der Browser die ursprungsübergreifende Anforderung nicht.

Festlegen der verfügbar gemachten Antwortheader

Standardmäßig macht der Browser nicht alle Antwortheader für die App verfügbar. Weitere Informationen finden Sie unter W3C Cross-Origin Resource Sharing (Terminologie): Einfacher Antwortheader.

Standardmäßig sind folgende Antwortheader verfügbar:

  • Cache-Control
  • Content-Language
  • Content-Type
  • Expires
  • Last-Modified
  • Pragma

Die CORS-Spezifikation ruft diese Header als einfache Antwortheader auf. Rufen Sie WithExposedHeaders auf, um andere Header für die App verfügbar zu machen:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy("MyExposeResponseHeadersPolicy",
        policy =>
        {
            policy.WithOrigins("https://*.example.com")
                   .WithExposedHeaders("x-custom-header");
        });
});

builder.Services.AddControllers();

var app = builder.Build();

Anmeldeinformationen in ursprungsübergreifenden Anforderungen

Für Anmeldeinformationen ist in einer CORS-Anforderung eine besondere Behandlung erforderlich. Standardmäßig sendet der Browser mit einer ursprungsübergreifenden Anforderung keine Anmeldeinformationen. Zu den Anmeldeinformationen gehören cookies und HTTP-Authentifizierungsschemas. Zum Senden von Anmeldeinformationen mit einer ursprungsübergreifenden Anforderung muss der Client XMLHttpRequest.withCredentials auf true festlegen.

Mit direkter Verwendung von XMLHttpRequest:

var xhr = new XMLHttpRequest();
xhr.open('get', 'https://www.example.com/api/test');
xhr.withCredentials = true;

Mithilfe von jQuery:

$.ajax({
  type: 'get',
  url: 'https://www.example.com/api/test',
  xhrFields: {
    withCredentials: true
  }
});

Mithilfe der Fetch-API:

fetch('https://www.example.com/api/test', {
    credentials: 'include'
});

Der Server muss die Anmeldeinformationen zulassen. Rufen Sie AllowCredentials auf, um ursprungsübergreifende Anmeldeinformationen zuzulassen:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy("MyMyAllowCredentialsPolicy",
        policy =>
        {
            policy.WithOrigins("http://example.com")
                   .AllowCredentials();
        });
});

builder.Services.AddControllers();

var app = builder.Build();

Die HTTP-Antwort enthält einen Access-Control-Allow-Credentials-Header, der dem Browser mitteilt, dass der Server Anmeldeinformationen für eine ursprungsübergreifende Anforderung zulässt.

Wenn der Browser Anmeldeinformationen sendet, die Antwort aber keinen gültigen Access-Control-Allow-Credentials-Header enthält, macht der Browser die Antwort für die App nicht verfügbar, und die ursprungsübergreifende Anforderung schlägt fehl.

Das Zulassen von ursprungsübergreifenden Anmeldeinformationen ist ein Sicherheitsrisiko. Eine Website in einer anderen Domäne kann die Anmeldeinformationen eines angemeldeten Benutzers im Namen des Benutzers ohne dessen Wissen an die App senden.

Die CORS-Spezifikation besagt ferner, dass das Festlegen von Ursprüngen auf "*" (alle Ursprünge) ungültig ist, wenn der Access-Control-Allow-Credentials-Header vorhanden ist.

Preflight-Anforderungen

Bei einigen CORS-Anforderungen sendet der Browser vor der eigentlichen Anforderung eine zusätzliche OPTIONS-Anforderung. Diese Anforderung wird als Preflight-Anforderung bezeichnet. Der Browser kann die Preflight-Anforderung überspringen, wenn alle folgenden Bedingungen erfüllt sind:

  • Die Anforderungsmethode ist GET, HEAD oder POST.
  • Die App legt keine anderen Anforderungsheader als Accept, Accept-Language, Content-Language, Content-Type oder Last-Event-ID fest.
  • Der Header Content-Type hat, sofern er festgelegt ist, einen der folgenden Werte:
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

Die für die Clientanforderung festgelegte Regel für Anforderungsheader gilt für Header, die die App durch Aufrufen von setRequestHeader für das XMLHttpRequest-Objekt festlegt. In der CORS-Spezifikation werden diese Header als Autorenanforderungsheader bezeichnet. Die Regel gilt nicht für Header, die vom Browser festgelegt werden können, wie etwa User-Agent, Host oder Content-Length.

Nachfolgend ist eine Beispielantwort ähnlich der Preflight-Anforderung, wie sie über die Schaltfläche [Put test] im Abschnitt Testen von CORS dieses Dokuments vorgenommen wird.

General:
Request URL: https://cors3.azurewebsites.net/api/values/5
Request Method: OPTIONS
Status Code: 204 No Content

Response Headers:
Access-Control-Allow-Methods: PUT,DELETE,GET
Access-Control-Allow-Origin: https://cors1.azurewebsites.net
Server: Microsoft-IIS/10.0
Set-Cookie: ARRAffinity=8f8...8;Path=/;HttpOnly;Domain=cors1.azurewebsites.net
Vary: Origin

Request Headers:
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Access-Control-Request-Method: PUT
Connection: keep-alive
Host: cors3.azurewebsites.net
Origin: https://cors1.azurewebsites.net
Referer: https://cors1.azurewebsites.net/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0

Die Preflight-Anforderung verwendet die HTTP OPTIONS-Methode. Sie kann die folgenden Header enthalten:

Wenn die Preflight-Anforderung abgelehnt wird, gibt die App eine 200 OK-Antwort zurück, legt aber die CORS-Header nicht fest. Daher versucht der Browser die ursprungsübergreifende Anforderung nicht. Ein Beispiel für eine verweigerte Preflight-Anforderung finden Sie im Abschnitt Testen von CORS in diesem Dokument.

Bei Verwendung der F12-Tools zeigt die Konsolen-App je nach Browser einen Fehler ähnlich einem der folgenden an:

  • Firefox: Ursprungsübergreifende Anforderung blockiert: Die Richtlinie des gleichen Ursprungs lässt das Lesen der Remoteressource unter https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5 nicht zu. (Grund: CORS-Anforderung war nicht erfolgreich). Weitere Informationen
  • Chromium-basiert: Der Zugriff auf Fetch unter „https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5“ vom Ursprung „https://cors3.azurewebsites.net“ wurde durch die CORS-Richtlinie blockiert: Die Antwort auf eine Preflight-Anforderung hat die Zugriffssteuerungsprüfung nicht bestanden: Für die angeforderte Ressource ist kein „Access-Control-Allow-Origin“-Header vorhanden. Falls eine opake Antwort Ihre Anforderungen erfüllt, legen Sie den Modus der Anforderung auf „no-cors“ fest, um CORS für den Ressourcenabruf zu deaktivieren.

Rufen Sie WithHeaders auf, um bestimmte Header zuzulassen:

using Microsoft.Net.Http.Headers;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy("MyAllowHeadersPolicy",
        policy =>
        {
        policy.WithOrigins("http://example.com")
                   .WithHeaders(HeaderNames.ContentType, "x-custom-header");
        });
});

builder.Services.AddControllers();

var app = builder.Build();

Rufen Sie zum Zulassen aller AutorenanforderungsheaderAllowAnyHeader auf:

using Microsoft.Net.Http.Headers;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy("MyAllowAllHeadersPolicy",
        policy =>
        {
            policy.WithOrigins("https://*.example.com")
                   .AllowAnyHeader();
        });
});

builder.Services.AddControllers();

var app = builder.Build();

Browser sind in der Festlegung von Access-Control-Request-Headers nicht konsistent. Hier gelten entweder:

  • Die Header sind auf einen anderen Wert als "*" festgelegt
  • AllowAnyHeader wird aufgerufen: Schließen Sie mindestens Accept, Content-Type und Origin sowie alle benutzerdefinierten Header ein, die Sie unterstützen möchten.

Code für automatische Preflight-Anforderungen

Die CORS-Richtlinie wird auf eine dieser Weisen angewendet:

  • Global durch Aufrufen von app.UseCors in Program.cs.
  • Mithilfe des [EnableCors]-Attributs.

ASP.NET Core antwortet auf die Preflight-Anforderung OPTIONS.

Im Abschnitt Testen von CORS dieses Dokuments wird dieses Verhalten veranschaulicht.

[HttpOptions]-Attribut für Preflight-Anforderungen

Wenn CORS mit der entsprechenden Richtlinie aktiviert ist, reagiert ASP.NET Core in der Regel automatisch auf CORS-Preflight-Anforderungen.

Der folgende Code verwendet das [HttpOptions]-Attribut, um Endpunkte für OPTIONS-Anforderungen zu erstellen:

[Route("api/[controller]")]
[ApiController]
public class TodoItems2Controller : ControllerBase
{
    // OPTIONS: api/TodoItems2/5
    [HttpOptions("{id}")]
    public IActionResult PreflightRoute(int id)
    {
        return NoContent();
    }

    // OPTIONS: api/TodoItems2 
    [HttpOptions]
    public IActionResult PreflightRoute()
    {
        return NoContent();
    }

    [HttpPut("{id}")]
    public IActionResult PutTodoItem(int id)
    {
        if (id < 1)
        {
            return BadRequest();
        }

        return ControllerContext.MyDisplayRouteInfo(id);
    }

Anweisungen zum Testen des vorstehenden Codes finden Sie unter Testen von CORS mit dem [EnableCors]-Attribut und der RequireCors-Methode.

Festlegen der Preflight-Ablaufzeit

Der Access-Control-Max-Age-Header gibt an, wie lange die Antwort auf die Preflight-Anforderung zwischengespeichert werden kann. Rufen Sie SetPreflightMaxAge auf, um diesen Header festzulegen:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy("MySetPreflightExpirationPolicy",
        policy =>
        {
            policy.WithOrigins("http://example.com")
                   .SetPreflightMaxAge(TimeSpan.FromSeconds(2520));
        });
});

builder.Services.AddControllers();

var app = builder.Build();

Aktivieren von CORS auf einem Endpunkt

Funktionsweise von CORS

In diesem Abschnitt wird beschrieben, was in einer CORS-Anforderung auf der Ebene der HTTP-Nachrichten geschieht.

  • CORS ist kein Sicherheitsfeature. CORS ist ein W3C-Standard, der einem Server eine weniger strenge Anwendung der Richtlinie desselben Ursprungs ermöglicht.
    • Beispielsweise könnte ein böswilliger Akteur Cross-Site Scripting (XSS) auf Ihre Website anwenden und eine websiteübergreifende Anforderung an seine CORS-fähige Website vornehmen, um Informationen zu stehlen.
  • Durch Zulassen von CORS wird eine API wird nicht sicherer.
    • Das Durchsetzen von CORS liegt in der Zuständigkeit des Clients (Browsers). Der Server führt die Anforderung aus und gibt die Antwort zurück. Es ist der Client, der einen Fehler zurückgibt und die Antwort blockiert. Beispielsweise wird für jedes der folgenden Tools die Serverantwort angezeigt:
  • Es stellt eine Möglichkeit für einen Server dar, Browsern die Ausführung einer ursprungsübergreifenden XHR- oder Fetch-API-Anforderung zu erlauben, die andernfalls verboten wäre.
    • Browser ohne CORS können keine ursprungsübergreifenden Anforderungen ausführen. Vor CORS wurde JSONP verwendet, um diese Einschränkung zu umgehen. JSONP verwendet nicht XHR, es verwendet das <script>-Tag, um die Antwort zu empfangen. Skripts dürfen ursprungsübergreifend geladen werden.

Mit der CORS-Spezifikation wurden mehrere neue HTTP-Header eingeführt, die ursprungsübergreifende Anforderungen ermöglichen. Wenn ein Browser CORS unterstützt, legt er diese Header für ursprungsübergreifende Anforderungen automatisch fest. Zum Aktivieren von CORS ist kein benutzerdefinierter JavaScript-Code erforderlich.

Die PUT test-Schaltfläche im bereitgestellten Beispiel

Nachfolgend ist ein Beispiel für eine ursprungsübergreifende Anforderung von der Werte-Testschaltfläche an https://cors1.azurewebsites.net/api/values. Der Origin-Header:

  • Gibt die Domäne der Website an, die die Anforderung ausführt.
  • Ist erforderlich und muss sich vom Host unterscheiden.

Allgemeine Header

Request URL: https://cors1.azurewebsites.net/api/values
Request Method: GET
Status Code: 200 OK

Antwortheader

Content-Encoding: gzip
Content-Type: text/plain; charset=utf-8
Server: Microsoft-IIS/10.0
Set-Cookie: ARRAffinity=8f...;Path=/;HttpOnly;Domain=cors1.azurewebsites.net
Transfer-Encoding: chunked
Vary: Accept-Encoding
X-Powered-By: ASP.NET

Anforderungsheader

Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Connection: keep-alive
Host: cors1.azurewebsites.net
Origin: https://cors3.azurewebsites.net
Referer: https://cors3.azurewebsites.net/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0 ...

In OPTIONS-Anforderungen legt der Server den AntwortheaderAccess-Control-Allow-Origin: {allowed origin}-Header in der Antwort fest. Beispielsweise enthält die OPTIONS-Anforderung im zur Verfügung gestellten MusterDelete [EnableCors]-Schaltfläche die folgenden Header:

Allgemeine Header

Request URL: https://cors3.azurewebsites.net/api/TodoItems2/MyDelete2/5
Request Method: OPTIONS
Status Code: 204 No Content

Antwortheader

Access-Control-Allow-Headers: Content-Type,x-custom-header
Access-Control-Allow-Methods: PUT,DELETE,GET,OPTIONS
Access-Control-Allow-Origin: https://cors1.azurewebsites.net
Server: Microsoft-IIS/10.0
Set-Cookie: ARRAffinity=8f...;Path=/;HttpOnly;Domain=cors3.azurewebsites.net
Vary: Origin
X-Powered-By: ASP.NET

Anforderungsheader

Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Access-Control-Request-Headers: content-type
Access-Control-Request-Method: DELETE
Connection: keep-alive
Host: cors3.azurewebsites.net
Origin: https://cors1.azurewebsites.net
Referer: https://cors1.azurewebsites.net/test?number=2
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0

In den vorstehenden Antwortheadern legt der Server den Access-Control-Allow-Origin-Header in der Antwort fest. Der https://cors1.azurewebsites.net-Wert dieses Headers stimmt mit dem Origin-Header aus der Anforderung überein.

Wenn AllowAnyOrigin aufgerufen wird, wird Access-Control-Allow-Origin: * zurückgegeben, der Platzhalterwert. AllowAnyOrigin lässt jeden Ursprung zu.

Wenn die Antwort den Access-Control-Allow-Origin-Header nicht enthält, schlägt die ursprungsübergreifende Anforderung fehl. Insbesondere lässt der Browser die Anforderung nicht zu. Auch wenn der Server eine erfolgreiche Antwort zurückgibt, stellt der Browser die Antwort der Client-App nicht zur Verfügung.

Eine HTTP-Umleitung zu HTTPS bewirkt ein ERR_INVALID_REDIRECT für die CORS-Preflight-Anforderung

Anforderungen an einen Endpunkt über HTTP, die per UseHttpsRedirection an HTTPS weitergeleitet werden, weisen den Fehler ERR_INVALID_REDIRECT on the CORS preflight request auf.

API-Projekte können HTTP-Anforderungen ablehnen, anstatt Anforderungen über UseHttpsRedirection an HTTPS umzuleiten.

CORS in IIS

Bei der Bereitstellung in IIS muss CORS vor der Windows-Authentifizierung ausgeführt werden, wenn der Server nicht für den anonymen Zugriff konfiguriert ist. Zum Unterstützen dieses Szenarios muss das IIS-CORS-Modul installiert und für die App konfiguriert werden.

Testen von CORS

Der Beispieldownload enthält Code zum Testen von CORS. Informationen zum Herunterladen finden Sie hier. Das Beispiel ist ein API-Projekt mit hinzugefügten Razor Pages:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy(name: "MyPolicy",
        policy =>
        {
            policy.WithOrigins("http://example.com",
                    "http://www.contoso.com",
                    "https://cors1.azurewebsites.net",
                    "https://cors3.azurewebsites.net",
                    "https://localhost:44398",
                    "https://localhost:5001")
                .WithMethods("PUT", "DELETE", "GET");
        });
});

builder.Services.AddControllers();
builder.Services.AddRazorPages();

var app = builder.Build();

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

app.UseCors();

app.UseAuthorization();

app.MapControllers();
app.MapRazorPages();

app.Run();

Warnung

WithOrigins("https://localhost:<port>"); sollte nur zum Testen einer Beispiel-App verwendet werden, die dem Code des Downloadbeispiels ähnelt.

Der folgende ValuesController stellt die Endpunkte zum Testen zur Verfügung:

[EnableCors("MyPolicy")]
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
    // GET api/values
    [HttpGet]
    public IActionResult Get() =>
        ControllerContext.MyDisplayRouteInfo();

    // GET api/values/5
    [HttpGet("{id}")]
    public IActionResult Get(int id) =>
        ControllerContext.MyDisplayRouteInfo(id);

    // PUT api/values/5
    [HttpPut("{id}")]
    public IActionResult Put(int id) =>
        ControllerContext.MyDisplayRouteInfo(id);


    // GET: api/values/GetValues2
    [DisableCors]
    [HttpGet("{action}")]
    public IActionResult GetValues2() =>
        ControllerContext.MyDisplayRouteInfo();

}

MyDisplayRouteInfo wird von dem NuGet-Paket Rick.Docs.Samples.RouteInfo bereitgestellt und zeigt Routeninformationen an.

Testen Sie den vorstehenden Beispielcode mit einem der folgenden Ansätze:

  • Verwenden Sie die unter https://cors3.azurewebsites.net/ zur Verfügung gestellte Beispiel-App. Das Beispiel muss nicht heruntergeladen werden.
  • Führen Sie das Beispiel mit dotnet run mit der Standard-URL https://localhost:5001 aus.
  • Führen Sie das Beispiel in Visual Studio aus, wobei der Port für die URL https://localhost:44398 auf 44398 festgelegt ist.

Verwenden eines Browsers mit den F12-Tools:

  • Wählen Sie die Schaltfläche Werte aus, und überprüfen Sie die Header auf der Registerkarte Netzwerk.

  • Wählen Sie die Schaltfläche PUT test aus. Anweisungen zum Anzeigen der OPTIONS-Anforderung finden Sie unter Anzeigen von OPTIONS-Anforderungen. PUT test erstellt zwei Anforderungen, eine OPTIONS-Preflight-Anforderung und die PUT-Anforderung.

  • Wählen Sie die GetValues2 [DisableCors]-Schaltfläche aus, um eine fehlerhafte CORS-Anforderung auszulösen. Wie im Dokument erwähnt, gibt die Antwort „200 (Erfolg)“ zurück, aber die CORS-Anforderung wird nicht ausgeführt. Wählen Sie die Registerkarte Konsole aus, um den CORS-Fehler anzuzeigen. Abhängig vom Browser wird ein Fehler ähnlich dem Folgenden angezeigt:

    Der Zugriff auf Fetch unter 'https://cors1.azurewebsites.net/api/values/GetValues2' vom Ursprung 'https://cors3.azurewebsites.net' wurde durch die CORS-Richtlinie blockiert: In der angeforderten Ressource ist kein „Access-Control-Allow-Origin“-Header vorhanden. Falls eine opake Antwort Ihre Anforderungen erfüllt, legen Sie den Modus der Anforderung auf „no-cors“ fest, um CORS für den Ressourcenabruf zu deaktivieren.

CORS-fähige Endpunkte können mit einem Tool wie cURL oder Fiddler getestet werden. Bei Verwendung eines Tools muss sich der Ursprung der durch den Origin-Header angegebenen Anforderung von dem Host unterscheiden, der die Anforderung empfängt. Wenn die Anforderung auf der Grundlage des Werts des Origin-Headers nicht ursprungsübergreifend ist:

  • Es besteht keine Notwendigkeit, dass die Anforderung durch die CORS-Middleware verarbeitet wird.
  • CORS-Header werden in der Antwort nicht zurückgegeben.

Der folgende Befehl verwendet curl, um eine OPTIONS-Anforderung mit Informationen auszugeben:

curl -X OPTIONS https://cors3.azurewebsites.net/api/TodoItems2/5 -i

Testen von CORS mit dem Attribut [EnableCors] und der RequireCors-Methode

Betrachten Sie den folgenden Code, der Endpunktrouting verwendet, um CORS pro Endpunkt mithilfe von RequireCors zu aktivieren:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy(name: "MyPolicy",
        policy =>
        {
            policy.WithOrigins("http://example.com",
                    "http://www.contoso.com",
                    "https://cors1.azurewebsites.net",
                    "https://cors3.azurewebsites.net",
                    "https://localhost:44398",
                    "https://localhost:5001")
                .WithMethods("PUT", "DELETE", "GET");
        });
});

builder.Services.AddControllers();
builder.Services.AddRazorPages();

var app = builder.Build();

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

app.UseCors();

app.UseAuthorization();

app.UseEndpoints(endpoints =>
{
    endpoints.MapGet("/echo",
        context => context.Response.WriteAsync("echo"))
        .RequireCors("MyPolicy");

    endpoints.MapControllers();
    endpoints.MapRazorPages();
});

app.Run();

Beachten Sie, dass nur der /echo-Endpunkt RequireCors verwendet, um ursprungsübergreifende Anforderungen mithilfe der angegebenen Richtlinie zuzulassen. Die unten angegebenen Controller aktivieren CORS mithilfe des [EnableCors]-Attributs.

Der folgende TodoItems1Controller stellt die Endpunkte zum Testen zur Verfügung:

[Route("api/[controller]")]
[ApiController]
public class TodoItems1Controller : ControllerBase 
{
    // PUT: api/TodoItems1/5
    [HttpPut("{id}")]
    public IActionResult PutTodoItem(int id) {
        if (id < 1) {
            return Content($"ID = {id}");
        }

        return ControllerContext.MyDisplayRouteInfo(id);
    }

    // Delete: api/TodoItems1/5
    [HttpDelete("{id}")]
    public IActionResult MyDelete(int id) =>
        ControllerContext.MyDisplayRouteInfo(id);

    // GET: api/TodoItems1
    [HttpGet]
    public IActionResult GetTodoItems() =>
        ControllerContext.MyDisplayRouteInfo();

    [EnableCors("MyPolicy")]
    [HttpGet("{action}")]
    public IActionResult GetTodoItems2() =>
        ControllerContext.MyDisplayRouteInfo();

    // Delete: api/TodoItems1/MyDelete2/5
    [EnableCors("MyPolicy")]
    [HttpDelete("{action}/{id}")]
    public IActionResult MyDelete2(int id) =>
        ControllerContext.MyDisplayRouteInfo(id);
}

Testen Sie den vorstehenden Code auf der Testseite des bereitgestellten Beispiels.

Die Schaltflächen Delete [EnableCors] und GET [EnableCors] werden erfolgreich ausgeführt, da die Endpunkte über [EnableCors] verfügen und auf Preflight-Anforderungen antworten. Bei den anderen Endpunkten tritt ein Fehler auf. Bei der GET-Schaltfläche tritt ein Fehler auf, da das JavaScript Folgendes sendet:

 headers: {
      "Content-Type": "x-custom-header"
 },

Der folgende TodoItems2Controller stellt ähnliche Endpunkte zur Verfügung, schließt aber expliziten Code zum Antworten auf OPTIONS-Anforderungen ein:

[Route("api/[controller]")]
[ApiController]
public class TodoItems2Controller : ControllerBase
{
    // OPTIONS: api/TodoItems2/5
    [HttpOptions("{id}")]
    public IActionResult PreflightRoute(int id)
    {
        return NoContent();
    }

    // OPTIONS: api/TodoItems2 
    [HttpOptions]
    public IActionResult PreflightRoute()
    {
        return NoContent();
    }

    [HttpPut("{id}")]
    public IActionResult PutTodoItem(int id)
    {
        if (id < 1)
        {
            return BadRequest();
        }

        return ControllerContext.MyDisplayRouteInfo(id);
    }

    // [EnableCors] // Not needed as OPTIONS path provided.
    [HttpDelete("{id}")]
    public IActionResult MyDelete(int id) =>
        ControllerContext.MyDisplayRouteInfo(id);

    // [EnableCors] //  Warning ASP0023 Route '{id}' conflicts with another action route.
    //                  An HTTP request that matches multiple routes results in an ambiguous
    //                  match error.
    [EnableCors("MyPolicy")] // Required for this path.
    [HttpGet]
    public IActionResult GetTodoItems() =>
        ControllerContext.MyDisplayRouteInfo();

    [HttpGet("{action}")]
    public IActionResult GetTodoItems2() =>
        ControllerContext.MyDisplayRouteInfo();

    [EnableCors("MyPolicy")]  // Required for this path.
    [HttpDelete("{action}/{id}")]
    public IActionResult MyDelete2(int id) =>
        ControllerContext.MyDisplayRouteInfo(id);
}

Testen Sie den vorstehenden Code auf der Testseite des bereitgestellten Beispiels. Wählen Sie in der Dropdownliste Controller die Option Preflight und dann Controller festlegen aus. Alle CORS-Aufrufe an die TodoItems2Controller-Endpunkte sind erfolgreich.

Zusätzliche Ressourcen

Von Rick Anderson und Kirk Larkin

In diesem Artikel erfahren Sie, wie Sie CORS in einer ASP.NET Core-App aktivieren.

Die Browsersicherheit verhindert, dass eine Webseite Anforderungen an eine andere Domäne als diejenige stellt, die die Webseite versorgt hat. Diese Einschränkung wird als Richtlinie des gleichen Ursprungs bezeichnet. Die Richtlinie des gleichen Ursprungs verhindert, dass eine schädliche Website sensible Daten von einer anderen Website liest. Manchmal kann es sinnvoll sein, anderen Websites das Senden von ursprungsübergreifenden Anforderungen an Ihre App zu erlauben. Weitere Informationen finden Sie im Mozilla CORS-Artikel.

Ressourcenfreigabe zwischen verschiedenen Ursprüngen (Cross-Origin Resource Sharing, CORS):

  • ist ein W3C-Standard, der einem Server eine weniger strenge Anwendung der Richtlinie des gleichen Ursprungs ermöglicht.
  • ist kein Sicherheitsfeature, CORS lockert die Sicherheit. Eine API wird nicht sicherer, indem sie CORS zulässt. Weitere Informationen finden Sie unter Funktionsweise von CORS.
  • ermöglicht es einem Server, einige ursprungsübergreifende Anforderungen explizit zuzulassen und andere abzulehnen.
  • ist sicherer und flexibler als frühere Techniken wie etwa JSONP.

Anzeigen oder Herunterladen von Beispielcode (Vorgehensweise zum Herunterladen)

Gleicher Ursprung

Zwei URLs haben den gleichen Ursprung, wenn sie identische Schemas, Hosts und Ports aufweisen (RFC 6454).

Diese beiden URLs haben den gleichen Ursprung:

  • https://example.com/foo.html
  • https://example.com/bar.html

Diese URLs haben andere Ursprünge als die vorherigen beiden URLs:

  • https://example.net: andere Domäne
  • https://www.example.com/foo.html: andere Unterdomäne
  • http://example.com/foo.html: anderes Schema
  • https://example.com:9000/foo.html: anderer Port

Aktivieren von CORS

Es gibt es drei Möglichkeiten zum Aktualisieren von CORS:

Die Verwendung des [EnableCors]-Attributs mit einer benannten Richtlinie bietet die beste Kontrolle bei der Begrenzung von Endpunkten, die CORS unterstützen.

Warnung

UseCors muss in der richtigen Reihenfolge aufgerufen werden. Weitere Informationen finden Sie unter Middleware-Reihenfolge. Beispielsweise muss UseCors bei Verwendung von UseResponseCaching vor UseResponseCaching aufgerufen werden.

Jeder Ansatz wird in den folgenden Abschnitten ausführlich beschrieben.

CORS mit benannter Richtlinie und Middleware

CORS-Middleware verarbeitet ursprungsübergreifende Anforderungen. Der folgende Code wendet eine CORS-Richtlinie auf alle Endpunkte der App mit den angegebenen Ursprüngen an:

var  MyAllowSpecificOrigins = "_myAllowSpecificOrigins";

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy(name: MyAllowSpecificOrigins,
                      policy  =>
                      {
                          policy.WithOrigins("http://example.com",
                                              "http://www.contoso.com");
                      });
});

// services.AddResponseCaching();

builder.Services.AddControllers();

var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();

app.UseCors(MyAllowSpecificOrigins);

app.UseAuthorization();

app.MapControllers();

app.Run();

Der vorangehende Code:

  • Legt den Richtliniennamen auf _myAllowSpecificOrigins fest. Der Name der Richtlinie ist frei wählbar.
  • Ruft die Erweiterungsmethode UseCors auf und gibt die CORS-Richtlinie _myAllowSpecificOrigins an. UseCors fügt die CORS-Middleware hinzu. Der Aufruf von UseCors muss nach UseRouting, aber vor UseAuthorization platziert werden. Weitere Informationen finden Sie unter Middleware-Reihenfolge.
  • Ruft AddCors mit einem Lambdaausdruck auf. Der Lambdaausdruck nimmt ein CorsPolicyBuilder-Objekt an. Konfigurationsoptionen wie WithOrigins werden weiter unten in diesem Artikel beschrieben.
  • Aktiviert die CORS-Richtlinie _myAllowSpecificOrigins für alle Controllerendpunkte. Informationen zum Anwenden einer CORS-Richtlinie auf bestimmte Endpunkte finden Sie unter Endpunktrouting.
  • Wenn Sie Antworten zwischenspeichernde Middleware verwenden, rufen Sie UseCors vor UseResponseCaching auf.

Beim Endpunktrouting muss die CORS-Middleware für die Ausführung zwischen den Aufrufen von UseRouting und UseEndpoints konfiguriert werden.

Anweisungen zum Testen von Code ähnlich dem vorstehenden Code finden Sie unter Testen von CORS.

Der Methodenaufruf AddCors fügt dem Dienstcontainer der App CORS-Dienste hinzu:

var  MyAllowSpecificOrigins = "_myAllowSpecificOrigins";

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy(name: MyAllowSpecificOrigins,
                      policy  =>
                      {
                          policy.WithOrigins("http://example.com",
                                              "http://www.contoso.com");
                      });
});

// services.AddResponseCaching();

builder.Services.AddControllers();

var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();

app.UseCors(MyAllowSpecificOrigins);

app.UseAuthorization();

app.MapControllers();

app.Run();

Weitere Informationen finden Sie unter CORS-Richtlinienoptionen in diesem Dokument.

Die CorsPolicyBuilder-Methoden können verkettet werden, wie im folgenden Code gezeigt:

var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy(MyAllowSpecificOrigins,
                          policy =>
                          {
                              policy.WithOrigins("http://example.com",
                                                  "http://www.contoso.com")
                                                  .AllowAnyHeader()
                                                  .AllowAnyMethod();
                          });
});

builder.Services.AddControllers();

var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();

app.UseCors(MyAllowSpecificOrigins);

app.UseAuthorization();

app.MapControllers();

app.Run();

Hinweis: Die angegebene URL darf keinen nachgestellten Schrägstrich (/) enthalten. Wenn die URL mit / beendet wird, gibt der Vergleich false zurück, und es wird kein Header zurückgegeben.

Warnung

UseCors muss nach UseRouting und vor UseAuthorization platziert werden. Dadurch wird sichergestellt, dass CORS-Header sowohl für autorisierte als auch für nicht autorisierte Aufrufe in der Antwort enthalten sind.

Reihenfolge von UseCors und UseStaticFiles

In der Regel wird UseStaticFiles vor UseCors aufgerufen. Apps, die JavaScript zum websiteübergreifenden Abrufen statischer Dateien verwenden, müssen UseCors vor UseStaticFiles aufrufen.

CORS mit Standardrichtlinie und Middleware

Der folgende hervorgehobene Code aktiviert die CORS-Standardrichtlinie:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddDefaultPolicy(
        policy =>
        {
            policy.WithOrigins("http://example.com",
                                "http://www.contoso.com");
        });
});

builder.Services.AddControllers();

var app = builder.Build();

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

app.UseCors();

app.UseAuthorization();

app.MapControllers();

app.Run();

Der vorstehende Code wendet die CORS-Standardrichtlinie auf alle Controllerendpunkte an.

Aktivieren von Cors mit Endpunktrouting

Beim Endpunktrouting kann CORS mithilfe der RequireCors-Sammlung von Erweiterungsmethoden je Endpunkt aktiviert werden:

var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy(name: MyAllowSpecificOrigins,
                      policy =>
                      {
                          policy.WithOrigins("http://example.com",
                                              "http://www.contoso.com");
                      });
});

builder.Services.AddControllers();
builder.Services.AddRazorPages();

var app = builder.Build();

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

app.UseCors();

app.UseAuthorization();

app.UseEndpoints(endpoints =>
{
    endpoints.MapGet("/echo",
        context => context.Response.WriteAsync("echo"))
        .RequireCors(MyAllowSpecificOrigins);

    endpoints.MapControllers()
             .RequireCors(MyAllowSpecificOrigins);

    endpoints.MapGet("/echo2",
        context => context.Response.WriteAsync("echo2"));

    endpoints.MapRazorPages();
});

app.Run();

Für den Code oben gilt:

  • app.UseCors aktiviert die CORS-Middleware. Da keine Standardrichtlinie konfiguriert wurde, wird CORS nicht durch app.UseCors() allein aktiviert.
  • Die /echo- und Controllerendpunkte ermöglichen ursprungsübergreifende Anforderungen mithilfe der angegebenen Richtlinie.
  • Die /echo2- und Razor Pages-Endpunkte ermöglichen keine ursprungsübergreifenden Anforderungen, da keine Standardrichtlinie angegeben wurde.

Das Attribut [DisableCors] deaktiviert CORS nicht, wenn es durch Endpunktrouting mit RequireCors aktiviert wurde.

In ASP.NET Core 7.0 muss das [EnableCors]-Attribut einen Parameter übergeben, andernfalls wird eine ASP0023-Warnung aus einer mehrdeutigen Übereinstimmung auf der Route generiert. In ASP.NET Core 8.0 und höher wird die ASP0023-Warnung nicht generiert.

[Route("api/[controller]")]
[ApiController]
public class TodoItems2Controller : ControllerBase
{
    // OPTIONS: api/TodoItems2/5
    [HttpOptions("{id}")]
    public IActionResult PreflightRoute(int id)
    {
        return NoContent();
    }

    // OPTIONS: api/TodoItems2 
    [HttpOptions]
    public IActionResult PreflightRoute()
    {
        return NoContent();
    }

    [HttpPut("{id}")]
    public IActionResult PutTodoItem(int id)
    {
        if (id < 1)
        {
            return BadRequest();
        }

        return ControllerContext.MyDisplayRouteInfo(id);
    }

    // [EnableCors] // Not needed as OPTIONS path provided.
    [HttpDelete("{id}")]
    public IActionResult MyDelete(int id) =>
        ControllerContext.MyDisplayRouteInfo(id);

    // [EnableCors] //  Warning ASP0023 Route '{id}' conflicts with another action route.
    //                  An HTTP request that matches multiple routes results in an ambiguous
    //                  match error.
    [EnableCors("MyPolicy")] // Required for this path.
    [HttpGet]
    public IActionResult GetTodoItems() =>
        ControllerContext.MyDisplayRouteInfo();

    [HttpGet("{action}")]
    public IActionResult GetTodoItems2() =>
        ControllerContext.MyDisplayRouteInfo();

    [EnableCors("MyPolicy")]  // Required for this path.
    [HttpDelete("{action}/{id}")]
    public IActionResult MyDelete2(int id) =>
        ControllerContext.MyDisplayRouteInfo(id);
}

Anweisungen zum Testen von Code ähnlich dem vorstehenden finden Sie unter Testen von CORS mit dem [EnableCors]-Attribut und der RequireCors-Methode.

Aktivieren von CORS mit Attributen

Das Aktivieren von CORS mit dem [EnableCors]-Attribut und das Anwenden einer benannten Richtlinie lediglich auf die Endpunkte, die CORS erfordern, bietet die genaueste Steuerung.

Das Attribut [EnableCors] stellt eine Alternative zum globalen Anwenden von CORS dar. Das [EnableCors]-Attribut aktiviert CORS für ausgewählte Endpunkte anstelle aller Endpunkte:

  • [EnableCors] gibt die Standardrichtlinie an.
  • [EnableCors("{Policy String}")] gibt eine benannte Richtlinie an.

Das [EnableCors]-Attribut kann auf Folgendes angewendet werden:

  • Razor Page PageModel
  • Controller
  • Controlleraktionsmethode

Mit dem [EnableCors]-Attribut können verschiedene Richtlinien auf Controller, Seitenmodelle oder Aktionsmethoden angewendet werden. Wenn das [EnableCors]-Attribut auf einen Controller, ein Seitenmodell oder eine Aktionsmethode angewendet wird und CORS in Middleware aktiviert ist, werden beide Richtlinien angewendet. Wir raten davon ab, Richtlinien zu kombinieren. Verwenden Sie das [EnableCors]-Attribut oder Middleware, aber nicht beides in derselben App.

Der folgende Code wendet eine andere Richtlinie auf jede Methode an:

[Route("api/[controller]")]
[ApiController]
public class WidgetController : ControllerBase
{
    // GET api/values
    [EnableCors("AnotherPolicy")]
    [HttpGet]
    public ActionResult<IEnumerable<string>> Get()
    {
        return new string[] { "green widget", "red widget" };
    }

    // GET api/values/5
    [EnableCors("Policy1")]
    [HttpGet("{id}")]
    public ActionResult<string> Get(int id)
    {
        return id switch
        {
            1 => "green widget",
            2 => "red widget",
            _ => NotFound(),
        };
    }
}

Mit dem folgenden Code werden zwei CORS-Richtlinien erstellt:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy("Policy1",
        policy =>
        {
            policy.WithOrigins("http://example.com",
                                "http://www.contoso.com");
        });

    options.AddPolicy("AnotherPolicy",
        policy =>
        {
            policy.WithOrigins("http://www.contoso.com")
                                .AllowAnyHeader()
                                .AllowAnyMethod();
        });
});

builder.Services.AddControllers();

var app = builder.Build();

app.UseHttpsRedirection();

app.UseRouting();

app.UseCors();

app.UseAuthorization();

app.MapControllers();

app.Run();

Zum Erzielen der genauesten Kontrolle bei der Begrenzung von CORS-Anforderungen:

  • Verwenden Sie [EnableCors("MyPolicy")] mit einer benannten Richtlinie.
  • Definieren Sie keine Standardrichtlinie.
  • Verwenden Sie kein Endpunktrouting.

Der Code im nächsten Abschnitt entspricht der vorstehenden Liste.

Anweisungen zum Testen von Code ähnlich dem vorstehenden Code finden Sie unter Testen von CORS.

Deaktivieren von CORS

Das Attribut [DisableCors] deaktiviert CORS nicht, wenn es durch Endpunktrouting aktiviert wurde.

Im folgenden Code wird die CORS-Richtlinie "MyPolicy" definiert:

var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy(name: "MyPolicy",
        policy =>
        {
            policy.WithOrigins("http://example.com",
                                "http://www.contoso.com")
                    .WithMethods("PUT", "DELETE", "GET");
        });
});

builder.Services.AddControllers();
builder.Services.AddRazorPages();

var app = builder.Build();

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

app.UseCors();

app.UseAuthorization();

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

app.Run();

Der folgende Code deaktiviert CORS für die Aktion GetValues2:

[EnableCors("MyPolicy")]
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
    // GET api/values
    [HttpGet]
    public IActionResult Get() =>
        ControllerContext.MyDisplayRouteInfo();

    // GET api/values/5
    [HttpGet("{id}")]
    public IActionResult Get(int id) =>
        ControllerContext.MyDisplayRouteInfo(id);

    // PUT api/values/5
    [HttpPut("{id}")]
    public IActionResult Put(int id) =>
        ControllerContext.MyDisplayRouteInfo(id);


    // GET: api/values/GetValues2
    [DisableCors]
    [HttpGet("{action}")]
    public IActionResult GetValues2() =>
        ControllerContext.MyDisplayRouteInfo();

}

Der vorangehende Code:

Anweisungen zum Testen des vorstehenden Codes finden Sie unter Testen von CORS.

CORS-Richtlinienoptionen

In diesem Abschnitt werden die verschiedenen Optionen beschrieben, die in einer CORS-Richtlinie festgelegt werden können:

AddPolicy wird in Program.cs aufgerufen. Für einige Optionen kann es nützlich sein, zuerst den Abschnitt Funktionsweise von CORS zu lesen.

Festlegen der zulässigen Ursprünge

AllowAnyOrigin: Ermöglicht CORS-Anforderungen von allen Ursprüngen mit einem beliebigen Schema (http oder https). AllowAnyOrigin ist unsicher, da jede Website ursprungsübergreifende Anforderungen an die App vornehmen kann.

Hinweis

Die Angabe von AllowAnyOrigin und AllowCredentials stellt eine unsichere Konfiguration dar und kann zu siteübergreifender Anforderungsfälschung führen. Der CORS-Dienst gibt eine ungültige CORS-Antwort zurück, wenn eine App mit beiden Methoden konfiguriert ist.

AllowAnyOrigin wirkt sich auf Preflight-Anforderungen und den Access-Control-Allow-Origin-Header aus. Weitere Informationen finden Sie im Abschnitt Preflight-Anforderungen.

SetIsOriginAllowedToAllowWildcardSubdomains: Legt die IsOriginAllowed-Eigenschaft der Richtlinie als Funktion fest, die Ursprüngen bei der Prüfung des Ursprungs auf Zulässigkeit die Übereinstimmung mit einer konfigurierten Platzhalterdomäne ermöglicht.

var MyAllowSpecificOrigins = "_MyAllowSubdomainPolicy";

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy(name: MyAllowSpecificOrigins,
        policy =>
        {
            policy.WithOrigins("https://*.example.com")
                .SetIsOriginAllowedToAllowWildcardSubdomains();
        });
});

builder.Services.AddControllers();

var app = builder.Build();

Festlegen der zulässigen HTTP-Methoden

AllowAnyMethod:

  • Lässt jede HTTP-Methode zu:
  • Wirkt sich auf Preflight-Anforderungen und den Access-Control-Allow-Methods-Header aus. Weitere Informationen finden Sie im Abschnitt Preflight-Anforderungen.

Festlegen der zulässigen Anforderungsheader

Rufen Sie WithHeaders auf, und geben Sie die zulässigen Header an, um das Senden bestimmter Header, die als Autorenanforderungsheader bezeichnet werden, in einer CORS-Anforderung zuzulassen:

using Microsoft.Net.Http.Headers;

var MyAllowSpecificOrigins = "_MyAllowSubdomainPolicy";

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy(name: MyAllowSpecificOrigins,
       policy =>
       {
           policy.WithOrigins("http://example.com")
                  .WithHeaders(HeaderNames.ContentType, "x-custom-header");
       });
});

builder.Services.AddControllers();

var app = builder.Build();

Rufen Sie zum Zulassen aller AutorenanforderungsheaderAllowAnyHeader auf:

var MyAllowSpecificOrigins = "_MyAllowSubdomainPolicy";

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy(name: MyAllowSpecificOrigins,
        policy =>
        {
            policy.WithOrigins("https://*.example.com")
                   .AllowAnyHeader();
        });
});

builder.Services.AddControllers();

var app = builder.Build();

AllowAnyHeader wirkt sich auf Preflight-Anforderungen und den Header Access-Control-Request-Headers aus. Weitere Informationen finden Sie im Abschnitt Preflight-Anforderungen.

Eine Zuordnung einer CORS-Middleware-Richtlinie zu bestimmten Headern, die in WithHeaders angegeben werden, ist nur möglich, wenn die in Access-Control-Request-Headers gesendeten Header exakt mit den in WithHeaders angegebenen Headern übereinstimmen.

Betrachten Sie beispielsweise eine App, die wie folgt konfiguriert ist:

app.UseCors(policy => policy.WithHeaders(HeaderNames.CacheControl));

CORS Middleware lehnt eine Preflight-Anforderung mit dem folgenden Anforderungsheader ab, da Content-Language (HeaderNames.ContentLanguage) nicht in WithHeaders aufgeführt ist:

Access-Control-Request-Headers: Cache-Control, Content-Language

Die App gibt eine 200 OK-Antwort zurück, sendet die CORS-Header jedoch nicht zurück. Daher versucht der Browser die ursprungsübergreifende Anforderung nicht.

Festlegen der verfügbar gemachten Antwortheader

Standardmäßig macht der Browser nicht alle Antwortheader für die App verfügbar. Weitere Informationen finden Sie unter W3C Cross-Origin Resource Sharing (Terminologie): Einfacher Antwortheader.

Standardmäßig sind folgende Antwortheader verfügbar:

  • Cache-Control
  • Content-Language
  • Content-Type
  • Expires
  • Last-Modified
  • Pragma

Die CORS-Spezifikation ruft diese Header als einfache Antwortheader auf. Rufen Sie WithExposedHeaders auf, um andere Header für die App verfügbar zu machen:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy("MyExposeResponseHeadersPolicy",
        policy =>
        {
            policy.WithOrigins("https://*.example.com")
                   .WithExposedHeaders("x-custom-header");
        });
});

builder.Services.AddControllers();

var app = builder.Build();

Anmeldeinformationen in ursprungsübergreifenden Anforderungen

Für Anmeldeinformationen ist in einer CORS-Anforderung eine besondere Behandlung erforderlich. Standardmäßig sendet der Browser mit einer ursprungsübergreifenden Anforderung keine Anmeldeinformationen. Zu den Anmeldeinformationen gehören cookies und HTTP-Authentifizierungsschemas. Zum Senden von Anmeldeinformationen mit einer ursprungsübergreifenden Anforderung muss der Client XMLHttpRequest.withCredentials auf true festlegen.

Mit direkter Verwendung von XMLHttpRequest:

var xhr = new XMLHttpRequest();
xhr.open('get', 'https://www.example.com/api/test');
xhr.withCredentials = true;

Mithilfe von jQuery:

$.ajax({
  type: 'get',
  url: 'https://www.example.com/api/test',
  xhrFields: {
    withCredentials: true
  }
});

Mithilfe der Fetch-API:

fetch('https://www.example.com/api/test', {
    credentials: 'include'
});

Der Server muss die Anmeldeinformationen zulassen. Rufen Sie AllowCredentials auf, um ursprungsübergreifende Anmeldeinformationen zuzulassen:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy("MyMyAllowCredentialsPolicy",
        policy =>
        {
            policy.WithOrigins("http://example.com")
                   .AllowCredentials();
        });
});

builder.Services.AddControllers();

var app = builder.Build();

Die HTTP-Antwort enthält einen Access-Control-Allow-Credentials-Header, der dem Browser mitteilt, dass der Server Anmeldeinformationen für eine ursprungsübergreifende Anforderung zulässt.

Wenn der Browser Anmeldeinformationen sendet, die Antwort aber keinen gültigen Access-Control-Allow-Credentials-Header enthält, macht der Browser die Antwort für die App nicht verfügbar, und die ursprungsübergreifende Anforderung schlägt fehl.

Das Zulassen von ursprungsübergreifenden Anmeldeinformationen ist ein Sicherheitsrisiko. Eine Website in einer anderen Domäne kann die Anmeldeinformationen eines angemeldeten Benutzers im Namen des Benutzers ohne dessen Wissen an die App senden.

Die CORS-Spezifikation besagt ferner, dass das Festlegen von Ursprüngen auf "*" (alle Ursprünge) ungültig ist, wenn der Access-Control-Allow-Credentials-Header vorhanden ist.

Preflight-Anforderungen

Bei einigen CORS-Anforderungen sendet der Browser vor der eigentlichen Anforderung eine zusätzliche OPTIONS-Anforderung. Diese Anforderung wird als Preflight-Anforderung bezeichnet. Der Browser kann die Preflight-Anforderung überspringen, wenn alle folgenden Bedingungen erfüllt sind:

  • Die Anforderungsmethode ist GET, HEAD oder POST.
  • Die App legt keine anderen Anforderungsheader als Accept, Accept-Language, Content-Language, Content-Type oder Last-Event-ID fest.
  • Der Header Content-Type hat, sofern er festgelegt ist, einen der folgenden Werte:
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

Die für die Clientanforderung festgelegte Regel für Anforderungsheader gilt für Header, die die App durch Aufrufen von setRequestHeader für das XMLHttpRequest-Objekt festlegt. In der CORS-Spezifikation werden diese Header als Autorenanforderungsheader bezeichnet. Die Regel gilt nicht für Header, die vom Browser festgelegt werden können, wie etwa User-Agent, Host oder Content-Length.

Nachfolgend ist eine Beispielantwort ähnlich der Preflight-Anforderung, wie sie über die Schaltfläche [Put test] im Abschnitt Testen von CORS dieses Dokuments vorgenommen wird.

General:
Request URL: https://cors3.azurewebsites.net/api/values/5
Request Method: OPTIONS
Status Code: 204 No Content

Response Headers:
Access-Control-Allow-Methods: PUT,DELETE,GET
Access-Control-Allow-Origin: https://cors1.azurewebsites.net
Server: Microsoft-IIS/10.0
Set-Cookie: ARRAffinity=8f8...8;Path=/;HttpOnly;Domain=cors1.azurewebsites.net
Vary: Origin

Request Headers:
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Access-Control-Request-Method: PUT
Connection: keep-alive
Host: cors3.azurewebsites.net
Origin: https://cors1.azurewebsites.net
Referer: https://cors1.azurewebsites.net/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0

Die Preflight-Anforderung verwendet die HTTP OPTIONS-Methode. Sie kann die folgenden Header enthalten:

Wenn die Preflight-Anforderung abgelehnt wird, gibt die App eine 200 OK-Antwort zurück, legt aber die CORS-Header nicht fest. Daher versucht der Browser die ursprungsübergreifende Anforderung nicht. Ein Beispiel für eine verweigerte Preflight-Anforderung finden Sie im Abschnitt Testen von CORS in diesem Dokument.

Bei Verwendung der F12-Tools zeigt die Konsolen-App je nach Browser einen Fehler ähnlich einem der folgenden an:

  • Firefox: Ursprungsübergreifende Anforderung blockiert: Die Richtlinie des gleichen Ursprungs lässt das Lesen der Remoteressource unter https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5 nicht zu. (Grund: CORS-Anforderung war nicht erfolgreich). Weitere Informationen
  • Chromium-basiert: Der Zugriff auf Fetch unter „https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5“ vom Ursprung „https://cors3.azurewebsites.net“ wurde durch die CORS-Richtlinie blockiert: Die Antwort auf eine Preflight-Anforderung hat die Zugriffssteuerungsprüfung nicht bestanden: Für die angeforderte Ressource ist kein „Access-Control-Allow-Origin“-Header vorhanden. Falls eine opake Antwort Ihre Anforderungen erfüllt, legen Sie den Modus der Anforderung auf „no-cors“ fest, um CORS für den Ressourcenabruf zu deaktivieren.

Rufen Sie WithHeaders auf, um bestimmte Header zuzulassen:

using Microsoft.Net.Http.Headers;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy("MyAllowHeadersPolicy",
        policy =>
        {
        policy.WithOrigins("http://example.com")
                   .WithHeaders(HeaderNames.ContentType, "x-custom-header");
        });
});

builder.Services.AddControllers();

var app = builder.Build();

Rufen Sie zum Zulassen aller AutorenanforderungsheaderAllowAnyHeader auf:

using Microsoft.Net.Http.Headers;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy("MyAllowAllHeadersPolicy",
        policy =>
        {
            policy.WithOrigins("https://*.example.com")
                   .AllowAnyHeader();
        });
});

builder.Services.AddControllers();

var app = builder.Build();

Browser sind in der Festlegung von Access-Control-Request-Headers nicht konsistent. Hier gelten entweder:

  • Die Header sind auf einen anderen Wert als "*" festgelegt
  • AllowAnyHeader wird aufgerufen: Schließen Sie mindestens Accept, Content-Type und Origin sowie alle benutzerdefinierten Header ein, die Sie unterstützen möchten.

Code für automatische Preflight-Anforderungen

Die CORS-Richtlinie wird auf eine dieser Weisen angewendet:

  • Global durch Aufrufen von app.UseCors in Program.cs.
  • Mithilfe des [EnableCors]-Attributs.

ASP.NET Core antwortet auf die Preflight-Anforderung OPTIONS.

Im Abschnitt Testen von CORS dieses Dokuments wird dieses Verhalten veranschaulicht.

[HttpOptions]-Attribut für Preflight-Anforderungen

Wenn CORS mit der entsprechenden Richtlinie aktiviert ist, reagiert ASP.NET Core in der Regel automatisch auf CORS-Preflight-Anforderungen.

Der folgende Code verwendet das [HttpOptions]-Attribut, um Endpunkte für OPTIONS-Anforderungen zu erstellen:

[Route("api/[controller]")]
[ApiController]
public class TodoItems2Controller : ControllerBase
{
    // OPTIONS: api/TodoItems2/5
    [HttpOptions("{id}")]
    public IActionResult PreflightRoute(int id)
    {
        return NoContent();
    }

    // OPTIONS: api/TodoItems2 
    [HttpOptions]
    public IActionResult PreflightRoute()
    {
        return NoContent();
    }

    [HttpPut("{id}")]
    public IActionResult PutTodoItem(int id)
    {
        if (id < 1)
        {
            return BadRequest();
        }

        return ControllerContext.MyDisplayRouteInfo(id);
    }

Anweisungen zum Testen des vorstehenden Codes finden Sie unter Testen von CORS mit dem [EnableCors]-Attribut und der RequireCors-Methode.

Festlegen der Preflight-Ablaufzeit

Der Access-Control-Max-Age-Header gibt an, wie lange die Antwort auf die Preflight-Anforderung zwischengespeichert werden kann. Rufen Sie SetPreflightMaxAge auf, um diesen Header festzulegen:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy("MySetPreflightExpirationPolicy",
        policy =>
        {
            policy.WithOrigins("http://example.com")
                   .SetPreflightMaxAge(TimeSpan.FromSeconds(2520));
        });
});

builder.Services.AddControllers();

var app = builder.Build();

Aktivieren von CORS auf einem Endpunkt

Funktionsweise von CORS

In diesem Abschnitt wird beschrieben, was in einer CORS-Anforderung auf der Ebene der HTTP-Nachrichten geschieht.

  • CORS ist kein Sicherheitsfeature. CORS ist ein W3C-Standard, der einem Server eine weniger strenge Anwendung der Richtlinie desselben Ursprungs ermöglicht.
    • Beispielsweise könnte ein böswilliger Akteur Cross-Site Scripting (XSS) auf Ihre Website anwenden und eine websiteübergreifende Anforderung an seine CORS-fähige Website vornehmen, um Informationen zu stehlen.
  • Durch Zulassen von CORS wird eine API wird nicht sicherer.
    • Das Durchsetzen von CORS liegt in der Zuständigkeit des Clients (Browsers). Der Server führt die Anforderung aus und gibt die Antwort zurück. Es ist der Client, der einen Fehler zurückgibt und die Antwort blockiert. Beispielsweise wird für jedes der folgenden Tools die Serverantwort angezeigt:
  • Es stellt eine Möglichkeit für einen Server dar, Browsern die Ausführung einer ursprungsübergreifenden XHR- oder Fetch-API-Anforderung zu erlauben, die andernfalls verboten wäre.
    • Browser ohne CORS können keine ursprungsübergreifenden Anforderungen ausführen. Vor CORS wurde JSONP verwendet, um diese Einschränkung zu umgehen. JSONP verwendet nicht XHR, es verwendet das <script>-Tag, um die Antwort zu empfangen. Skripts dürfen ursprungsübergreifend geladen werden.

Mit der CORS-Spezifikation wurden mehrere neue HTTP-Header eingeführt, die ursprungsübergreifende Anforderungen ermöglichen. Wenn ein Browser CORS unterstützt, legt er diese Header für ursprungsübergreifende Anforderungen automatisch fest. Zum Aktivieren von CORS ist kein benutzerdefinierter JavaScript-Code erforderlich.

Die PUT test-Schaltfläche im bereitgestellten Beispiel

Nachfolgend ist ein Beispiel für eine ursprungsübergreifende Anforderung von der Werte-Testschaltfläche an https://cors1.azurewebsites.net/api/values. Der Origin-Header:

  • Gibt die Domäne der Website an, die die Anforderung ausführt.
  • Ist erforderlich und muss sich vom Host unterscheiden.

Allgemeine Header

Request URL: https://cors1.azurewebsites.net/api/values
Request Method: GET
Status Code: 200 OK

Antwortheader

Content-Encoding: gzip
Content-Type: text/plain; charset=utf-8
Server: Microsoft-IIS/10.0
Set-Cookie: ARRAffinity=8f...;Path=/;HttpOnly;Domain=cors1.azurewebsites.net
Transfer-Encoding: chunked
Vary: Accept-Encoding
X-Powered-By: ASP.NET

Anforderungsheader

Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Connection: keep-alive
Host: cors1.azurewebsites.net
Origin: https://cors3.azurewebsites.net
Referer: https://cors3.azurewebsites.net/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0 ...

In OPTIONS-Anforderungen legt der Server den AntwortheaderAccess-Control-Allow-Origin: {allowed origin}-Header in der Antwort fest. Beispielsweise enthält die OPTIONS-Anforderung im zur Verfügung gestellten MusterDelete [EnableCors]-Schaltfläche die folgenden Header:

Allgemeine Header

Request URL: https://cors3.azurewebsites.net/api/TodoItems2/MyDelete2/5
Request Method: OPTIONS
Status Code: 204 No Content

Antwortheader

Access-Control-Allow-Headers: Content-Type,x-custom-header
Access-Control-Allow-Methods: PUT,DELETE,GET,OPTIONS
Access-Control-Allow-Origin: https://cors1.azurewebsites.net
Server: Microsoft-IIS/10.0
Set-Cookie: ARRAffinity=8f...;Path=/;HttpOnly;Domain=cors3.azurewebsites.net
Vary: Origin
X-Powered-By: ASP.NET

Anforderungsheader

Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Access-Control-Request-Headers: content-type
Access-Control-Request-Method: DELETE
Connection: keep-alive
Host: cors3.azurewebsites.net
Origin: https://cors1.azurewebsites.net
Referer: https://cors1.azurewebsites.net/test?number=2
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0

In den vorstehenden Antwortheadern legt der Server den Access-Control-Allow-Origin-Header in der Antwort fest. Der https://cors1.azurewebsites.net-Wert dieses Headers stimmt mit dem Origin-Header aus der Anforderung überein.

Wenn AllowAnyOrigin aufgerufen wird, wird Access-Control-Allow-Origin: * zurückgegeben, der Platzhalterwert. AllowAnyOrigin lässt jeden Ursprung zu.

Wenn die Antwort den Access-Control-Allow-Origin-Header nicht enthält, schlägt die ursprungsübergreifende Anforderung fehl. Insbesondere lässt der Browser die Anforderung nicht zu. Auch wenn der Server eine erfolgreiche Antwort zurückgibt, stellt der Browser die Antwort der Client-App nicht zur Verfügung.

Eine HTTP-Umleitung zu HTTPS bewirkt ein ERR_INVALID_REDIRECT für die CORS-Preflight-Anforderung

Anforderungen an einen Endpunkt über HTTP, die per UseHttpsRedirection an HTTPS weitergeleitet werden, weisen den Fehler ERR_INVALID_REDIRECT on the CORS preflight request auf.

API-Projekte können HTTP-Anforderungen ablehnen, anstatt Anforderungen über UseHttpsRedirection an HTTPS umzuleiten.

CORS in IIS

Bei der Bereitstellung in IIS muss CORS vor der Windows-Authentifizierung ausgeführt werden, wenn der Server nicht für den anonymen Zugriff konfiguriert ist. Zum Unterstützen dieses Szenarios muss das IIS-CORS-Modul installiert und für die App konfiguriert werden.

Testen von CORS

Der Beispieldownload enthält Code zum Testen von CORS. Informationen zum Herunterladen finden Sie hier. Das Beispiel ist ein API-Projekt mit hinzugefügten Razor Pages:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy(name: "MyPolicy",
        policy =>
        {
            policy.WithOrigins("http://example.com",
                    "http://www.contoso.com",
                    "https://cors1.azurewebsites.net",
                    "https://cors3.azurewebsites.net",
                    "https://localhost:44398",
                    "https://localhost:5001")
                .WithMethods("PUT", "DELETE", "GET");
        });
});

builder.Services.AddControllers();
builder.Services.AddRazorPages();

var app = builder.Build();

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

app.UseCors();

app.UseAuthorization();

app.MapControllers();
app.MapRazorPages();

app.Run();

Warnung

WithOrigins("https://localhost:<port>"); sollte nur zum Testen einer Beispiel-App verwendet werden, die dem Code des Downloadbeispiels ähnelt.

Der folgende ValuesController stellt die Endpunkte zum Testen zur Verfügung:

[EnableCors("MyPolicy")]
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
    // GET api/values
    [HttpGet]
    public IActionResult Get() =>
        ControllerContext.MyDisplayRouteInfo();

    // GET api/values/5
    [HttpGet("{id}")]
    public IActionResult Get(int id) =>
        ControllerContext.MyDisplayRouteInfo(id);

    // PUT api/values/5
    [HttpPut("{id}")]
    public IActionResult Put(int id) =>
        ControllerContext.MyDisplayRouteInfo(id);


    // GET: api/values/GetValues2
    [DisableCors]
    [HttpGet("{action}")]
    public IActionResult GetValues2() =>
        ControllerContext.MyDisplayRouteInfo();

}

MyDisplayRouteInfo wird von dem NuGet-Paket Rick.Docs.Samples.RouteInfo bereitgestellt und zeigt Routeninformationen an.

Testen Sie den vorstehenden Beispielcode mit einem der folgenden Ansätze:

  • Verwenden Sie die unter https://cors3.azurewebsites.net/ zur Verfügung gestellte Beispiel-App. Das Beispiel muss nicht heruntergeladen werden.
  • Führen Sie das Beispiel mit dotnet run mit der Standard-URL https://localhost:5001 aus.
  • Führen Sie das Beispiel in Visual Studio aus, wobei der Port für die URL https://localhost:44398 auf 44398 festgelegt ist.

Verwenden eines Browsers mit den F12-Tools:

  • Wählen Sie die Schaltfläche Werte aus, und überprüfen Sie die Header auf der Registerkarte Netzwerk.

  • Wählen Sie die Schaltfläche PUT test aus. Anweisungen zum Anzeigen der OPTIONS-Anforderung finden Sie unter Anzeigen von OPTIONS-Anforderungen. PUT test erstellt zwei Anforderungen, eine OPTIONS-Preflight-Anforderung und die PUT-Anforderung.

  • Wählen Sie die GetValues2 [DisableCors]-Schaltfläche aus, um eine fehlerhafte CORS-Anforderung auszulösen. Wie im Dokument erwähnt, gibt die Antwort „200 (Erfolg)“ zurück, aber die CORS-Anforderung wird nicht ausgeführt. Wählen Sie die Registerkarte Konsole aus, um den CORS-Fehler anzuzeigen. Abhängig vom Browser wird ein Fehler ähnlich dem Folgenden angezeigt:

    Der Zugriff auf Fetch unter 'https://cors1.azurewebsites.net/api/values/GetValues2' vom Ursprung 'https://cors3.azurewebsites.net' wurde durch die CORS-Richtlinie blockiert: In der angeforderten Ressource ist kein „Access-Control-Allow-Origin“-Header vorhanden. Falls eine opake Antwort Ihre Anforderungen erfüllt, legen Sie den Modus der Anforderung auf „no-cors“ fest, um CORS für den Ressourcenabruf zu deaktivieren.

CORS-fähige Endpunkte können mit einem Tool wie cURL oder Fiddler getestet werden. Bei Verwendung eines Tools muss sich der Ursprung der durch den Origin-Header angegebenen Anforderung von dem Host unterscheiden, der die Anforderung empfängt. Wenn die Anforderung auf der Grundlage des Werts des Origin-Headers nicht ursprungsübergreifend ist:

  • Es besteht keine Notwendigkeit, dass die Anforderung durch die CORS-Middleware verarbeitet wird.
  • CORS-Header werden in der Antwort nicht zurückgegeben.

Der folgende Befehl verwendet curl, um eine OPTIONS-Anforderung mit Informationen auszugeben:

curl -X OPTIONS https://cors3.azurewebsites.net/api/TodoItems2/5 -i

Testen von CORS mit dem Attribut [EnableCors] und der RequireCors-Methode

Betrachten Sie den folgenden Code, der Endpunktrouting verwendet, um CORS pro Endpunkt mithilfe von RequireCors zu aktivieren:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy(name: "MyPolicy",
        policy =>
        {
            policy.WithOrigins("http://example.com",
                    "http://www.contoso.com",
                    "https://cors1.azurewebsites.net",
                    "https://cors3.azurewebsites.net",
                    "https://localhost:44398",
                    "https://localhost:5001")
                .WithMethods("PUT", "DELETE", "GET");
        });
});

builder.Services.AddControllers();
builder.Services.AddRazorPages();

var app = builder.Build();

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

app.UseCors();

app.UseAuthorization();

app.UseEndpoints(endpoints =>
{
    endpoints.MapGet("/echo",
        context => context.Response.WriteAsync("echo"))
        .RequireCors("MyPolicy");

    endpoints.MapControllers();
    endpoints.MapRazorPages();
});

app.Run();

Beachten Sie, dass nur der /echo-Endpunkt RequireCors verwendet, um ursprungsübergreifende Anforderungen mithilfe der angegebenen Richtlinie zuzulassen. Die unten angegebenen Controller aktivieren CORS mithilfe des [EnableCors]-Attributs.

Der folgende TodoItems1Controller stellt die Endpunkte zum Testen zur Verfügung:

[Route("api/[controller]")]
[ApiController]
public class TodoItems1Controller : ControllerBase 
{
    // PUT: api/TodoItems1/5
    [HttpPut("{id}")]
    public IActionResult PutTodoItem(int id) {
        if (id < 1) {
            return Content($"ID = {id}");
        }

        return ControllerContext.MyDisplayRouteInfo(id);
    }

    // Delete: api/TodoItems1/5
    [HttpDelete("{id}")]
    public IActionResult MyDelete(int id) =>
        ControllerContext.MyDisplayRouteInfo(id);

    // GET: api/TodoItems1
    [HttpGet]
    public IActionResult GetTodoItems() =>
        ControllerContext.MyDisplayRouteInfo();

    [EnableCors("MyPolicy")]
    [HttpGet("{action}")]
    public IActionResult GetTodoItems2() =>
        ControllerContext.MyDisplayRouteInfo();

    // Delete: api/TodoItems1/MyDelete2/5
    [EnableCors("MyPolicy")]
    [HttpDelete("{action}/{id}")]
    public IActionResult MyDelete2(int id) =>
        ControllerContext.MyDisplayRouteInfo(id);
}

Testen Sie den vorstehenden Code auf der Testseite des bereitgestellten Beispiels.

Die Schaltflächen Delete [EnableCors] und GET [EnableCors] werden erfolgreich ausgeführt, da die Endpunkte über [EnableCors] verfügen und auf Preflight-Anforderungen antworten. Bei den anderen Endpunkten tritt ein Fehler auf. Bei der GET-Schaltfläche tritt ein Fehler auf, da das JavaScript Folgendes sendet:

 headers: {
      "Content-Type": "x-custom-header"
 },

Der folgende TodoItems2Controller stellt ähnliche Endpunkte zur Verfügung, schließt aber expliziten Code zum Antworten auf OPTIONS-Anforderungen ein:

[Route("api/[controller]")]
[ApiController]
public class TodoItems2Controller : ControllerBase
{
    // OPTIONS: api/TodoItems2/5
    [HttpOptions("{id}")]
    public IActionResult PreflightRoute(int id)
    {
        return NoContent();
    }

    // OPTIONS: api/TodoItems2 
    [HttpOptions]
    public IActionResult PreflightRoute()
    {
        return NoContent();
    }

    [HttpPut("{id}")]
    public IActionResult PutTodoItem(int id)
    {
        if (id < 1)
        {
            return BadRequest();
        }

        return ControllerContext.MyDisplayRouteInfo(id);
    }

    // [EnableCors] // Not needed as OPTIONS path provided.
    [HttpDelete("{id}")]
    public IActionResult MyDelete(int id) =>
        ControllerContext.MyDisplayRouteInfo(id);

    // [EnableCors] //  Warning ASP0023 Route '{id}' conflicts with another action route.
    //                  An HTTP request that matches multiple routes results in an ambiguous
    //                  match error.
    [EnableCors("MyPolicy")] // Required for this path.
    [HttpGet]
    public IActionResult GetTodoItems() =>
        ControllerContext.MyDisplayRouteInfo();

    [HttpGet("{action}")]
    public IActionResult GetTodoItems2() =>
        ControllerContext.MyDisplayRouteInfo();

    [EnableCors("MyPolicy")]  // Required for this path.
    [HttpDelete("{action}/{id}")]
    public IActionResult MyDelete2(int id) =>
        ControllerContext.MyDisplayRouteInfo(id);
}

Testen Sie den vorstehenden Code auf der Testseite des bereitgestellten Beispiels. Wählen Sie in der Dropdownliste Controller die Option Preflight und dann Controller festlegen aus. Alle CORS-Aufrufe an die TodoItems2Controller-Endpunkte sind erfolgreich.

Zusätzliche Ressourcen

Von Rick Anderson und Kirk Larkin

In diesem Artikel erfahren Sie, wie Sie CORS in einer ASP.NET Core-App aktivieren.

Die Browsersicherheit verhindert, dass eine Webseite Anforderungen an eine andere Domäne als diejenige stellt, die die Webseite versorgt hat. Diese Einschränkung wird als Richtlinie des gleichen Ursprungs bezeichnet. Die Richtlinie des gleichen Ursprungs verhindert, dass eine schädliche Website sensible Daten von einer anderen Website liest. Manchmal kann es sinnvoll sein, anderen Websites das Senden von ursprungsübergreifenden Anforderungen an Ihre App zu erlauben. Weitere Informationen finden Sie im Mozilla CORS-Artikel.

Ressourcenfreigabe zwischen verschiedenen Ursprüngen (Cross-Origin Resource Sharing, CORS):

  • ist ein W3C-Standard, der einem Server eine weniger strenge Anwendung der Richtlinie des gleichen Ursprungs ermöglicht.
  • ist kein Sicherheitsfeature, CORS lockert die Sicherheit. Eine API wird nicht sicherer, indem sie CORS zulässt. Weitere Informationen finden Sie unter Funktionsweise von CORS.
  • ermöglicht es einem Server, einige ursprungsübergreifende Anforderungen explizit zuzulassen und andere abzulehnen.
  • ist sicherer und flexibler als frühere Techniken wie etwa JSONP.

Anzeigen oder Herunterladen von Beispielcode (Vorgehensweise zum Herunterladen)

Gleicher Ursprung

Zwei URLs haben den gleichen Ursprung, wenn sie identische Schemas, Hosts und Ports aufweisen (RFC 6454).

Diese beiden URLs haben den gleichen Ursprung:

  • https://example.com/foo.html
  • https://example.com/bar.html

Diese URLs haben andere Ursprünge als die vorherigen beiden URLs:

  • https://example.net: andere Domäne
  • https://www.example.com/foo.html: andere Unterdomäne
  • http://example.com/foo.html: anderes Schema
  • https://example.com:9000/foo.html: anderer Port

Aktivieren von CORS

Es gibt es drei Möglichkeiten zum Aktualisieren von CORS:

Die Verwendung des [EnableCors]-Attributs mit einer benannten Richtlinie bietet die beste Kontrolle bei der Begrenzung von Endpunkten, die CORS unterstützen.

Warnung

UseCors muss in der richtigen Reihenfolge aufgerufen werden. Weitere Informationen finden Sie unter Middleware-Reihenfolge. Beispielsweise muss UseCors bei Verwendung von UseResponseCaching vor UseResponseCaching aufgerufen werden.

Jeder Ansatz wird in den folgenden Abschnitten ausführlich beschrieben.

CORS mit benannter Richtlinie und Middleware

CORS-Middleware verarbeitet ursprungsübergreifende Anforderungen. Der folgende Code wendet eine CORS-Richtlinie auf alle Endpunkte der App mit den angegebenen Ursprüngen an:

var  MyAllowSpecificOrigins = "_myAllowSpecificOrigins";

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy(name: MyAllowSpecificOrigins,
                      policy  =>
                      {
                          policy.WithOrigins("http://example.com",
                                              "http://www.contoso.com");
                      });
});

// services.AddResponseCaching();

builder.Services.AddControllers();

var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();

app.UseCors(MyAllowSpecificOrigins);

app.UseAuthorization();

app.MapControllers();

app.Run();

Der vorangehende Code:

  • Legt den Richtliniennamen auf _myAllowSpecificOrigins fest. Der Name der Richtlinie ist frei wählbar.
  • Ruft die Erweiterungsmethode UseCors auf und gibt die CORS-Richtlinie _myAllowSpecificOrigins an. UseCors fügt die CORS-Middleware hinzu. Der Aufruf von UseCors muss nach UseRouting, aber vor UseAuthorization platziert werden. Weitere Informationen finden Sie unter Middleware-Reihenfolge.
  • Ruft AddCors mit einem Lambdaausdruck auf. Der Lambdaausdruck nimmt ein CorsPolicyBuilder-Objekt an. Konfigurationsoptionen wie WithOrigins werden weiter unten in diesem Artikel beschrieben.
  • Aktiviert die CORS-Richtlinie _myAllowSpecificOrigins für alle Controllerendpunkte. Informationen zum Anwenden einer CORS-Richtlinie auf bestimmte Endpunkte finden Sie unter Endpunktrouting.
  • Wenn Sie Antworten zwischenspeichernde Middleware verwenden, rufen Sie UseCors vor UseResponseCaching auf.

Beim Endpunktrouting muss die CORS-Middleware für die Ausführung zwischen den Aufrufen von UseRouting und UseEndpoints konfiguriert werden.

Anweisungen zum Testen von Code ähnlich dem vorstehenden Code finden Sie unter Testen von CORS.

Der Methodenaufruf AddCors fügt dem Dienstcontainer der App CORS-Dienste hinzu:

var  MyAllowSpecificOrigins = "_myAllowSpecificOrigins";

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy(name: MyAllowSpecificOrigins,
                      policy  =>
                      {
                          policy.WithOrigins("http://example.com",
                                              "http://www.contoso.com");
                      });
});

// services.AddResponseCaching();

builder.Services.AddControllers();

var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();

app.UseCors(MyAllowSpecificOrigins);

app.UseAuthorization();

app.MapControllers();

app.Run();

Weitere Informationen finden Sie unter CORS-Richtlinienoptionen in diesem Dokument.

Die CorsPolicyBuilder-Methoden können verkettet werden, wie im folgenden Code gezeigt:

var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy(MyAllowSpecificOrigins,
                          policy =>
                          {
                              policy.WithOrigins("http://example.com",
                                                  "http://www.contoso.com")
                                                  .AllowAnyHeader()
                                                  .AllowAnyMethod();
                          });
});

builder.Services.AddControllers();

var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();

app.UseCors(MyAllowSpecificOrigins);

app.UseAuthorization();

app.MapControllers();

app.Run();

Hinweis: Die angegebene URL darf keinen nachgestellten Schrägstrich (/) enthalten. Wenn die URL mit / beendet wird, gibt der Vergleich false zurück, und es wird kein Header zurückgegeben.

Warnung

UseCors muss nach UseRouting und vor UseAuthorization platziert werden. Dadurch wird sichergestellt, dass CORS-Header sowohl für autorisierte als auch für nicht autorisierte Aufrufe in der Antwort enthalten sind.

Reihenfolge von UseCors und UseStaticFiles

In der Regel wird UseStaticFiles vor UseCors aufgerufen. Apps, die JavaScript zum websiteübergreifenden Abrufen statischer Dateien verwenden, müssen UseCors vor UseStaticFiles aufrufen.

CORS mit Standardrichtlinie und Middleware

Der folgende hervorgehobene Code aktiviert die CORS-Standardrichtlinie:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddDefaultPolicy(
        policy =>
        {
            policy.WithOrigins("http://example.com",
                                "http://www.contoso.com");
        });
});

builder.Services.AddControllers();

var app = builder.Build();

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

app.UseCors();

app.UseAuthorization();

app.MapControllers();

app.Run();

Der vorstehende Code wendet die CORS-Standardrichtlinie auf alle Controllerendpunkte an.

Aktivieren von Cors mit Endpunktrouting

Das Aktivieren von CORS pro Endpunkt mit RequireCors unterstützt derzeit keine automatischen Preflight-Anforderungen. Weitere Informationen finden Sie in diesem GitHub-Issue und unter Testen von CORS mit Endpunktrouting und [HttpOptions].

Beim Endpunktrouting kann CORS mithilfe der RequireCors-Sammlung von Erweiterungsmethoden je Endpunkt aktiviert werden:

var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy(name: MyAllowSpecificOrigins,
                      policy =>
                      {
                          policy.WithOrigins("http://example.com",
                                              "http://www.contoso.com");
                      });
});

builder.Services.AddControllers();
builder.Services.AddRazorPages();

var app = builder.Build();

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

app.UseCors();

app.UseAuthorization();

app.UseEndpoints(endpoints =>
{
    endpoints.MapGet("/echo",
        context => context.Response.WriteAsync("echo"))
        .RequireCors(MyAllowSpecificOrigins);

    endpoints.MapControllers()
             .RequireCors(MyAllowSpecificOrigins);

    endpoints.MapGet("/echo2",
        context => context.Response.WriteAsync("echo2"));

    endpoints.MapRazorPages();
});

app.Run();

Für den Code oben gilt:

  • app.UseCors aktiviert die CORS-Middleware. Da keine Standardrichtlinie konfiguriert wurde, wird CORS nicht durch app.UseCors() allein aktiviert.
  • Die /echo- und Controllerendpunkte ermöglichen ursprungsübergreifende Anforderungen mithilfe der angegebenen Richtlinie.
  • Die /echo2- und Razor Pages-Endpunkte ermöglichen keine ursprungsübergreifenden Anforderungen, da keine Standardrichtlinie angegeben wurde.

Das Attribut [DisableCors] deaktiviert CORS nicht, wenn es durch Endpunktrouting mit RequireCors aktiviert wurde.

Anweisungen zum Testen von Code ähnlich dem vorstehenden finden Sie unter Testen von CORS mit Endpunktrouting und [HttpOptions].

Aktivieren von CORS mit Attributen

Das Aktivieren von CORS mit dem [EnableCors]-Attribut und das Anwenden einer benannten Richtlinie lediglich auf die Endpunkte, die CORS erfordern, bietet die genaueste Steuerung.

Das Attribut [EnableCors] stellt eine Alternative zum globalen Anwenden von CORS dar. Das [EnableCors]-Attribut aktiviert CORS für ausgewählte Endpunkte anstelle aller Endpunkte:

  • [EnableCors] gibt die Standardrichtlinie an.
  • [EnableCors("{Policy String}")] gibt eine benannte Richtlinie an.

Das [EnableCors]-Attribut kann auf Folgendes angewendet werden:

  • Razor Page PageModel
  • Controller
  • Controlleraktionsmethode

Mit dem [EnableCors]-Attribut können verschiedene Richtlinien auf Controller, Seitenmodelle oder Aktionsmethoden angewendet werden. Wenn das [EnableCors]-Attribut auf einen Controller, ein Seitenmodell oder eine Aktionsmethode angewendet wird und CORS in Middleware aktiviert ist, werden beide Richtlinien angewendet. Wir raten davon ab, Richtlinien zu kombinieren. Verwenden Sie das [EnableCors]-Attribut oder Middleware, aber nicht beides in derselben App.

Der folgende Code wendet eine andere Richtlinie auf jede Methode an:

[Route("api/[controller]")]
[ApiController]
public class WidgetController : ControllerBase
{
    // GET api/values
    [EnableCors("AnotherPolicy")]
    [HttpGet]
    public ActionResult<IEnumerable<string>> Get()
    {
        return new string[] { "green widget", "red widget" };
    }

    // GET api/values/5
    [EnableCors("Policy1")]
    [HttpGet("{id}")]
    public ActionResult<string> Get(int id)
    {
        return id switch
        {
            1 => "green widget",
            2 => "red widget",
            _ => NotFound(),
        };
    }
}

Mit dem folgenden Code werden zwei CORS-Richtlinien erstellt:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy("Policy1",
        policy =>
        {
            policy.WithOrigins("http://example.com",
                                "http://www.contoso.com");
        });

    options.AddPolicy("AnotherPolicy",
        policy =>
        {
            policy.WithOrigins("http://www.contoso.com")
                                .AllowAnyHeader()
                                .AllowAnyMethod();
        });
});

builder.Services.AddControllers();

var app = builder.Build();

app.UseHttpsRedirection();

app.UseRouting();

app.UseCors();

app.UseAuthorization();

app.MapControllers();

app.Run();

Zum Erzielen der genauesten Kontrolle bei der Begrenzung von CORS-Anforderungen:

  • Verwenden Sie [EnableCors("MyPolicy")] mit einer benannten Richtlinie.
  • Definieren Sie keine Standardrichtlinie.
  • Verwenden Sie kein Endpunktrouting.

Der Code im nächsten Abschnitt entspricht der vorstehenden Liste.

Anweisungen zum Testen von Code ähnlich dem vorstehenden Code finden Sie unter Testen von CORS.

Deaktivieren von CORS

Das Attribut [DisableCors] deaktiviert CORS nicht, wenn es durch Endpunktrouting aktiviert wurde.

Im folgenden Code wird die CORS-Richtlinie "MyPolicy" definiert:

var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy(name: "MyPolicy",
        policy =>
        {
            policy.WithOrigins("http://example.com",
                                "http://www.contoso.com")
                    .WithMethods("PUT", "DELETE", "GET");
        });
});

builder.Services.AddControllers();
builder.Services.AddRazorPages();

var app = builder.Build();

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

app.UseCors();

app.UseAuthorization();

app.MapControllers();
app.MapRazorPages();

app.Run();

Der folgende Code deaktiviert CORS für die Aktion GetValues2:

[EnableCors("MyPolicy")]
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
    // GET api/values
    [HttpGet]
    public IActionResult Get() =>
        ControllerContext.MyDisplayRouteInfo();

    // GET api/values/5
    [HttpGet("{id}")]
    public IActionResult Get(int id) =>
        ControllerContext.MyDisplayRouteInfo(id);

    // PUT api/values/5
    [HttpPut("{id}")]
    public IActionResult Put(int id) =>
        ControllerContext.MyDisplayRouteInfo(id);


    // GET: api/values/GetValues2
    [DisableCors]
    [HttpGet("{action}")]
    public IActionResult GetValues2() =>
        ControllerContext.MyDisplayRouteInfo();

}

Der vorangehende Code:

Anweisungen zum Testen des vorstehenden Codes finden Sie unter Testen von CORS.

CORS-Richtlinienoptionen

In diesem Abschnitt werden die verschiedenen Optionen beschrieben, die in einer CORS-Richtlinie festgelegt werden können:

AddPolicy wird in Program.cs aufgerufen. Für einige Optionen kann es nützlich sein, zuerst den Abschnitt Funktionsweise von CORS zu lesen.

Festlegen der zulässigen Ursprünge

AllowAnyOrigin: Ermöglicht CORS-Anforderungen von allen Ursprüngen mit einem beliebigen Schema (http oder https). AllowAnyOrigin ist unsicher, da jede Website ursprungsübergreifende Anforderungen an die App vornehmen kann.

Hinweis

Die Angabe von AllowAnyOrigin und AllowCredentials stellt eine unsichere Konfiguration dar und kann zu siteübergreifender Anforderungsfälschung führen. Der CORS-Dienst gibt eine ungültige CORS-Antwort zurück, wenn eine App mit beiden Methoden konfiguriert ist.

AllowAnyOrigin wirkt sich auf Preflight-Anforderungen und den Access-Control-Allow-Origin-Header aus. Weitere Informationen finden Sie im Abschnitt Preflight-Anforderungen.

SetIsOriginAllowedToAllowWildcardSubdomains: Legt die IsOriginAllowed-Eigenschaft der Richtlinie als Funktion fest, die Ursprüngen bei der Prüfung des Ursprungs auf Zulässigkeit die Übereinstimmung mit einer konfigurierten Platzhalterdomäne ermöglicht.

var MyAllowSpecificOrigins = "_MyAllowSubdomainPolicy";

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy(name: MyAllowSpecificOrigins,
        policy =>
        {
            policy.WithOrigins("https://*.example.com")
                .SetIsOriginAllowedToAllowWildcardSubdomains();
        });
});

builder.Services.AddControllers();

var app = builder.Build();

Festlegen der zulässigen HTTP-Methoden

AllowAnyMethod:

  • Lässt jede HTTP-Methode zu:
  • Wirkt sich auf Preflight-Anforderungen und den Access-Control-Allow-Methods-Header aus. Weitere Informationen finden Sie im Abschnitt Preflight-Anforderungen.

Festlegen der zulässigen Anforderungsheader

Rufen Sie WithHeaders auf, und geben Sie die zulässigen Header an, um das Senden bestimmter Header, die als Autorenanforderungsheader bezeichnet werden, in einer CORS-Anforderung zuzulassen:

using Microsoft.Net.Http.Headers;

var MyAllowSpecificOrigins = "_MyAllowSubdomainPolicy";

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy(name: MyAllowSpecificOrigins,
       policy =>
       {
           policy.WithOrigins("http://example.com")
                  .WithHeaders(HeaderNames.ContentType, "x-custom-header");
       });
});

builder.Services.AddControllers();

var app = builder.Build();

Rufen Sie zum Zulassen aller AutorenanforderungsheaderAllowAnyHeader auf:

var MyAllowSpecificOrigins = "_MyAllowSubdomainPolicy";

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy(name: MyAllowSpecificOrigins,
        policy =>
        {
            policy.WithOrigins("https://*.example.com")
                   .AllowAnyHeader();
        });
});

builder.Services.AddControllers();

var app = builder.Build();

AllowAnyHeader wirkt sich auf Preflight-Anforderungen und den Header Access-Control-Request-Headers aus. Weitere Informationen finden Sie im Abschnitt Preflight-Anforderungen.

Eine Zuordnung einer CORS-Middleware-Richtlinie zu bestimmten Headern, die in WithHeaders angegeben werden, ist nur möglich, wenn die in Access-Control-Request-Headers gesendeten Header exakt mit den in WithHeaders angegebenen Headern übereinstimmen.

Betrachten Sie beispielsweise eine App, die wie folgt konfiguriert ist:

app.UseCors(policy => policy.WithHeaders(HeaderNames.CacheControl));

CORS Middleware lehnt eine Preflight-Anforderung mit dem folgenden Anforderungsheader ab, da Content-Language (HeaderNames.ContentLanguage) nicht in WithHeaders aufgeführt ist:

Access-Control-Request-Headers: Cache-Control, Content-Language

Die App gibt eine 200 OK-Antwort zurück, sendet die CORS-Header jedoch nicht zurück. Daher versucht der Browser die ursprungsübergreifende Anforderung nicht.

Festlegen der verfügbar gemachten Antwortheader

Standardmäßig macht der Browser nicht alle Antwortheader für die App verfügbar. Weitere Informationen finden Sie unter W3C Cross-Origin Resource Sharing (Terminologie): Einfacher Antwortheader.

Standardmäßig sind folgende Antwortheader verfügbar:

  • Cache-Control
  • Content-Language
  • Content-Type
  • Expires
  • Last-Modified
  • Pragma

Die CORS-Spezifikation ruft diese Header als einfache Antwortheader auf. Rufen Sie WithExposedHeaders auf, um andere Header für die App verfügbar zu machen:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy("MyExposeResponseHeadersPolicy",
        policy =>
        {
            policy.WithOrigins("https://*.example.com")
                   .WithExposedHeaders("x-custom-header");
        });
});

builder.Services.AddControllers();

var app = builder.Build();

Anmeldeinformationen in ursprungsübergreifenden Anforderungen

Für Anmeldeinformationen ist in einer CORS-Anforderung eine besondere Behandlung erforderlich. Standardmäßig sendet der Browser mit einer ursprungsübergreifenden Anforderung keine Anmeldeinformationen. Zu den Anmeldeinformationen gehören cookies und HTTP-Authentifizierungsschemas. Zum Senden von Anmeldeinformationen mit einer ursprungsübergreifenden Anforderung muss der Client XMLHttpRequest.withCredentials auf true festlegen.

Mit direkter Verwendung von XMLHttpRequest:

var xhr = new XMLHttpRequest();
xhr.open('get', 'https://www.example.com/api/test');
xhr.withCredentials = true;

Mithilfe von jQuery:

$.ajax({
  type: 'get',
  url: 'https://www.example.com/api/test',
  xhrFields: {
    withCredentials: true
  }
});

Mithilfe der Fetch-API:

fetch('https://www.example.com/api/test', {
    credentials: 'include'
});

Der Server muss die Anmeldeinformationen zulassen. Rufen Sie AllowCredentials auf, um ursprungsübergreifende Anmeldeinformationen zuzulassen:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy("MyMyAllowCredentialsPolicy",
        policy =>
        {
            policy.WithOrigins("http://example.com")
                   .AllowCredentials();
        });
});

builder.Services.AddControllers();

var app = builder.Build();

Die HTTP-Antwort enthält einen Access-Control-Allow-Credentials-Header, der dem Browser mitteilt, dass der Server Anmeldeinformationen für eine ursprungsübergreifende Anforderung zulässt.

Wenn der Browser Anmeldeinformationen sendet, die Antwort aber keinen gültigen Access-Control-Allow-Credentials-Header enthält, macht der Browser die Antwort für die App nicht verfügbar, und die ursprungsübergreifende Anforderung schlägt fehl.

Das Zulassen von ursprungsübergreifenden Anmeldeinformationen ist ein Sicherheitsrisiko. Eine Website in einer anderen Domäne kann die Anmeldeinformationen eines angemeldeten Benutzers im Namen des Benutzers ohne dessen Wissen an die App senden.

Die CORS-Spezifikation besagt ferner, dass das Festlegen von Ursprüngen auf "*" (alle Ursprünge) ungültig ist, wenn der Access-Control-Allow-Credentials-Header vorhanden ist.

Preflight-Anforderungen

Bei einigen CORS-Anforderungen sendet der Browser vor der eigentlichen Anforderung eine zusätzliche OPTIONS-Anforderung. Diese Anforderung wird als Preflight-Anforderung bezeichnet. Der Browser kann die Preflight-Anforderung überspringen, wenn alle folgenden Bedingungen erfüllt sind:

  • Die Anforderungsmethode ist GET, HEAD oder POST.
  • Die App legt keine anderen Anforderungsheader als Accept, Accept-Language, Content-Language, Content-Type oder Last-Event-ID fest.
  • Der Header Content-Type hat, sofern er festgelegt ist, einen der folgenden Werte:
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

Die für die Clientanforderung festgelegte Regel für Anforderungsheader gilt für Header, die die App durch Aufrufen von setRequestHeader für das XMLHttpRequest-Objekt festlegt. In der CORS-Spezifikation werden diese Header als Autorenanforderungsheader bezeichnet. Die Regel gilt nicht für Header, die vom Browser festgelegt werden können, wie etwa User-Agent, Host oder Content-Length.

Nachfolgend ist eine Beispielantwort ähnlich der Preflight-Anforderung, wie sie über die Schaltfläche [Put test] im Abschnitt Testen von CORS dieses Dokuments vorgenommen wird.

General:
Request URL: https://cors3.azurewebsites.net/api/values/5
Request Method: OPTIONS
Status Code: 204 No Content

Response Headers:
Access-Control-Allow-Methods: PUT,DELETE,GET
Access-Control-Allow-Origin: https://cors1.azurewebsites.net
Server: Microsoft-IIS/10.0
Set-Cookie: ARRAffinity=8f8...8;Path=/;HttpOnly;Domain=cors1.azurewebsites.net
Vary: Origin

Request Headers:
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Access-Control-Request-Method: PUT
Connection: keep-alive
Host: cors3.azurewebsites.net
Origin: https://cors1.azurewebsites.net
Referer: https://cors1.azurewebsites.net/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0

Die Preflight-Anforderung verwendet die HTTP OPTIONS-Methode. Sie kann die folgenden Header enthalten:

Wenn die Preflight-Anforderung abgelehnt wird, gibt die App eine 200 OK-Antwort zurück, legt aber die CORS-Header nicht fest. Daher versucht der Browser die ursprungsübergreifende Anforderung nicht. Ein Beispiel für eine verweigerte Preflight-Anforderung finden Sie im Abschnitt Testen von CORS in diesem Dokument.

Bei Verwendung der F12-Tools zeigt die Konsolen-App je nach Browser einen Fehler ähnlich einem der folgenden an:

  • Firefox: Ursprungsübergreifende Anforderung blockiert: Die Richtlinie des gleichen Ursprungs lässt das Lesen der Remoteressource unter https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5 nicht zu. (Grund: CORS-Anforderung war nicht erfolgreich). Weitere Informationen
  • Chromium-basiert: Der Zugriff auf Fetch unter „https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5“ vom Ursprung „https://cors3.azurewebsites.net“ wurde durch die CORS-Richtlinie blockiert: Die Antwort auf eine Preflight-Anforderung hat die Zugriffssteuerungsprüfung nicht bestanden: Für die angeforderte Ressource ist kein „Access-Control-Allow-Origin“-Header vorhanden. Falls eine opake Antwort Ihre Anforderungen erfüllt, legen Sie den Modus der Anforderung auf „no-cors“ fest, um CORS für den Ressourcenabruf zu deaktivieren.

Rufen Sie WithHeaders auf, um bestimmte Header zuzulassen:

using Microsoft.Net.Http.Headers;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy("MyAllowHeadersPolicy",
        policy =>
        {
        policy.WithOrigins("http://example.com")
                   .WithHeaders(HeaderNames.ContentType, "x-custom-header");
        });
});

builder.Services.AddControllers();

var app = builder.Build();

Rufen Sie zum Zulassen aller AutorenanforderungsheaderAllowAnyHeader auf:

using Microsoft.Net.Http.Headers;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy("MyAllowAllHeadersPolicy",
        policy =>
        {
            policy.WithOrigins("https://*.example.com")
                   .AllowAnyHeader();
        });
});

builder.Services.AddControllers();

var app = builder.Build();

Browser sind in der Festlegung von Access-Control-Request-Headers nicht konsistent. Hier gelten entweder:

  • Die Header sind auf einen anderen Wert als "*" festgelegt
  • AllowAnyHeader wird aufgerufen: Schließen Sie mindestens Accept, Content-Type und Origin sowie alle benutzerdefinierten Header ein, die Sie unterstützen möchten.

Code für automatische Preflight-Anforderungen

Die CORS-Richtlinie wird auf eine dieser Weisen angewendet:

  • Global durch Aufrufen von app.UseCors in Program.cs.
  • Mithilfe des [EnableCors]-Attributs.

ASP.NET Core antwortet auf die Preflight-Anforderung OPTIONS.

Das Aktivieren von CORS pro Endpunkt mit RequireCors unterstützt derzeit keine automatischen Preflight-Anforderungen.

Im Abschnitt Testen von CORS dieses Dokuments wird dieses Verhalten veranschaulicht.

[HttpOptions]-Attribut für Preflight-Anforderungen

Wenn CORS mit der entsprechenden Richtlinie aktiviert ist, reagiert ASP.NET Core in der Regel automatisch auf CORS-Preflight-Anforderungen. Bei einigen Szenarien ist dies möglicherweise nicht der Fall. Beispielsweise beim Verwenden von CORS mit Endpunktrouting.

Der folgende Code verwendet das [HttpOptions]-Attribut, um Endpunkte für OPTIONS-Anforderungen zu erstellen:

[Route("api/[controller]")]
[ApiController]
public class TodoItems2Controller : ControllerBase
{
    // OPTIONS: api/TodoItems2/5
    [HttpOptions("{id}")]
    public IActionResult PreflightRoute(int id)
    {
        return NoContent();
    }

    // OPTIONS: api/TodoItems2 
    [HttpOptions]
    public IActionResult PreflightRoute()
    {
        return NoContent();
    }

    [HttpPut("{id}")]
    public IActionResult PutTodoItem(int id)
    {
        if (id < 1)
        {
            return BadRequest();
        }

        return ControllerContext.MyDisplayRouteInfo(id);
    }

Anweisungen zum Testen des vorstehenden Codes finden Sie unter Testen von CORS mit Endpunktrouting und [HttpOptions].

Festlegen der Preflight-Ablaufzeit

Der Access-Control-Max-Age-Header gibt an, wie lange die Antwort auf die Preflight-Anforderung zwischengespeichert werden kann. Rufen Sie SetPreflightMaxAge auf, um diesen Header festzulegen:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy("MySetPreflightExpirationPolicy",
        policy =>
        {
            policy.WithOrigins("http://example.com")
                   .SetPreflightMaxAge(TimeSpan.FromSeconds(2520));
        });
});

builder.Services.AddControllers();

var app = builder.Build();

Funktionsweise von CORS

In diesem Abschnitt wird beschrieben, was in einer CORS-Anforderung auf der Ebene der HTTP-Nachrichten geschieht.

  • CORS ist kein Sicherheitsfeature. CORS ist ein W3C-Standard, der einem Server eine weniger strenge Anwendung der Richtlinie desselben Ursprungs ermöglicht.
    • Beispielsweise könnte ein böswilliger Akteur Cross-Site Scripting (XSS) auf Ihre Website anwenden und eine websiteübergreifende Anforderung an seine CORS-fähige Website vornehmen, um Informationen zu stehlen.
  • Durch Zulassen von CORS wird eine API wird nicht sicherer.
    • Das Durchsetzen von CORS liegt in der Zuständigkeit des Clients (Browsers). Der Server führt die Anforderung aus und gibt die Antwort zurück. Es ist der Client, der einen Fehler zurückgibt und die Antwort blockiert. Beispielsweise wird für jedes der folgenden Tools die Serverantwort angezeigt:
  • Es stellt eine Möglichkeit für einen Server dar, Browsern die Ausführung einer ursprungsübergreifenden XHR- oder Fetch-API-Anforderung zu erlauben, die andernfalls verboten wäre.
    • Browser ohne CORS können keine ursprungsübergreifenden Anforderungen ausführen. Vor CORS wurde JSONP verwendet, um diese Einschränkung zu umgehen. JSONP verwendet nicht XHR, es verwendet das <script>-Tag, um die Antwort zu empfangen. Skripts dürfen ursprungsübergreifend geladen werden.

Mit der CORS-Spezifikation wurden mehrere neue HTTP-Header eingeführt, die ursprungsübergreifende Anforderungen ermöglichen. Wenn ein Browser CORS unterstützt, legt er diese Header für ursprungsübergreifende Anforderungen automatisch fest. Zum Aktivieren von CORS ist kein benutzerdefinierter JavaScript-Code erforderlich.

Die PUT test-Schaltfläche im bereitgestellten Beispiel

Nachfolgend ist ein Beispiel für eine ursprungsübergreifende Anforderung von der Werte-Testschaltfläche an https://cors1.azurewebsites.net/api/values. Der Origin-Header:

  • Gibt die Domäne der Website an, die die Anforderung ausführt.
  • Ist erforderlich und muss sich vom Host unterscheiden.

Allgemeine Header

Request URL: https://cors1.azurewebsites.net/api/values
Request Method: GET
Status Code: 200 OK

Antwortheader

Content-Encoding: gzip
Content-Type: text/plain; charset=utf-8
Server: Microsoft-IIS/10.0
Set-Cookie: ARRAffinity=8f...;Path=/;HttpOnly;Domain=cors1.azurewebsites.net
Transfer-Encoding: chunked
Vary: Accept-Encoding
X-Powered-By: ASP.NET

Anforderungsheader

Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Connection: keep-alive
Host: cors1.azurewebsites.net
Origin: https://cors3.azurewebsites.net
Referer: https://cors3.azurewebsites.net/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0 ...

In OPTIONS-Anforderungen legt der Server den AntwortheaderAccess-Control-Allow-Origin: {allowed origin}-Header in der Antwort fest. Beispielsweise enthält die OPTIONS-Anforderung im zur Verfügung gestellten MusterDelete [EnableCors]-Schaltfläche die folgenden Header:

Allgemeine Header

Request URL: https://cors3.azurewebsites.net/api/TodoItems2/MyDelete2/5
Request Method: OPTIONS
Status Code: 204 No Content

Antwortheader

Access-Control-Allow-Headers: Content-Type,x-custom-header
Access-Control-Allow-Methods: PUT,DELETE,GET,OPTIONS
Access-Control-Allow-Origin: https://cors1.azurewebsites.net
Server: Microsoft-IIS/10.0
Set-Cookie: ARRAffinity=8f...;Path=/;HttpOnly;Domain=cors3.azurewebsites.net
Vary: Origin
X-Powered-By: ASP.NET

Anforderungsheader

Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Access-Control-Request-Headers: content-type
Access-Control-Request-Method: DELETE
Connection: keep-alive
Host: cors3.azurewebsites.net
Origin: https://cors1.azurewebsites.net
Referer: https://cors1.azurewebsites.net/test?number=2
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0

In den vorstehenden Antwortheadern legt der Server den Access-Control-Allow-Origin-Header in der Antwort fest. Der https://cors1.azurewebsites.net-Wert dieses Headers stimmt mit dem Origin-Header aus der Anforderung überein.

Wenn AllowAnyOrigin aufgerufen wird, wird Access-Control-Allow-Origin: * zurückgegeben, der Platzhalterwert. AllowAnyOrigin lässt jeden Ursprung zu.

Wenn die Antwort den Access-Control-Allow-Origin-Header nicht enthält, schlägt die ursprungsübergreifende Anforderung fehl. Insbesondere lässt der Browser die Anforderung nicht zu. Auch wenn der Server eine erfolgreiche Antwort zurückgibt, stellt der Browser die Antwort der Client-App nicht zur Verfügung.

Eine HTTP-Umleitung zu HTTPS bewirkt ein ERR_INVALID_REDIRECT für die CORS-Preflight-Anforderung

Anforderungen an einen Endpunkt über HTTP, die per UseHttpsRedirection an HTTPS weitergeleitet werden, weisen den Fehler ERR_INVALID_REDIRECT on the CORS preflight request auf.

API-Projekte können HTTP-Anforderungen ablehnen, anstatt Anforderungen über UseHttpsRedirection an HTTPS umzuleiten.

Anzeigen von OPTIONS-Anforderungen

Standardmäßig zeigen die Chrome- und Edge-Browser OPTIONS-Anforderungen auf der Registerkarte „Netzwerk“ der F12-Tools nicht an. So zeigen Sie OPTIONS-Anforderungen in diesen Browsern an:

  • chrome://flags/#out-of-blink-cors oder edge://flags/#out-of-blink-cors
  • deaktivieren das Flag.
  • Neustart.

Firefox zeigt OPTIONS-Anforderungen standardmäßig an.

CORS in IIS

Bei der Bereitstellung in IIS muss CORS vor der Windows-Authentifizierung ausgeführt werden, wenn der Server nicht für den anonymen Zugriff konfiguriert ist. Zum Unterstützen dieses Szenarios muss das IIS-CORS-Modul installiert und für die App konfiguriert werden.

Testen von CORS

Der Beispieldownload enthält Code zum Testen von CORS. Informationen zum Herunterladen finden Sie hier. Das Beispiel ist ein API-Projekt mit hinzugefügten Razor Pages:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy(name: "MyPolicy",
                policy =>
                {
                    policy.WithOrigins("http://example.com",
                        "http://www.contoso.com",
                        "https://cors1.azurewebsites.net",
                        "https://cors3.azurewebsites.net",
                        "https://localhost:44398",
                        "https://localhost:5001")
                            .WithMethods("PUT", "DELETE", "GET");
                });
});

builder.Services.AddControllers();
builder.Services.AddRazorPages();

var app = builder.Build();

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

app.UseCors();

app.UseAuthorization();

app.MapControllers();
app.MapRazorPages();

app.Run();

Warnung

WithOrigins("https://localhost:<port>"); sollte nur zum Testen einer Beispiel-App verwendet werden, die dem Code des Downloadbeispiels ähnelt.

Der folgende ValuesController stellt die Endpunkte zum Testen zur Verfügung:

[EnableCors("MyPolicy")]
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
    // GET api/values
    [HttpGet]
    public IActionResult Get() =>
        ControllerContext.MyDisplayRouteInfo();

    // GET api/values/5
    [HttpGet("{id}")]
    public IActionResult Get(int id) =>
        ControllerContext.MyDisplayRouteInfo(id);

    // PUT api/values/5
    [HttpPut("{id}")]
    public IActionResult Put(int id) =>
        ControllerContext.MyDisplayRouteInfo(id);


    // GET: api/values/GetValues2
    [DisableCors]
    [HttpGet("{action}")]
    public IActionResult GetValues2() =>
        ControllerContext.MyDisplayRouteInfo();

}

MyDisplayRouteInfo wird von dem NuGet-Paket Rick.Docs.Samples.RouteInfo bereitgestellt und zeigt Routeninformationen an.

Testen Sie den vorstehenden Beispielcode mit einem der folgenden Ansätze:

  • Verwenden Sie die unter https://cors3.azurewebsites.net/ zur Verfügung gestellte Beispiel-App. Das Beispiel muss nicht heruntergeladen werden.
  • Führen Sie das Beispiel mit dotnet run mit der Standard-URL https://localhost:5001 aus.
  • Führen Sie das Beispiel in Visual Studio aus, wobei der Port für die URL https://localhost:44398 auf 44398 festgelegt ist.

Verwenden eines Browsers mit den F12-Tools:

  • Wählen Sie die Schaltfläche Werte aus, und überprüfen Sie die Header auf der Registerkarte Netzwerk.

  • Wählen Sie die Schaltfläche PUT test aus. Anweisungen zum Anzeigen der OPTIONS-Anforderung finden Sie unter Anzeigen von OPTIONS-Anforderungen. PUT test erstellt zwei Anforderungen, eine OPTIONS-Preflight-Anforderung und die PUT-Anforderung.

  • Wählen Sie die GetValues2 [DisableCors]-Schaltfläche aus, um eine fehlerhafte CORS-Anforderung auszulösen. Wie im Dokument erwähnt, gibt die Antwort „200 (Erfolg)“ zurück, aber die CORS-Anforderung wird nicht ausgeführt. Wählen Sie die Registerkarte Konsole aus, um den CORS-Fehler anzuzeigen. Abhängig vom Browser wird ein Fehler ähnlich dem Folgenden angezeigt:

    Der Zugriff auf Fetch unter 'https://cors1.azurewebsites.net/api/values/GetValues2' vom Ursprung 'https://cors3.azurewebsites.net' wurde durch die CORS-Richtlinie blockiert: In der angeforderten Ressource ist kein „Access-Control-Allow-Origin“-Header vorhanden. Falls eine opake Antwort Ihre Anforderungen erfüllt, legen Sie den Modus der Anforderung auf „no-cors“ fest, um CORS für den Ressourcenabruf zu deaktivieren.

CORS-fähige Endpunkte können mit einem Tool wie cURL oder Fiddler getestet werden. Bei Verwendung eines Tools muss sich der Ursprung der durch den Origin-Header angegebenen Anforderung von dem Host unterscheiden, der die Anforderung empfängt. Wenn die Anforderung auf der Grundlage des Werts des Origin-Headers nicht ursprungsübergreifend ist:

  • Es besteht keine Notwendigkeit, dass die Anforderung durch die CORS-Middleware verarbeitet wird.
  • CORS-Header werden in der Antwort nicht zurückgegeben.

Der folgende Befehl verwendet curl, um eine OPTIONS-Anforderung mit Informationen auszugeben:

curl -X OPTIONS https://cors3.azurewebsites.net/api/TodoItems2/5 -i

Testen von CORS mit Endpunktrouting und [HttpOptions]

Das Aktivieren von CORS pro Endpunkt mit RequireCors unterstützt derzeit keineautomatischen Preflight-Anforderungen. Betrachten Sie den folgenden Code, der Endpunktrouting zum Aktivieren von CORS verwendet:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy(name: "MyPolicy",
                policy =>
                {
                    policy.WithOrigins("http://example.com",
                        "http://www.contoso.com",
                        "https://cors1.azurewebsites.net",
                        "https://cors3.azurewebsites.net",
                        "https://localhost:44398",
                        "https://localhost:5001")
                            .WithMethods("PUT", "DELETE", "GET");
                });
});

builder.Services.AddControllers();
builder.Services.AddRazorPages();

var app = builder.Build();

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

app.UseCors();

app.UseAuthorization();

app.MapControllers();
app.MapRazorPages();

app.Run();

Der folgende TodoItems1Controller stellt die Endpunkte zum Testen zur Verfügung:

[Route("api/[controller]")]
[ApiController]
public class TodoItems1Controller : ControllerBase
{
    // PUT: api/TodoItems1/5
    [HttpPut("{id}")]
    public IActionResult PutTodoItem(int id)
    {
        if (id < 1)
        {
            return Content($"ID = {id}");
        }

        return ControllerContext.MyDisplayRouteInfo(id);
    }

    // Delete: api/TodoItems1/5
    [HttpDelete("{id}")]
    public IActionResult MyDelete(int id) =>
        ControllerContext.MyDisplayRouteInfo(id);

    // GET: api/TodoItems1
    [HttpGet]
    public IActionResult GetTodoItems() =>
        ControllerContext.MyDisplayRouteInfo();

    [EnableCors]
    [HttpGet("{action}")]
    public IActionResult GetTodoItems2() =>
        ControllerContext.MyDisplayRouteInfo();

    // Delete: api/TodoItems1/MyDelete2/5
    [EnableCors]
    [HttpDelete("{action}/{id}")]
    public IActionResult MyDelete2(int id) =>
        ControllerContext.MyDisplayRouteInfo(id);
}

Testen Sie den vorstehenden Code auf der Testseite des bereitgestellten Beispiels.

Die Schaltflächen Delete [EnableCors] und GET [EnableCors] werden erfolgreich ausgeführt, da die Endpunkte über [EnableCors] verfügen und auf Preflight-Anforderungen antworten. Bei den anderen Endpunkten tritt ein Fehler auf. Bei der GET-Schaltfläche tritt ein Fehler auf, da das JavaScript Folgendes sendet:

 headers: {
      "Content-Type": "x-custom-header"
 },

Der folgende TodoItems2Controller stellt ähnliche Endpunkte zur Verfügung, schließt aber expliziten Code zum Antworten auf OPTIONS-Anforderungen ein:

[Route("api/[controller]")]
[ApiController]
public class TodoItems2Controller : ControllerBase
{
    // OPTIONS: api/TodoItems2/5
    [HttpOptions("{id}")]
    public IActionResult PreflightRoute(int id)
    {
        return NoContent();
    }

    // OPTIONS: api/TodoItems2 
    [HttpOptions]
    public IActionResult PreflightRoute()
    {
        return NoContent();
    }

    [HttpPut("{id}")]
    public IActionResult PutTodoItem(int id)
    {
        if (id < 1)
        {
            return BadRequest();
        }

        return ControllerContext.MyDisplayRouteInfo(id);
    }

    // [EnableCors] // Not needed as OPTIONS path provided
    [HttpDelete("{id}")]
    public IActionResult MyDelete(int id) =>
        ControllerContext.MyDisplayRouteInfo(id);

    [EnableCors]  // Rquired for this path
    [HttpGet]
    public IActionResult GetTodoItems() =>
        ControllerContext.MyDisplayRouteInfo();

    [HttpGet("{action}")]
    public IActionResult GetTodoItems2() =>
        ControllerContext.MyDisplayRouteInfo();

    [EnableCors]  // Rquired for this path
    [HttpDelete("{action}/{id}")]
    public IActionResult MyDelete2(int id) =>
        ControllerContext.MyDisplayRouteInfo(id);
}

Testen Sie den vorstehenden Code auf der Testseite des bereitgestellten Beispiels. Wählen Sie in der Dropdownliste Controller die Option Preflight und dann Controller festlegen aus. Alle CORS-Aufrufe an die TodoItems2Controller-Endpunkte sind erfolgreich.

Zusätzliche Ressourcen

Von Rick Anderson und Kirk Larkin

In diesem Artikel erfahren Sie, wie Sie CORS in einer ASP.NET Core-App aktivieren.

Die Browsersicherheit verhindert, dass eine Webseite Anforderungen an eine andere Domäne als diejenige stellt, die die Webseite versorgt hat. Diese Einschränkung wird als Richtlinie des gleichen Ursprungs bezeichnet. Die Richtlinie des gleichen Ursprungs verhindert, dass eine schädliche Website sensible Daten von einer anderen Website liest. Manchmal kann es sinnvoll sein, anderen Websites das Senden von ursprungsübergreifenden Anforderungen an Ihre App zu erlauben. Weitere Informationen finden Sie im Mozilla CORS-Artikel.

Ressourcenfreigabe zwischen verschiedenen Ursprüngen (Cross-Origin Resource Sharing, CORS):

  • ist ein W3C-Standard, der einem Server eine weniger strenge Anwendung der Richtlinie des gleichen Ursprungs ermöglicht.
  • ist kein Sicherheitsfeature, CORS lockert die Sicherheit. Eine API wird nicht sicherer, indem sie CORS zulässt. Weitere Informationen finden Sie unter Funktionsweise von CORS.
  • ermöglicht es einem Server, einige ursprungsübergreifende Anforderungen explizit zuzulassen und andere abzulehnen.
  • ist sicherer und flexibler als frühere Techniken wie etwa JSONP.

Anzeigen oder Herunterladen von Beispielcode (Vorgehensweise zum Herunterladen)

Gleicher Ursprung

Zwei URLs haben den gleichen Ursprung, wenn sie identische Schemas, Hosts und Ports aufweisen (RFC 6454).

Diese beiden URLs haben den gleichen Ursprung:

  • https://example.com/foo.html
  • https://example.com/bar.html

Diese URLs haben andere Ursprünge als die vorherigen beiden URLs:

  • https://example.net: andere Domäne
  • https://www.example.com/foo.html: andere Unterdomäne
  • http://example.com/foo.html: anderes Schema
  • https://example.com:9000/foo.html: anderer Port

Aktivieren von CORS

Es gibt es drei Möglichkeiten zum Aktualisieren von CORS:

Die Verwendung des [EnableCors]-Attributs mit einer benannten Richtlinie bietet die beste Kontrolle bei der Begrenzung von Endpunkten, die CORS unterstützen.

Warnung

UseCors muss in der richtigen Reihenfolge aufgerufen werden. Weitere Informationen finden Sie unter Middleware-Reihenfolge. Beispielsweise muss UseCors bei Verwendung von UseResponseCaching vor UseResponseCaching aufgerufen werden.

Jeder Ansatz wird in den folgenden Abschnitten ausführlich beschrieben.

CORS mit benannter Richtlinie und Middleware

CORS-Middleware verarbeitet ursprungsübergreifende Anforderungen. Der folgende Code wendet eine CORS-Richtlinie auf alle Endpunkte der App mit den angegebenen Ursprüngen an:

public class Startup
{
    readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddCors(options =>
        {
            options.AddPolicy(name: MyAllowSpecificOrigins,
                              policy =>
                              {
                                  policy.WithOrigins("http://example.com",
                                                      "http://www.contoso.com");
                              });
        });

        // services.AddResponseCaching();
        services.AddControllers();
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

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

        app.UseCors(MyAllowSpecificOrigins);

        // app.UseResponseCaching();

        app.UseAuthorization();

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

Der vorangehende Code:

  • Legt den Richtliniennamen auf _myAllowSpecificOrigins fest. Der Name der Richtlinie ist frei wählbar.
  • Ruft die Erweiterungsmethode UseCors auf und gibt die CORS-Richtlinie _myAllowSpecificOrigins an. UseCors fügt die CORS-Middleware hinzu. Der Aufruf von UseCors muss nach UseRouting, aber vor UseAuthorization platziert werden. Weitere Informationen finden Sie unter Middleware-Reihenfolge.
  • Ruft AddCors mit einem Lambdaausdruck auf. Der Lambdaausdruck nimmt ein CorsPolicyBuilder-Objekt an. Konfigurationsoptionen wie WithOrigins werden weiter unten in diesem Artikel beschrieben.
  • Aktiviert die CORS-Richtlinie _myAllowSpecificOrigins für alle Controllerendpunkte. Informationen zum Anwenden einer CORS-Richtlinie auf bestimmte Endpunkte finden Sie unter Endpunktrouting.
  • Wenn Sie Antworten zwischenspeichernde Middleware verwenden, rufen Sie UseCors vor UseResponseCaching auf.

Beim Endpunktrouting muss die CORS-Middleware für die Ausführung zwischen den Aufrufen von UseRouting und UseEndpoints konfiguriert werden.

Anweisungen zum Testen von Code ähnlich dem vorstehenden Code finden Sie unter Testen von CORS.

Der Methodenaufruf AddCors fügt dem Dienstcontainer der App CORS-Dienste hinzu:

public class Startup
{
    readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddCors(options =>
        {
            options.AddPolicy(name: MyAllowSpecificOrigins,
                              policy =>
                              {
                                  policy.WithOrigins("http://example.com",
                                                      "http://www.contoso.com");
                              });
        });

        // services.AddResponseCaching();
        services.AddControllers();
    }

Weitere Informationen finden Sie unter CORS-Richtlinienoptionen in diesem Dokument.

Die CorsPolicyBuilder-Methoden können verkettet werden, wie im folgenden Code gezeigt:

public void ConfigureServices(IServiceCollection services)
{
    services.AddCors(options =>
    {
        options.AddPolicy(MyAllowSpecificOrigins,
                          policy =>
                          {
                              policy.WithOrigins("http://example.com",
                                                  "http://www.contoso.com")
                                                  .AllowAnyHeader()
                                                  .AllowAnyMethod();
                          });
    });

    services.AddControllers();
}

Hinweis: Die angegebene URL darf keinen nachgestellten Schrägstrich (/) enthalten. Wenn die URL mit / beendet wird, gibt der Vergleich false zurück, und es wird kein Header zurückgegeben.

CORS mit Standardrichtlinie und Middleware

Der folgende hervorgehobene Code aktiviert die CORS-Standardrichtlinie:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddCors(options =>
        {
            options.AddDefaultPolicy(
                policy =>
                {
                    policy.WithOrigins("http://example.com",
                                        "http://www.contoso.com");
                });
        });

        services.AddControllers();
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

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

        app.UseCors();

        app.UseAuthorization();

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

Der vorstehende Code wendet die CORS-Standardrichtlinie auf alle Controllerendpunkte an.

Aktivieren von Cors mit Endpunktrouting

Das Aktivieren von CORS pro Endpunkt mit RequireCors unterstützt derzeit keine automatischen Preflight-Anforderungen. Weitere Informationen finden Sie in diesem GitHub-Issue und unter Testen von CORS mit Endpunktrouting und [HttpOptions].

Beim Endpunktrouting kann CORS mithilfe der RequireCors-Sammlung von Erweiterungsmethoden je Endpunkt aktiviert werden:

public class Startup
{
    readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddCors(options =>
        {
            options.AddPolicy(name: MyAllowSpecificOrigins,
                              policy =>
                              {
                                  policy.WithOrigins("http://example.com",
                                                      "http://www.contoso.com");
                              });
        });

        services.AddControllers();
        services.AddRazorPages();
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

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

        app.UseCors();

        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapGet("/echo",
                context => context.Response.WriteAsync("echo"))
                .RequireCors(MyAllowSpecificOrigins);

            endpoints.MapControllers()
                     .RequireCors(MyAllowSpecificOrigins);

            endpoints.MapGet("/echo2",
                context => context.Response.WriteAsync("echo2"));

            endpoints.MapRazorPages();
        });
    }
}

Für den Code oben gilt:

  • app.UseCors aktiviert die CORS-Middleware. Da keine Standardrichtlinie konfiguriert wurde, wird CORS nicht durch app.UseCors() allein aktiviert.
  • Die /echo- und Controllerendpunkte ermöglichen ursprungsübergreifende Anforderungen mithilfe der angegebenen Richtlinie.
  • Die /echo2- und Razor Pages-Endpunkte ermöglichen keine ursprungsübergreifenden Anforderungen, da keine Standardrichtlinie angegeben wurde.

Das Attribut [DisableCors] deaktiviert CORS nicht, wenn es durch Endpunktrouting mit RequireCors aktiviert wurde.

Anweisungen zum Testen von Code ähnlich dem vorstehenden finden Sie unter Testen von CORS mit Endpunktrouting und [HttpOptions].

Aktivieren von CORS mit Attributen

Das Aktivieren von CORS mit dem [EnableCors]-Attribut und das Anwenden einer benannten Richtlinie lediglich auf die Endpunkte, die CORS erfordern, bietet die genaueste Steuerung.

Das Attribut [EnableCors] stellt eine Alternative zum globalen Anwenden von CORS dar. Das [EnableCors]-Attribut aktiviert CORS für ausgewählte Endpunkte anstelle aller Endpunkte:

  • [EnableCors] gibt die Standardrichtlinie an.
  • [EnableCors("{Policy String}")] gibt eine benannte Richtlinie an.

Das [EnableCors]-Attribut kann auf Folgendes angewendet werden:

  • Razor Page PageModel
  • Controller
  • Controlleraktionsmethode

Mit dem [EnableCors]-Attribut können verschiedene Richtlinien auf Controller, Seitenmodelle oder Aktionsmethoden angewendet werden. Wenn das [EnableCors]-Attribut auf einen Controller, ein Seitenmodell oder eine Aktionsmethode angewendet wird und CORS in Middleware aktiviert ist, werden beide Richtlinien angewendet. Wir raten davon ab, Richtlinien zu kombinieren. Verwenden Sie das [EnableCors]-Attribut oder Middleware, aber nicht beides in derselben App.

Der folgende Code wendet eine andere Richtlinie auf jede Methode an:

[Route("api/[controller]")]
[ApiController]
public class WidgetController : ControllerBase
{
    // GET api/values
    [EnableCors("AnotherPolicy")]
    [HttpGet]
    public ActionResult<IEnumerable<string>> Get()
    {
        return new string[] { "green widget", "red widget" };
    }

    // GET api/values/5
    [EnableCors("Policy1")]
    [HttpGet("{id}")]
    public ActionResult<string> Get(int id)
    {
        return id switch
        {
            1 => "green widget",
            2 => "red widget",
            _ => NotFound(),
        };
    }
}

Mit dem folgenden Code werden zwei CORS-Richtlinien erstellt:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddCors(options =>
        {
            options.AddPolicy("Policy1",
                policy =>
                {
                    policy.WithOrigins("http://example.com",
                                        "http://www.contoso.com");
                });

            options.AddPolicy("AnotherPolicy",
                policy =>
                {
                    policy.WithOrigins("http://www.contoso.com")
                                        .AllowAnyHeader()
                                        .AllowAnyMethod();
                });
        });

        services.AddControllers();
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseHttpsRedirection();

        app.UseRouting();

        app.UseCors();

        app.UseAuthorization();

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

Zum Erzielen der genauesten Kontrolle bei der Begrenzung von CORS-Anforderungen:

  • Verwenden Sie [EnableCors("MyPolicy")] mit einer benannten Richtlinie.
  • Definieren Sie keine Standardrichtlinie.
  • Verwenden Sie kein Endpunktrouting.

Der Code im nächsten Abschnitt entspricht der vorstehenden Liste.

Anweisungen zum Testen von Code ähnlich dem vorstehenden Code finden Sie unter Testen von CORS.

Deaktivieren von CORS

Das Attribut [DisableCors] deaktiviert CORS nicht, wenn es durch Endpunktrouting aktiviert wurde.

Im folgenden Code wird die CORS-Richtlinie "MyPolicy" definiert:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddCors(options =>
        {
            options.AddPolicy(name: "MyPolicy",
                policy =>
                {
                    policy.WithOrigins("http://example.com",
                                        "http://www.contoso.com")
                            .WithMethods("PUT", "DELETE", "GET");
                });
        });

        services.AddControllers();
        services.AddRazorPages();
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

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

        app.UseCors();

        app.UseAuthorization();

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

Der folgende Code deaktiviert CORS für die Aktion GetValues2:

[EnableCors("MyPolicy")]
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
    // GET api/values
    [HttpGet]
    public IActionResult Get() =>
        ControllerContext.MyDisplayRouteInfo();

    // GET api/values/5
    [HttpGet("{id}")]
    public IActionResult Get(int id) =>
        ControllerContext.MyDisplayRouteInfo(id);

    // PUT api/values/5
    [HttpPut("{id}")]
    public IActionResult Put(int id) =>
        ControllerContext.MyDisplayRouteInfo(id);


    // GET: api/values/GetValues2
    [DisableCors]
    [HttpGet("{action}")]
    public IActionResult GetValues2() =>
        ControllerContext.MyDisplayRouteInfo();

}

Der vorangehende Code:

Anweisungen zum Testen des vorstehenden Codes finden Sie unter Testen von CORS.

CORS-Richtlinienoptionen

In diesem Abschnitt werden die verschiedenen Optionen beschrieben, die in einer CORS-Richtlinie festgelegt werden können:

AddPolicy wird in Startup.ConfigureServices aufgerufen. Für einige Optionen kann es nützlich sein, zuerst den Abschnitt Funktionsweise von CORS zu lesen.

Festlegen der zulässigen Ursprünge

AllowAnyOrigin: Ermöglicht CORS-Anforderungen von allen Ursprüngen mit einem beliebigen Schema (http oder https). AllowAnyOrigin ist unsicher, da jede Website ursprungsübergreifende Anforderungen an die App vornehmen kann.

Hinweis

Die Angabe von AllowAnyOrigin und AllowCredentials stellt eine unsichere Konfiguration dar und kann zu siteübergreifender Anforderungsfälschung führen. Der CORS-Dienst gibt eine ungültige CORS-Antwort zurück, wenn eine App mit beiden Methoden konfiguriert ist.

AllowAnyOrigin wirkt sich auf Preflight-Anforderungen und den Access-Control-Allow-Origin-Header aus. Weitere Informationen finden Sie im Abschnitt Preflight-Anforderungen.

SetIsOriginAllowedToAllowWildcardSubdomains: Legt die IsOriginAllowed-Eigenschaft der Richtlinie als Funktion fest, die Ursprüngen bei der Prüfung des Ursprungs auf Zulässigkeit die Übereinstimmung mit einer konfigurierten Platzhalterdomäne ermöglicht.

options.AddPolicy("MyAllowSubdomainPolicy",
    policy =>
    {
        policy.WithOrigins("https://*.example.com")
            .SetIsOriginAllowedToAllowWildcardSubdomains();
    });

Festlegen der zulässigen HTTP-Methoden

AllowAnyMethod:

  • Lässt jede HTTP-Methode zu:
  • Wirkt sich auf Preflight-Anforderungen und den Access-Control-Allow-Methods-Header aus. Weitere Informationen finden Sie im Abschnitt Preflight-Anforderungen.

Festlegen der zulässigen Anforderungsheader

Rufen Sie WithHeaders auf, und geben Sie die zulässigen Header an, um das Senden bestimmter Header, die als Autorenanforderungsheader bezeichnet werden, in einer CORS-Anforderung zuzulassen:

options.AddPolicy("MyAllowHeadersPolicy",
    policy =>
    {
        // requires using Microsoft.Net.Http.Headers;
        policy.WithOrigins("http://example.com")
               .WithHeaders(HeaderNames.ContentType, "x-custom-header");
    });

Rufen Sie zum Zulassen aller AutorenanforderungsheaderAllowAnyHeader auf:

options.AddPolicy("MyAllowAllHeadersPolicy",
    policy =>
    {
        policy.WithOrigins("https://*.example.com")
               .AllowAnyHeader();
    });

AllowAnyHeader wirkt sich auf Preflight-Anforderungen und den Header Access-Control-Request-Headers aus. Weitere Informationen finden Sie im Abschnitt Preflight-Anforderungen.

Eine Zuordnung einer CORS-Middleware-Richtlinie zu bestimmten Headern, die in WithHeaders angegeben werden, ist nur möglich, wenn die in Access-Control-Request-Headers gesendeten Header exakt mit den in WithHeaders angegebenen Headern übereinstimmen.

Betrachten Sie beispielsweise eine App, die wie folgt konfiguriert ist:

app.UseCors(policy => policy.WithHeaders(HeaderNames.CacheControl));

CORS Middleware lehnt eine Preflight-Anforderung mit dem folgenden Anforderungsheader ab, da Content-Language (HeaderNames.ContentLanguage) nicht in WithHeaders aufgeführt ist:

Access-Control-Request-Headers: Cache-Control, Content-Language

Die App gibt eine 200 OK-Antwort zurück, sendet die CORS-Header jedoch nicht zurück. Daher versucht der Browser die ursprungsübergreifende Anforderung nicht.

Festlegen der verfügbar gemachten Antwortheader

Standardmäßig macht der Browser nicht alle Antwortheader für die App verfügbar. Weitere Informationen finden Sie unter W3C Cross-Origin Resource Sharing (Terminologie): Einfacher Antwortheader.

Standardmäßig sind folgende Antwortheader verfügbar:

  • Cache-Control
  • Content-Language
  • Content-Type
  • Expires
  • Last-Modified
  • Pragma

Die CORS-Spezifikation ruft diese Header als einfache Antwortheader auf. Rufen Sie WithExposedHeaders auf, um andere Header für die App verfügbar zu machen:

options.AddPolicy("MyExposeResponseHeadersPolicy",
    policy =>
    {
        policy.WithOrigins("https://*.example.com")
               .WithExposedHeaders("x-custom-header");
    });

Anmeldeinformationen in ursprungsübergreifenden Anforderungen

Für Anmeldeinformationen ist in einer CORS-Anforderung eine besondere Behandlung erforderlich. Standardmäßig sendet der Browser mit einer ursprungsübergreifenden Anforderung keine Anmeldeinformationen. Zu den Anmeldeinformationen gehören cookies und HTTP-Authentifizierungsschemas. Zum Senden von Anmeldeinformationen mit einer ursprungsübergreifenden Anforderung muss der Client XMLHttpRequest.withCredentials auf true festlegen.

Mit direkter Verwendung von XMLHttpRequest:

var xhr = new XMLHttpRequest();
xhr.open('get', 'https://www.example.com/api/test');
xhr.withCredentials = true;

Mithilfe von jQuery:

$.ajax({
  type: 'get',
  url: 'https://www.example.com/api/test',
  xhrFields: {
    withCredentials: true
  }
});

Mithilfe der Fetch-API:

fetch('https://www.example.com/api/test', {
    credentials: 'include'
});

Der Server muss die Anmeldeinformationen zulassen. Rufen Sie AllowCredentials auf, um ursprungsübergreifende Anmeldeinformationen zuzulassen:

options.AddPolicy("MyMyAllowCredentialsPolicy",
    policy =>
    {
        policy.WithOrigins("http://example.com")
               .AllowCredentials();
    });

Die HTTP-Antwort enthält einen Access-Control-Allow-Credentials-Header, der dem Browser mitteilt, dass der Server Anmeldeinformationen für eine ursprungsübergreifende Anforderung zulässt.

Wenn der Browser Anmeldeinformationen sendet, die Antwort aber keinen gültigen Access-Control-Allow-Credentials-Header enthält, macht der Browser die Antwort für die App nicht verfügbar, und die ursprungsübergreifende Anforderung schlägt fehl.

Das Zulassen von ursprungsübergreifenden Anmeldeinformationen ist ein Sicherheitsrisiko. Eine Website in einer anderen Domäne kann die Anmeldeinformationen eines angemeldeten Benutzers im Namen des Benutzers ohne dessen Wissen an die App senden.

Die CORS-Spezifikation besagt ferner, dass das Festlegen von Ursprüngen auf "*" (alle Ursprünge) ungültig ist, wenn der Access-Control-Allow-Credentials-Header vorhanden ist.

Preflight-Anforderungen

Bei einigen CORS-Anforderungen sendet der Browser vor der eigentlichen Anforderung eine zusätzliche OPTIONS-Anforderung. Diese Anforderung wird als Preflight-Anforderung bezeichnet. Der Browser kann die Preflight-Anforderung überspringen, wenn alle folgenden Bedingungen erfüllt sind:

  • Die Anforderungsmethode ist GET, HEAD oder POST.
  • Die App legt keine anderen Anforderungsheader als Accept, Accept-Language, Content-Language, Content-Type oder Last-Event-ID fest.
  • Der Header Content-Type hat, sofern er festgelegt ist, einen der folgenden Werte:
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

Die für die Clientanforderung festgelegte Regel für Anforderungsheader gilt für Header, die die App durch Aufrufen von setRequestHeader für das XMLHttpRequest-Objekt festlegt. In der CORS-Spezifikation werden diese Header als Autorenanforderungsheader bezeichnet. Die Regel gilt nicht für Header, die vom Browser festgelegt werden können, wie etwa User-Agent, Host oder Content-Length.

Nachfolgend ist eine Beispielantwort ähnlich der Preflight-Anforderung, wie sie über die Schaltfläche [Put test] im Abschnitt Testen von CORS dieses Dokuments vorgenommen wird.

General:
Request URL: https://cors3.azurewebsites.net/api/values/5
Request Method: OPTIONS
Status Code: 204 No Content

Response Headers:
Access-Control-Allow-Methods: PUT,DELETE,GET
Access-Control-Allow-Origin: https://cors1.azurewebsites.net
Server: Microsoft-IIS/10.0
Set-Cookie: ARRAffinity=8f8...8;Path=/;HttpOnly;Domain=cors1.azurewebsites.net
Vary: Origin

Request Headers:
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Access-Control-Request-Method: PUT
Connection: keep-alive
Host: cors3.azurewebsites.net
Origin: https://cors1.azurewebsites.net
Referer: https://cors1.azurewebsites.net/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0

Die Preflight-Anforderung verwendet die HTTP OPTIONS-Methode. Sie kann die folgenden Header enthalten:

Wenn die Preflight-Anforderung abgelehnt wird, gibt die App eine 200 OK-Antwort zurück, legt aber die CORS-Header nicht fest. Daher versucht der Browser die ursprungsübergreifende Anforderung nicht. Ein Beispiel für eine verweigerte Preflight-Anforderung finden Sie im Abschnitt Testen von CORS in diesem Dokument.

Bei Verwendung der F12-Tools zeigt die Konsolen-App je nach Browser einen Fehler ähnlich einem der folgenden an:

  • Firefox: Ursprungsübergreifende Anforderung blockiert: Die Richtlinie des gleichen Ursprungs lässt das Lesen der Remoteressource unter https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5 nicht zu. (Grund: CORS-Anforderung war nicht erfolgreich). Weitere Informationen
  • Chromium-basiert: Der Zugriff auf Fetch unter „https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5“ vom Ursprung „https://cors3.azurewebsites.net“ wurde durch die CORS-Richtlinie blockiert: Die Antwort auf eine Preflight-Anforderung hat die Zugriffssteuerungsprüfung nicht bestanden: Für die angeforderte Ressource ist kein „Access-Control-Allow-Origin“-Header vorhanden. Falls eine opake Antwort Ihre Anforderungen erfüllt, legen Sie den Modus der Anforderung auf „no-cors“ fest, um CORS für den Ressourcenabruf zu deaktivieren.

Rufen Sie WithHeaders auf, um bestimmte Header zuzulassen:

options.AddPolicy("MyAllowHeadersPolicy",
    policy =>
    {
        // requires using Microsoft.Net.Http.Headers;
        policy.WithOrigins("http://example.com")
               .WithHeaders(HeaderNames.ContentType, "x-custom-header");
    });

Rufen Sie zum Zulassen aller AutorenanforderungsheaderAllowAnyHeader auf:

options.AddPolicy("MyAllowAllHeadersPolicy",
    policy =>
    {
        policy.WithOrigins("https://*.example.com")
               .AllowAnyHeader();
    });

Browser sind in der Festlegung von Access-Control-Request-Headers nicht konsistent. Hier gelten entweder:

  • Die Header sind auf einen anderen Wert als "*" festgelegt
  • AllowAnyHeader wird aufgerufen: Schließen Sie mindestens Accept, Content-Type und Origin sowie alle benutzerdefinierten Header ein, die Sie unterstützen möchten.

Code für automatische Preflight-Anforderungen

Die CORS-Richtlinie wird auf eine dieser Weisen angewendet:

  • Global durch Aufrufen von app.UseCors in Startup.Configure.
  • Mithilfe des [EnableCors]-Attributs.

ASP.NET Core antwortet auf die Preflight-Anforderung OPTIONS.

Das Aktivieren von CORS pro Endpunkt mit RequireCors unterstützt derzeit keine automatischen Preflight-Anforderungen.

Im Abschnitt Testen von CORS dieses Dokuments wird dieses Verhalten veranschaulicht.

[HttpOptions]-Attribut für Preflight-Anforderungen

Wenn CORS mit der entsprechenden Richtlinie aktiviert ist, reagiert ASP.NET Core in der Regel automatisch auf CORS-Preflight-Anforderungen. Bei einigen Szenarien ist dies möglicherweise nicht der Fall. Beispielsweise beim Verwenden von CORS mit Endpunktrouting.

Der folgende Code verwendet das [HttpOptions]-Attribut, um Endpunkte für OPTIONS-Anforderungen zu erstellen:

[Route("api/[controller]")]
[ApiController]
public class TodoItems2Controller : ControllerBase
{
    // OPTIONS: api/TodoItems2/5
    [HttpOptions("{id}")]
    public IActionResult PreflightRoute(int id)
    {
        return NoContent();
    }

    // OPTIONS: api/TodoItems2 
    [HttpOptions]
    public IActionResult PreflightRoute()
    {
        return NoContent();
    }

    [HttpPut("{id}")]
    public IActionResult PutTodoItem(int id)
    {
        if (id < 1)
        {
            return BadRequest();
        }

        return ControllerContext.MyDisplayRouteInfo(id);
    }

Anweisungen zum Testen des vorstehenden Codes finden Sie unter Testen von CORS mit Endpunktrouting und [HttpOptions].

Festlegen der Preflight-Ablaufzeit

Der Access-Control-Max-Age-Header gibt an, wie lange die Antwort auf die Preflight-Anforderung zwischengespeichert werden kann. Rufen Sie SetPreflightMaxAge auf, um diesen Header festzulegen:

options.AddPolicy("MySetPreflightExpirationPolicy",
    policy =>
    {
        policy.WithOrigins("http://example.com")
               .SetPreflightMaxAge(TimeSpan.FromSeconds(2520));
    });

Funktionsweise von CORS

In diesem Abschnitt wird beschrieben, was in einer CORS-Anforderung auf der Ebene der HTTP-Nachrichten geschieht.

  • CORS ist kein Sicherheitsfeature. CORS ist ein W3C-Standard, der einem Server eine weniger strenge Anwendung der Richtlinie desselben Ursprungs ermöglicht.
    • Beispielsweise könnte ein böswilliger Akteur Cross-Site Scripting (XSS) auf Ihre Website anwenden und eine websiteübergreifende Anforderung an seine CORS-fähige Website vornehmen, um Informationen zu stehlen.
  • Durch Zulassen von CORS wird eine API wird nicht sicherer.
    • Das Durchsetzen von CORS liegt in der Zuständigkeit des Clients (Browsers). Der Server führt die Anforderung aus und gibt die Antwort zurück. Es ist der Client, der einen Fehler zurückgibt und die Antwort blockiert. Beispielsweise wird für jedes der folgenden Tools die Serverantwort angezeigt:
  • Es stellt eine Möglichkeit für einen Server dar, Browsern die Ausführung einer ursprungsübergreifenden XHR- oder Fetch-API-Anforderung zu erlauben, die andernfalls verboten wäre.
    • Browser ohne CORS können keine ursprungsübergreifenden Anforderungen ausführen. Vor CORS wurde JSONP verwendet, um diese Einschränkung zu umgehen. JSONP verwendet nicht XHR, es verwendet das <script>-Tag, um die Antwort zu empfangen. Skripts dürfen ursprungsübergreifend geladen werden.

Mit der CORS-Spezifikation wurden mehrere neue HTTP-Header eingeführt, die ursprungsübergreifende Anforderungen ermöglichen. Wenn ein Browser CORS unterstützt, legt er diese Header für ursprungsübergreifende Anforderungen automatisch fest. Zum Aktivieren von CORS ist kein benutzerdefinierter JavaScript-Code erforderlich.

Die PUT test-Schaltfläche im bereitgestellten Beispiel

Nachfolgend ist ein Beispiel für eine ursprungsübergreifende Anforderung von der Werte-Testschaltfläche an https://cors1.azurewebsites.net/api/values. Der Origin-Header:

  • Gibt die Domäne der Website an, die die Anforderung ausführt.
  • Ist erforderlich und muss sich vom Host unterscheiden.

Allgemeine Header

Request URL: https://cors1.azurewebsites.net/api/values
Request Method: GET
Status Code: 200 OK

Antwortheader

Content-Encoding: gzip
Content-Type: text/plain; charset=utf-8
Server: Microsoft-IIS/10.0
Set-Cookie: ARRAffinity=8f...;Path=/;HttpOnly;Domain=cors1.azurewebsites.net
Transfer-Encoding: chunked
Vary: Accept-Encoding
X-Powered-By: ASP.NET

Anforderungsheader

Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Connection: keep-alive
Host: cors1.azurewebsites.net
Origin: https://cors3.azurewebsites.net
Referer: https://cors3.azurewebsites.net/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0 ...

In OPTIONS-Anforderungen legt der Server den AntwortheaderAccess-Control-Allow-Origin: {allowed origin}-Header in der Antwort fest. Beispielsweise enthält die OPTIONS-Anforderung im zur Verfügung gestellten MusterDelete [EnableCors]-Schaltfläche die folgenden Header:

Allgemeine Header

Request URL: https://cors3.azurewebsites.net/api/TodoItems2/MyDelete2/5
Request Method: OPTIONS
Status Code: 204 No Content

Antwortheader

Access-Control-Allow-Headers: Content-Type,x-custom-header
Access-Control-Allow-Methods: PUT,DELETE,GET,OPTIONS
Access-Control-Allow-Origin: https://cors1.azurewebsites.net
Server: Microsoft-IIS/10.0
Set-Cookie: ARRAffinity=8f...;Path=/;HttpOnly;Domain=cors3.azurewebsites.net
Vary: Origin
X-Powered-By: ASP.NET

Anforderungsheader

Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Access-Control-Request-Headers: content-type
Access-Control-Request-Method: DELETE
Connection: keep-alive
Host: cors3.azurewebsites.net
Origin: https://cors1.azurewebsites.net
Referer: https://cors1.azurewebsites.net/test?number=2
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0

In den vorstehenden Antwortheadern legt der Server den Access-Control-Allow-Origin-Header in der Antwort fest. Der https://cors1.azurewebsites.net-Wert dieses Headers stimmt mit dem Origin-Header aus der Anforderung überein.

Wenn AllowAnyOrigin aufgerufen wird, wird Access-Control-Allow-Origin: * zurückgegeben, der Platzhalterwert. AllowAnyOrigin lässt jeden Ursprung zu.

Wenn die Antwort den Access-Control-Allow-Origin-Header nicht enthält, schlägt die ursprungsübergreifende Anforderung fehl. Insbesondere lässt der Browser die Anforderung nicht zu. Auch wenn der Server eine erfolgreiche Antwort zurückgibt, stellt der Browser die Antwort der Client-App nicht zur Verfügung.

Anzeigen von OPTIONS-Anforderungen

Standardmäßig zeigen die Chrome- und Edge-Browser OPTIONS-Anforderungen auf der Registerkarte „Netzwerk“ der F12-Tools nicht an. So zeigen Sie OPTIONS-Anforderungen in diesen Browsern an:

  • chrome://flags/#out-of-blink-cors oder edge://flags/#out-of-blink-cors
  • deaktivieren das Flag.
  • Neustart.

Firefox zeigt OPTIONS-Anforderungen standardmäßig an.

CORS in IIS

Bei der Bereitstellung in IIS muss CORS vor der Windows-Authentifizierung ausgeführt werden, wenn der Server nicht für den anonymen Zugriff konfiguriert ist. Zum Unterstützen dieses Szenarios muss das IIS-CORS-Modul installiert und für die App konfiguriert werden.

Testen von CORS

Der Beispieldownload enthält Code zum Testen von CORS. Informationen zum Herunterladen finden Sie hier. Das Beispiel ist ein API-Projekt mit hinzugefügten Razor Pages:

public class StartupTest2
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddCors(options =>
        {
            options.AddPolicy(name: "MyPolicy",
                policy =>
                {
                    policy.WithOrigins("http://example.com",
                        "http://www.contoso.com",
                        "https://cors1.azurewebsites.net",
                        "https://cors3.azurewebsites.net",
                        "https://localhost:44398",
                        "https://localhost:5001")
                            .WithMethods("PUT", "DELETE", "GET");
                });
        });

        services.AddControllers();
        services.AddRazorPages();
    }

    public void Configure(IApplicationBuilder app)
    {
        app.UseHttpsRedirection();
        app.UseStaticFiles();
        app.UseRouting();

        app.UseCors();

        app.UseAuthorization();

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

Warnung

WithOrigins("https://localhost:<port>"); sollte nur zum Testen einer Beispiel-App verwendet werden, die dem Code des Downloadbeispiels ähnelt.

Der folgende ValuesController stellt die Endpunkte zum Testen zur Verfügung:

[EnableCors("MyPolicy")]
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
    // GET api/values
    [HttpGet]
    public IActionResult Get() =>
        ControllerContext.MyDisplayRouteInfo();

    // GET api/values/5
    [HttpGet("{id}")]
    public IActionResult Get(int id) =>
        ControllerContext.MyDisplayRouteInfo(id);

    // PUT api/values/5
    [HttpPut("{id}")]
    public IActionResult Put(int id) =>
        ControllerContext.MyDisplayRouteInfo(id);


    // GET: api/values/GetValues2
    [DisableCors]
    [HttpGet("{action}")]
    public IActionResult GetValues2() =>
        ControllerContext.MyDisplayRouteInfo();

}

MyDisplayRouteInfo wird von dem NuGet-Paket Rick.Docs.Samples.RouteInfo bereitgestellt und zeigt Routeninformationen an.

Testen Sie den vorstehenden Beispielcode mit einem der folgenden Ansätze:

  • Verwenden Sie die unter https://cors3.azurewebsites.net/ zur Verfügung gestellte Beispiel-App. Das Beispiel muss nicht heruntergeladen werden.
  • Führen Sie das Beispiel mit dotnet run mit der Standard-URL https://localhost:5001 aus.
  • Führen Sie das Beispiel in Visual Studio aus, wobei der Port für die URL https://localhost:44398 auf 44398 festgelegt ist.

Verwenden eines Browsers mit den F12-Tools:

  • Wählen Sie die Schaltfläche Werte aus, und überprüfen Sie die Header auf der Registerkarte Netzwerk.

  • Wählen Sie die Schaltfläche PUT test aus. Anweisungen zum Anzeigen der OPTIONS-Anforderung finden Sie unter Anzeigen von OPTIONS-Anforderungen. PUT test erstellt zwei Anforderungen, eine OPTIONS-Preflight-Anforderung und die PUT-Anforderung.

  • Wählen Sie die GetValues2 [DisableCors]-Schaltfläche aus, um eine fehlerhafte CORS-Anforderung auszulösen. Wie im Dokument erwähnt, gibt die Antwort „200 (Erfolg)“ zurück, aber die CORS-Anforderung wird nicht ausgeführt. Wählen Sie die Registerkarte Konsole aus, um den CORS-Fehler anzuzeigen. Abhängig vom Browser wird ein Fehler ähnlich dem Folgenden angezeigt:

    Der Zugriff auf Fetch unter 'https://cors1.azurewebsites.net/api/values/GetValues2' vom Ursprung 'https://cors3.azurewebsites.net' wurde durch die CORS-Richtlinie blockiert: In der angeforderten Ressource ist kein „Access-Control-Allow-Origin“-Header vorhanden. Falls eine opake Antwort Ihre Anforderungen erfüllt, legen Sie den Modus der Anforderung auf „no-cors“ fest, um CORS für den Ressourcenabruf zu deaktivieren.

CORS-fähige Endpunkte können mit einem Tool wie cURL oder Fiddler getestet werden. Bei Verwendung eines Tools muss sich der Ursprung der durch den Origin-Header angegebenen Anforderung von dem Host unterscheiden, der die Anforderung empfängt. Wenn die Anforderung auf der Grundlage des Werts des Origin-Headers nicht ursprungsübergreifend ist:

  • Es besteht keine Notwendigkeit, dass die Anforderung durch die CORS-Middleware verarbeitet wird.
  • CORS-Header werden in der Antwort nicht zurückgegeben.

Der folgende Befehl verwendet curl, um eine OPTIONS-Anforderung mit Informationen auszugeben:

curl -X OPTIONS https://cors3.azurewebsites.net/api/TodoItems2/5 -i

Testen von CORS mit Endpunktrouting und [HttpOptions]

Das Aktivieren von CORS pro Endpunkt mit RequireCors unterstützt derzeit keineautomatischen Preflight-Anforderungen. Betrachten Sie den folgenden Code, der Endpunktrouting zum Aktivieren von CORS verwendet:

public class StartupEndPointBugTest
{
    readonly string MyPolicy = "_myPolicy";

    // .WithHeaders(HeaderNames.ContentType, "x-custom-header")
    // forces browsers to require a preflight request with GET

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddCors(options =>
        {
            options.AddPolicy(name: MyPolicy,
                policy =>
                {
                    policy.WithOrigins("http://example.com",
                                        "http://www.contoso.com",
                                        "https://cors1.azurewebsites.net",
                                        "https://cors3.azurewebsites.net",
                                        "https://localhost:44398",
                                        "https://localhost:5001")
                           .WithHeaders(HeaderNames.ContentType, "x-custom-header")
                           .WithMethods("PUT", "DELETE", "GET", "OPTIONS");
                });
        });

        services.AddControllers();
        services.AddRazorPages();
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        app.UseHttpsRedirection();
        app.UseStaticFiles();
        app.UseRouting();

        app.UseCors();

        app.UseAuthorization();

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

Der folgende TodoItems1Controller stellt die Endpunkte zum Testen zur Verfügung:

[Route("api/[controller]")]
[ApiController]
public class TodoItems1Controller : ControllerBase
{
    // PUT: api/TodoItems1/5
    [HttpPut("{id}")]
    public IActionResult PutTodoItem(int id)
    {
        if (id < 1)
        {
            return Content($"ID = {id}");
        }

        return ControllerContext.MyDisplayRouteInfo(id);
    }

    // Delete: api/TodoItems1/5
    [HttpDelete("{id}")]
    public IActionResult MyDelete(int id) =>
        ControllerContext.MyDisplayRouteInfo(id);

    // GET: api/TodoItems1
    [HttpGet]
    public IActionResult GetTodoItems() =>
        ControllerContext.MyDisplayRouteInfo();

    [EnableCors]
    [HttpGet("{action}")]
    public IActionResult GetTodoItems2() =>
        ControllerContext.MyDisplayRouteInfo();

    // Delete: api/TodoItems1/MyDelete2/5
    [EnableCors]
    [HttpDelete("{action}/{id}")]
    public IActionResult MyDelete2(int id) =>
        ControllerContext.MyDisplayRouteInfo(id);
}

Testen Sie den vorstehenden Code auf der Testseite des bereitgestellten Beispiels.

Die Schaltflächen Delete [EnableCors] und GET [EnableCors] werden erfolgreich ausgeführt, da die Endpunkte über [EnableCors] verfügen und auf Preflight-Anforderungen antworten. Bei den anderen Endpunkten tritt ein Fehler auf. Bei der GET-Schaltfläche tritt ein Fehler auf, da das JavaScript Folgendes sendet:

 headers: {
      "Content-Type": "x-custom-header"
 },

Der folgende TodoItems2Controller stellt ähnliche Endpunkte zur Verfügung, schließt aber expliziten Code zum Antworten auf OPTIONS-Anforderungen ein:

[Route("api/[controller]")]
[ApiController]
public class TodoItems2Controller : ControllerBase
{
    // OPTIONS: api/TodoItems2/5
    [HttpOptions("{id}")]
    public IActionResult PreflightRoute(int id)
    {
        return NoContent();
    }

    // OPTIONS: api/TodoItems2 
    [HttpOptions]
    public IActionResult PreflightRoute()
    {
        return NoContent();
    }

    [HttpPut("{id}")]
    public IActionResult PutTodoItem(int id)
    {
        if (id < 1)
        {
            return BadRequest();
        }

        return ControllerContext.MyDisplayRouteInfo(id);
    }

    // [EnableCors] // Not needed as OPTIONS path provided
    [HttpDelete("{id}")]
    public IActionResult MyDelete(int id) =>
        ControllerContext.MyDisplayRouteInfo(id);

    [EnableCors]  // Rquired for this path
    [HttpGet]
    public IActionResult GetTodoItems() =>
        ControllerContext.MyDisplayRouteInfo();

    [HttpGet("{action}")]
    public IActionResult GetTodoItems2() =>
        ControllerContext.MyDisplayRouteInfo();

    [EnableCors]  // Rquired for this path
    [HttpDelete("{action}/{id}")]
    public IActionResult MyDelete2(int id) =>
        ControllerContext.MyDisplayRouteInfo(id);
}

Testen Sie den vorstehenden Code auf der Testseite des bereitgestellten Beispiels. Wählen Sie in der Dropdownliste Controller die Option Preflight und dann Controller festlegen aus. Alle CORS-Aufrufe an die TodoItems2Controller-Endpunkte sind erfolgreich.

Zusätzliche Ressourcen