Aktivieren ursprungsübergreifender Anforderungen (Cross-Origin Requests, CORS) in ASP.NET Core

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 möchten Sie anderen Websites erlauben, ursprungsübergreifende Anforderungen an Ihre App zu stellen. Weitere Informationen finden Sie im Mozilla CORS-Artikel.

Cross Origin Resource Sharing (CORS):

  • Ein W3C-Standard, der es einem Server ermöglicht, die Richtlinie desselben Ursprungs zu lockern.
  • Ist kein Sicherheitsfeature, cors lockert die Sicherheit. Eine API ist nicht sicherer, indem CORS zugelassen wird. Weitere Informationen finden Sie unter Funktionsweise von CORS.
  • Ermöglicht es einem Server, einige ursprungsübergreifende Anforderungen explizit zuzulassen, während andere abgelehnt werden.
  • Ist sicherer und flexibler als frühere Techniken, z. B. 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 denselben Ursprung:

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

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

  • https://example.net: Unterschiedliche 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 drei Möglichkeiten, CORS zu aktivieren:

Die Verwendung des [EnableCors]-Attributs mit einer benannten Richtlinie bietet die beste Kontrolle beim Einschränken von Endpunkten, die CORS unterstützen.

Warnung

UseCors muss in der richtigen Reihenfolge aufgerufen werden. Weitere Informationen finden Sie unter Middleware reihenfolge. Muss UseCors z. B. vor aufgerufen werden, UseResponseCaching wenn verwendet UseResponseCaching wird.

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,
                              builder =>
                              {
                                  builder.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 Richtlinienname ist willkürlich.
  • Ruft die UseCors Erweiterungsmethode auf und gibt die _myAllowSpecificOrigins CORS-Richtlinie an. UseCors fügt die CORS-Middleware hinzu. Der Aufruf von UseCors muss nach , aber vor platziert UseRouting UseAuthorization werden. Weitere Informationen finden Sie unter Middleware reihenfolge.
  • Ruft AddCors mit einem Lambdaausdruck auf. Der Lambda-Ausdruck nimmt ein CorsPolicyBuilder -Objekt an. Konfigurationsoptionenwie WithOrigins werden weiter unten in diesem Artikel beschrieben.
  • Aktiviert die _myAllowSpecificOrigins CORS-Richtlinie für alle Controllerendpunkte. Informationen zum Anwenden einer CORS-Richtlinie auf bestimmte Endpunkte finden Sie unter Endpunktrouting.
  • Wenn Sie middleware für das Zwischenspeichernvon Antworten verwenden, rufen Sie UseCors vor UseResponseCaching auf.

Beim Endpunktrouting muss die CORS-Middleware so konfiguriert werden, dass sie zwischen den Aufrufen von und ausgeführt UseRouting UseEndpoints wird.

Anweisungen zum Testen von Code, der dem vorangehenden Code ähnelt, finden Sie unter Testen von CORS.

Der AddCors Methodenaufruf 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,
                              builder =>
                              {
                                  builder.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,
                          builder =>
                          {
                              builder.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, wird der Vergleich false zurückgegeben, 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(
                builder =>
                {
                    builder.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 vorangehende Code wendet die CORS-Standardrichtlinie auf alle Controllerendpunkte an.

Aktivieren von Cors mit Endpunktrouting

Das Aktivieren von CORS auf Endpunktbasis mit RequireCors unterstützt keine automatischen Preflightanforderungen. Weitere Informationen finden Sie unter diesem GitHub-Problem und Testen von CORS mit Endpunktrouting und [HttpOptions].

Beim Endpunktrouting kann CORS mithilfe der Erweiterungsmethoden pro Endpunkt aktiviert RequireCors werden:

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

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddCors(options =>
        {
            options.AddPolicy(name: MyAllowSpecificOrigins,
                              builder =>
                              {
                                  builder.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();
        });
    }
}

Im obigen Code:

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

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

Anweisungen zum Testen von Code, der dem vorherigen ähnelt, 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 nur auf die Endpunkte, die CORS erfordern, bietet die beste Kontrolle.

Das [EnableCors]-Attribut stellt eine Alternative zur globalen Anwendung von CORS dar. Das [EnableCors] -Attribut aktiviert CORS für ausgewählte Endpunkte und nicht für alle Endpunkte:

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

Das [EnableCors] -Attribut kann auf:

  • Razor Seite PageModel
  • Controller
  • Controlleraktionsmethode

Mit dem -Attribut können verschiedene Richtlinien auf Controller, Seitenmodelle oder Aktionsmethoden angewendet [EnableCors] werden. Wenn das Attribut auf einen Controller, ein Seitenmodell oder eine Aktionsmethode angewendet wird [EnableCors] und CORS in Middleware aktiviert ist, werden beide Richtlinien angewendet. Wir raten davon ab, Richtlinien zu kombinieren. Verwenden Sie [EnableCors] das Attribut oder die Middleware, nicht beide 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",
                builder =>
                {
                    builder.WithOrigins("http://example.com",
                                        "http://www.contoso.com");
                });

            options.AddPolicy("AnotherPolicy",
                builder =>
                {
                    builder.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();
        });
    }
}

Für die beste Kontrolle über das Einschränken von CORS-Anforderungen:

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

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

Anweisungen zum Testen von Code, der dem vorangehenden Code ähnelt, finden Sie unter Testen von CORS.

Deaktivieren von CORS

Das [DisableCors]-Attribut deaktiviert nicht CORS, das vom Endpunktroutingaktiviert wurde.

Der folgende Code definiert die CORS-Richtlinie: "MyPolicy"

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddCors(options =>
        {
            options.AddPolicy(name: "MyPolicy",
                builder =>
                {
                    builder.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 GetValues2 Aktion:

[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 vorangehenden 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 hilfreich 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 senden kann.

Hinweis

Die Angabe AllowAnyOrigin von und ist eine AllowCredentials unsichere Konfiguration und kann zu einer websiteübergreifenden 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 Preflightanforderungen und den Access-Control-Allow-Origin -Header aus. Weitere Informationen finden Sie im Abschnitt Preflightanforderungen.

SetIsOriginAllowedToAllowWildcardSubdomains: Legt die -Eigenschaft der Richtlinie auf eine Funktion fest, mit der Ursprünge mit einer konfigurierten Platzhalterdomäne übereinstimmen können, wenn bewertet wird, ob der IsOriginAllowed Ursprung zulässig ist.

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

Festlegen der zulässigen HTTP-Methoden

AllowAnyMethod:

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

Festlegen der zulässigen Anforderungsheader

Um das Senden bestimmter Header in einer CORS-Anforderung zu ermöglichen, die als Author Request-Headerbezeichnet wird, rufen Sie auf, und WithHeaders geben Sie die zulässigen Header an:

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

Um alle Anforderungsheader des Autors zu ermöglichen,rufen Sie AllowAnyHeader auf:

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

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

Eine CORS-Middlewarerichtlinie, die mit bestimmten von angegebenen Headern übereinstimmt, WithHeaders ist nur möglich, wenn die gesendeten Header Access-Control-Request-Headers genau mit den in angegebenen Headern WithHeaders übereinstimmen.

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

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

Cors-Middleware lehnt eine Preflightanforderung mit dem folgenden Anforderungsheader ab, da Content-Language (HeaderNames.ContentLanguage) nicht in aufgeführt WithHeaders 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 nicht, die ursprungsübergreifende Anforderung zu verwenden.

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): Simple Response Header.

Die standardmäßig verfügbaren Antwortheader sind:

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

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

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

Anmeldeinformationen in ursprungsübergreifenden Anforderungen

Anmeldeinformationen erfordern eine besondere Behandlung in einer CORS-Anforderung. Standardmäßig sendet der Browser keine Anmeldeinformationen mit einer ursprungsübergreifenden Anforderung. Zu den Anmeldeinformationen gehören cookie s- und HTTP-Authentifizierungsschemas. Um Anmeldeinformationen mit einer ursprungsübergreifenden Anforderung zu senden, muss der Client XMLHttpRequest.withCredentials auf true festlegen.

Direkte XMLHttpRequest Verwendung:

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

Verwenden von jQuery:

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

Verwenden der Fetch-API:

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

Der Server muss die Anmeldeinformationen zulassen. Um ursprungsübergreifende Anmeldeinformationen zu ermöglichen, rufen Sie AllowCredentials auf:

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

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

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

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

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

Preflightanforderungen

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

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

Die Regel für Anforderungsheader, die für die Clientanforderung festgelegt werden, gilt für Header, die die App durch Aufrufen von setRequestHeader für das -Objekt XMLHttpRequest festgelegt hat. Die CORS-Spezifikation ruft diese Header author request headers auf. Die Regel gilt nicht für Header, die der Browser festlegen kann, z. B. User-Agent Host , oder Content-Length .

Im Folgenden finden Sie eine Beispielantwort, die der Preflightanforderung ähnelt, die über die Schaltfläche [Put test] im Abschnitt Test CORS dieses Dokuments erfolgt ist.

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 Preflightanforderung verwendet die HTTP OPTIONS-Methode. Sie kann die folgenden Header enthalten:

Wenn die Preflightanforderung abgelehnt wird, gibt die App eine 200 OK Antwort zurück, legt jedoch die CORS-Header nicht fest. Daher versucht der Browser nicht, die ursprungsübergreifende Anforderung zu verwenden. Ein Beispiel für eine abgelehnte Preflightanforderung 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 dem folgenden an:

  • Firefox: Ursprungsübergreifende Anforderung blockiert: Die gleiche Ursprungsrichtlinie verhindert das Lesen der Remoteressource unter https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5 . (Ursache: Die CORS-Anforderung war nicht erfolgreich.) Weitere Informationen
  • Chromium-basiert: Der Zugriff auf den Abruf von "" vom Ursprung " wurde durch die https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5 https://cors3.azurewebsites.net CORS-Richtlinie blockiert: Die Antwort auf eine Preflightanforderung besteht keine Zugriffssteuerungsüberprüfung: Für die angeforderte Ressource ist kein Header "Access-Control-Allow-Origin" 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.

Um bestimmte Header zuzulassen, rufen Sie WithHeaders auf:

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

Um alle Header von Erstellungsanforderungenzuzulassen, rufen Sie AllowAnyHeader auf:

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

Browser sind bei der Festlegung von nicht Access-Control-Request-Headers konsistent. Wenn einer der beiden ist:

  • Header werden auf eine andere Einstellung als festgelegt. "*"
  • AllowAnyHeader wird aufgerufen: Schließen Sie mindestens Accept , und sowie alle Content-Type Origin benutzerdefinierten Header ein, die Sie unterstützen möchten.

Code für automatische Preflightanforderungen

Wenn die CORS-Richtlinie angewendet wird, gilt Folgendes:

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

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

Die Aktivierung von CORS pro Endpunkt mit unterstützt derzeit keine automatischen RequireCors Preflightanforderungen.

Dieses Verhalten wird im Abschnitt Test CORS dieses Dokuments veranschaulicht.

[HttpOptions]-Attribut für Preflightanforderungen

Wenn CORS mit der entsprechenden Richtlinie aktiviert ist, reagiert ASP.NET Core in der Regel automatisch auf CORS-Preflightanforderungen. In einigen Szenarien ist dies möglicherweise nicht der Fall. Verwenden Sie z. B. CORS mit Endpunktrouting.

Im folgenden Code wird das [HttpOptions]-Attribut verwendet, 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 vorangehenden 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 Preflightanforderung zwischengespeichert werden kann. Rufen Sie zum Festlegen dieses Headers SetPreflightMaxAge auf:

options.AddPolicy("MySetPreflightExpirationPolicy",
    builder =>
    {
        builder.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, mit dem ein Server die Richtlinie für den gleichen Ursprung lockern kann.
    • Beispielsweise könnte ein böswilliger Akteur Cross-Site Scripting (XSS) für Ihre Website verwenden und eine websiteübergreifende Anforderung an die CORS-fähige Website ausführen, um Informationen zu stehlen.
  • Eine API ist nicht sicherer, da CORS erlaubt wird.
    • Der Client (Browser) muss CORS erzwingen. 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 zeigt eines der folgenden Tools die Serverantwort an:
  • Es ist eine Möglichkeit für einen Server, Browsern das Ausführen einer ursprungsübergreifenden XHR- oder Fetch-API-Anforderung zu ermöglichen, die andernfalls unzulässig wäre.
    • Browser ohne CORS können keine ursprungsübergreifenden Anforderungen durchführen. Vor CORS wurde JSONP verwendet, um diese Einschränkung zu umgehen. JSONP verwendet XHR nicht, es verwendet das <script> -Tag, um die Antwort zu empfangen. Skripts dürfen ursprungsübergreifend geladen werden.

Die CORS-Spezifikation hat mehrere neue HTTP-Header eingeführt, die ursprungsübergreifende Anforderungen ermöglichen. Wenn ein Browser CORS unterstützt, werden diese Header automatisch für ursprungsübergreifende Anforderungen festgelegt. Benutzerdefinierter JavaScript-Code ist nicht erforderlich, um CORS zu aktivieren.

Put-Testschaltfläche für das bereitgestellte Beispiel

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

  • Stellt die Domäne des Standorts bereit, von dem die Anforderung gestellt wird.
  • 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 Header Antwortheader Access-Control-Allow-Origin: {allowed origin} in der Antwort fest. Beispielsweise enthält die bereitgestellte Beispielanforderung, Delete [EnableCors] button request ([EnableCors]-Schaltfläche OPTIONS löschen) 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 obigen Antwortheadern legt der Server den Access-Control-Allow-Origin-Header in der Antwort fest. Der https://cors1.azurewebsites.net Wert dieses Headers entspricht dem Header aus Origin der Anforderung.

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

Wenn die Antwort den Header nicht Access-Control-Allow-Origin enthält, schlägt die ursprungsübergreifende Anforderung fehl. Insbesondere der Browser lehnt die Anforderung ab. Auch wenn der Server eine erfolgreiche Antwort zurückgibt, macht der Browser die Antwort nicht für die Client-App verfügbar.

Anzeigen von OPTIONS-Anforderungen

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

  • chrome://flags/#out-of-blink-cors oder edge://flags/#out-of-blink-cors
  • Deaktivieren Sie das -Flag.
  • „Neu starten“.

Firefox zeigt standardmäßig OPTIONS-Anforderungen 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. Um dieses Szenario zu unterstützen, muss das IIS-CORS-Modul für die App installiert und 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 Razor hinzugefügten Pages:

public class StartupTest2
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddCors(options =>
        {
            options.AddPolicy(name: "MyPolicy",
                builder =>
                {
                    builder.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 Downloadbeispielcode ähnelt.

Im Folgenden ValuesController werden die Endpunkte für Tests angegeben:

[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 obigen Beispielcode mithilfe eines der folgenden Ansätze:

  • Verwenden Sie die bereitgestellte Beispiel-App unter https://cors3.azurewebsites.net/ . Es ist nicht erforderlich, das Beispiel herunterzuladen.
  • Führen Sie das Beispiel dotnet run mit unter Verwendung der Standard-URL von https://localhost:5001 aus.
  • Führen Sie das Beispiel aus Visual Studio aus, wobei der Port für eine URL von auf 44398 festgelegt https://localhost:44398 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. Der PUT-Test erstellt zwei Anforderungen: eine OPTIONS-Preflightanforderung 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 gestellt. Wählen Sie die Registerkarte Konsole aus, um den CORS-Fehler anzuzeigen. Je nach Browser wird ein Fehler ähnlich dem folgenden angezeigt:

    Der Zugriff zum Abrufen aus dem Ursprung wurde durch die 'https://cors1.azurewebsites.net/api/values/GetValues2' 'https://cors3.azurewebsites.net' CORS-Richtlinie blockiert: Für die angeforderte Ressource ist kein Header "Access-Control-Allow-Origin" 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, Fiddleroder Postmangetestet werden. Bei Verwendung eines Tools muss sich der Ursprung der durch den Header angegebenen Anforderung Origin vom Host unterscheiden, der die Anforderung empfängt. Wenn die Anforderung nicht ursprungsübergreifend ist, basierend auf dem Wert des Origin Headers:

  • Cors-Middleware muss die Anforderung nicht verarbeiten.
  • 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]

Die Aktivierung von CORS pro Endpunkt mit unterstützt derzeit keine automatischen RequireCors Preflightanforderungen. Betrachten Sie den folgenden Code, der Endpunktrouting verwendet, um CORS zu aktivieren:

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,
                builder =>
                {
                    builder.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();
        });
    }
}

Im Folgenden TodoItems1Controller finden Sie Endpunkte für Tests:

[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 vorangehenden Code auf der Testseite des bereitgestellten Beispiels.

Die Schaltflächen Löschen [EnableCors] und GET [EnableCors] sind erfolgreich, da die Endpunkte [EnableCors] preflight-Anforderungen haben und darauf reagieren. Die anderen Endpunkte können nicht verwendet werden. Die Get-Schaltfläche schlägt fehl, da der JavaScript-Code:

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

Das folgende TodoItems2Controller Beispiel enthält ähnliche Endpunkte, enthält jedoch expliziten Code, um auf OPTIONS-Anforderungen zu reagieren:

[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 obigen 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

In diesem Artikel wird gezeigt, 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 möchten Sie anderen Websites erlauben, ursprungsübergreifende Anforderungen an Ihre App zu senden. Weitere Informationen finden Sie im Mozilla CORS-Artikel.

Cross Origin Resource Sharing (CORS):

  • Ein W3C-Standard, der es einem Server ermöglicht, die Richtlinie für den gleichen Ursprung zu lockern.
  • Ist kein Sicherheitsfeature, cors lockert die Sicherheit. Eine API ist nicht sicherer, indem CORS zugelassen wird. Weitere Informationen finden Sie unter Funktionsweise von CORS.
  • Ermöglicht es einem Server, einige ursprungsübergreifende Anforderungen explizit zuzulassen, während andere abgelehnt werden.
  • Ist sicherer und flexibler als frühere Techniken, z. B. 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 denselben Ursprung:

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

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

  • https://example.net: Unterschiedliche 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

Internet Explorer berücksichtigt den Port beim Vergleichen von Ursprüngen nicht.

CORS mit benannter Richtlinie und Middleware

CORS-Middleware verarbeitet ursprungsübergreifende Anforderungen. Der folgende Code aktiviert CORS für die gesamte App mit dem angegebenen Ursprung:

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

    readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";

    public IConfiguration Configuration { get; }

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

        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    }

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

        app.UseCors(MyAllowSpecificOrigins); 

        app.UseHttpsRedirection();
        app.UseMvc();
    }
}

Der vorangehende Code:

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

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

    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}

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

Die CorsPolicyBuilder -Methode kann Methoden verketten, wie im folgenden Code gezeigt:

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

    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}

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

Der folgende Code wendet CORS-Richtlinien über CORS-Middleware auf alle Apps-Endpunkte an:

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

    app.UseCors();

    app.UseHttpsRedirection();
    app.UseMvc();
}

Hinweis: UseCors muss vor aufgerufen UseMvc werden.

Weitere Informationen finden Sie unter Aktivieren von CORS in Razor Pages, Controllern und Aktionsmethoden zum Anwenden von CORS-Richtlinien auf Seiten-/Controller-/Aktionsebene.

Anweisungen zum Testen von Code, der dem vorherigen Code ähnelt, finden Sie unter Testen von CORS.

Aktivieren von CORS mit Attributen

Das [ EnableCors-Attribut ] stellt eine Alternative zur globalen Anwendung von CORS dar. Das [EnableCors] -Attribut aktiviert CORS für ausgewählte Und nicht für alle Endpunkte.

Verwenden [EnableCors] Sie , um die Standardrichtlinie und eine Richtlinie [EnableCors("{Policy String}")] anzugeben.

Das [EnableCors] -Attribut kann auf:

  • Razor Seite PageModel
  • Controller
  • Controlleraktionsmethode

Sie können mit dem -Attribut verschiedene Richtlinien auf controller/page-model/action [EnableCors] anwenden. Wenn das [EnableCors] Attribut auf eine Controller-/Seitenmodell-/Aktionsmethode angewendet wird und CORS in Middleware aktiviert ist, werden beide Richtlinien angewendet. Es wird empfohlen, richtlinien nicht zu kombinieren. Verwenden Sie das Attribut oder die [EnableCors] Middleware, nicht beide. Definieren Sie bei Verwendung von [EnableCors] keine Standardrichtlinie.

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]        // Default policy.
    [HttpGet("{id}")]
    public ActionResult<string> Get(int id)
    {
        switch (id)
        {
            case 1:
                return "green widget";
            case 2:
                return "red widget";
            default:
                return NotFound();
        }
    }
}

Der folgende Code erstellt eine CORS-Standardrichtlinie und eine Richtlinie mit dem Namen "AnotherPolicy" :

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

    public IConfiguration Configuration { get; }

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

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

        });

        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    }

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

        app.UseHttpsRedirection();
        app.UseMvc();
    }
}

Deaktivieren von CORS

Das [ ] DisableCors-Attribut deaktiviert CORS für controller/page-model/action.

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 hilfreich 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 stellen kann.

Hinweis

Die Angabe AllowAnyOrigin von und ist eine AllowCredentials unsichere Konfiguration und kann zu einer websiteübergreifenden Anforderungsfälschung führen. Geben Sie für eine sichere App eine genaue Liste der Ursprünge an, wenn der Client sich selbst für den Zugriff auf Serverressourcen autorisieren muss.

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

SetIsOriginAllowedToAllowWildcardSubdomains: Legt die -Eigenschaft der Richtlinie auf eine Funktion fest, mit der Ursprünge mit einer konfigurierten Platzhalterdomäne übereinstimmen können, wenn bewertet wird, ob der IsOriginAllowed Ursprung zulässig ist.

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

Festlegen der zulässigen HTTP-Methoden

AllowAnyMethod:

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

Festlegen der zulässigen Anforderungsheader

Um das Senden bestimmter Header in einer CORS-Anforderung zu ermöglichen, die als Author Request-Header bezeichnet wird, rufen Sie auf, und WithHeaders geben Sie die zulässigen Header an:

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

Um alle Anforderungsheader des Autors zu ermöglichen, rufen Sie AllowAnyHeader auf:

options.AddPolicy("AllowAllHeaders",
    builder =>
    {
        builder.WithOrigins("http://example.com")
               .AllowAnyHeader();
    });

Diese Einstellung wirkt sich auf Preflightanforderungen und den Header Access-Control-Request-Headers aus. Weitere Informationen finden Sie im Abschnitt Preflightanforderungen.

Die CORS-Middleware lässt immer zu, dass vier Header in gesendet werden, unabhängig von den werten, die Access-Control-Request-Headers in CorsPolicy.Headers konfiguriert sind. Diese Liste von Headern enthält Folgendes:

  • Accept
  • Accept-Language
  • Content-Language
  • Origin

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

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

CORS-Middleware reagiert erfolgreich auf eine Preflightanforderung mit dem folgenden Anforderungsheader, da Content-Language immer zulässig ist:

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

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): Simple Response Header.

Die standardmäßig verfügbaren Antwortheader sind:

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

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

options.AddPolicy("ExposeResponseHeaders",
    builder =>
    {
        builder.WithOrigins("http://example.com")
               .WithExposedHeaders("x-custom-header");
    });

Anmeldeinformationen in ursprungsübergreifenden Anforderungen

Anmeldeinformationen erfordern eine besondere Behandlung in einer CORS-Anforderung. Standardmäßig sendet der Browser keine Anmeldeinformationen mit einer ursprungsübergreifenden Anforderung. Zu den Anmeldeinformationen gehören cookie s- und HTTP-Authentifizierungsschemas. Um Anmeldeinformationen mit einer ursprungsübergreifenden Anforderung zu senden, muss der Client XMLHttpRequest.withCredentials auf true festlegen.

Direkte XMLHttpRequest Verwendung:

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

Verwenden von jQuery:

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

Verwenden der Fetch-API:

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

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

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

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

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

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

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

Preflightanforderungen

Bei einigen CORS-Anforderungen sendet der Browser eine zusätzliche Anforderung, bevor die eigentliche Anforderung gestellt wird. Diese Anforderung wird als Preflightanforderung bezeichnet. Der Browser kann die Preflightanforderung überspringen, wenn die folgenden Bedingungen erfüllt sind:

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

Die Regel für Anforderungsheader, die für die Clientanforderung festgelegt werden, gilt für Header, die die App durch Aufrufen von setRequestHeader für das -Objekt XMLHttpRequest festgelegt hat. Die CORS-Spezifikation ruft diese Header author request headers auf. Die Regel gilt nicht für Header, die der Browser festlegen kann, z. B. User-Agent Host , oder Content-Length .

Im Folgenden finden Sie ein Beispiel für eine Preflightanforderung:

OPTIONS https://myservice.azurewebsites.net/api/test HTTP/1.1
Accept: */*
Origin: https://myclient.azurewebsites.net
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: accept, x-my-custom-header
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)
Host: myservice.azurewebsites.net
Content-Length: 0

Die Pre-Flight-Anforderung verwendet die HTTP OPTIONS-Methode. Sie enthält zwei spezielle Header:

  • Access-Control-Request-Method: Die HTTP-Methode, die für die tatsächliche Anforderung verwendet wird.
  • Access-Control-Request-Headers: Eine Liste von Anforderungsheadern, die die App für die tatsächliche Anforderung fest legt. Wie bereits erwähnt, enthält dies keine Header, die der Browser fest legt, z. User-Agent B. .

Wenn CORS mit der entsprechenden Richtlinie aktiviert ist, reagiert ASP.NET Core in der Regel automatisch auf CORS-Preflightanforderungen. Informationen zu Preflightanforderungen finden Sie unter [HttpOptions]-Attribut.

Eine CORS-Preflightanforderung kann einen -Header enthalten, der dem Server die Header angibt, die Access-Control-Request-Headers mit der tatsächlichen Anforderung gesendet werden.

Um bestimmte Header zu ermöglichen, rufen Sie WithHeaders auf:

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

Um alle Anforderungsheader des Autors zu ermöglichen, rufen Sie AllowAnyHeader auf:

options.AddPolicy("AllowAllHeaders",
    builder =>
    {
        builder.WithOrigins("http://example.com")
               .AllowAnyHeader();
    });

Browser sind bei der Festlegung von nicht vollständig Access-Control-Request-Headers konsistent. Wenn Sie Header auf andere Als "*" festlegen (oder AllowAnyHeader verwenden), sollten Sie mindestens Accept , und sowie alle Content-Type Origin benutzerdefinierten Header einschließen, die Sie unterstützen möchten.

Es folgt eine Beispielantwort auf die Preflightanforderung (vorausgesetzt, der Server lässt die Anforderung zu):

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Length: 0
Access-Control-Allow-Origin: https://myclient.azurewebsites.net
Access-Control-Allow-Headers: x-my-custom-header
Access-Control-Allow-Methods: PUT
Date: Wed, 20 May 2015 06:33:22 GMT

Die Antwort enthält einen Access-Control-Allow-Methods Header, der die zulässigen Methoden und optional einen Header Access-Control-Allow-Headers auflistet, der die zulässigen Header auflistet. Wenn die Preflightanforderung erfolgreich ist, sendet der Browser die tatsächliche Anforderung.

Wenn die Preflightanforderung abgelehnt wird, gibt die App eine 200 OK-Antwort zurück, sendet die CORS-Header jedoch nicht zurück. Daher versucht der Browser nicht, die ursprungsübergreifende Anforderung zu verwenden.

Festlegen der Ablaufzeit des Preflights

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

options.AddPolicy("SetPreflightExpiration",
    builder =>
    {
        builder.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 es einem Server ermöglicht, die Richtlinie desselben Ursprungs zu lockern.
    • Ein böswilliger Akteur könnte z. B. Prevent Cross-Site Scripting (XSS) für Ihre Website verwenden und eine websiteübergreifende Anforderung an seine CORS-fähige Website ausführen, um Informationen zu stehlen.
  • Ihre API ist nicht sicherer, indem SIE CORS zulässt.
    • Cors kann vom Client (Browser) erzwungen werden. Der Server führt die Anforderung aus und gibt die Antwort zurück. Der Client gibt einen Fehler zurück und blockiert die Antwort. Beispielsweise zeigt eines der folgenden Tools die Serverantwort an:
  • Es ist eine Möglichkeit für einen Server, Browsern das Ausführen einer ursprungsübergreifenden XHR- oder Fetch-API-Anforderung zu erlauben, die andernfalls nicht zulässig wäre.
    • Browser (ohne CORS) können keine ursprungsübergreifenden Anforderungen senden. Vor CORS wurde JSONP verwendet, um diese Einschränkung zu umgehen. JSONP verwendet nicht XHR, sondern 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 automatisch für ursprungsübergreifende Anforderungen fest. Benutzerdefinierter JavaScript-Code ist nicht erforderlich, um CORS zu aktivieren.

Im Folgenden finden Sie ein Beispiel für eine ursprungsübergreifende Anforderung. Der Origin Header stellt die Domäne der Website zur Verfügung, von der die Anforderung gestellt wird. Der Origin Header ist erforderlich und muss sich vom Host unterscheiden.

GET https://myservice.azurewebsites.net/api/test HTTP/1.1
Referer: https://myclient.azurewebsites.net/
Accept: */*
Accept-Language: en-US
Origin: https://myclient.azurewebsites.net
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)
Host: myservice.azurewebsites.net

Wenn der Server die Anforderung zulässt, legt er den Access-Control-Allow-Origin Header in der Antwort fest. Der Wert dieses Headers entspricht entweder dem Header der Anforderung oder ist der Platzhalterwert, was bedeutet, dass Origin "*" jeder Ursprung zulässig ist:

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: text/plain; charset=utf-8
Access-Control-Allow-Origin: https://myclient.azurewebsites.net
Date: Wed, 20 May 2015 06:27:30 GMT
Content-Length: 12

Test message

Wenn die Antwort den Header nicht Access-Control-Allow-Origin enthält, schlägt die ursprungsübergreifende Anforderung fehl. Insbesondere der Browser lehnt die Anforderung ab. Auch wenn der Server eine erfolgreiche Antwort zurückgibt, macht der Browser die Antwort nicht für die Client-App verfügbar.

Testen von CORS

So testen Sie CORS:

  1. Erstellen Sie ein API-Projekt. Alternativ können Sie das Beispiel herunterladen.
  2. Aktivieren Sie CORS mit einem der Ansätze in diesem Dokument. Beispiel:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseHsts();
    }

    // Shows UseCors with CorsPolicyBuilder.
    app.UseCors(builder =>
    {
        builder.WithOrigins("http://example.com",
                            "http://www.contoso.com",
                            "https://localhost:44375",
                            "https://localhost:5001");
    });

    app.UseHttpsRedirection();
    app.UseMvc();
}

Warnung

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

  1. Erstellen Sie ein Web-App-Projekt ( Razor Pages oder MVC). Im Beispiel werden Razor Pages verwendet. Sie können die Web-App in derselben Projektmappe wie das API-Projekt erstellen.
  2. Fügen Sie der Datei Index.cshtml den folgenden hervorgehobenen Code hinzu:
@page
@model IndexModel
@{
    ViewData["Title"] = "Home page";
}

<div class="text-center">
    <h1 class="display-4">CORS Test</h1>
</div>

<div>
    <input type="button" value="Test" 
           onclick="requestVal('https://<web app>.azurewebsites.net/api/values')" />
    <span id='result'></span>
</div>

<script>
    function requestVal(uri) {
        const resultSpan = document.getElementById('result');

        fetch(uri)
            .then(response => response.json())
            .then(data => resultSpan.innerText = data)
            .catch(error => resultSpan.innerText = 'See F12 Console for error');
    }
</script>
  1. Ersetzen Sie im vorangehenden Code url: 'https://<web app>.azurewebsites.net/api/values/1', durch die URL zur bereitgestellten App.

  2. Stellen Sie das API-Projekt bereit. Stellen Sie beispielsweise in Azure bereit.

  3. Führen Sie die Razor Pages- oder MVC-App auf dem Desktop aus, und klicken Sie auf die Schaltfläche Testen. Verwenden Sie die F12-Tools, um Fehlermeldungen zu überprüfen.

  4. Entfernen Sie den localhost-Ursprung aus , WithOrigins und stellen Sie die App bereit. Alternativ können Sie die Client-App mit einem anderen Port ausführen. Führen Sie beispielsweise über Visual Studio aus.

  5. Testen Sie mit der Client-App. CORS-Fehler geben einen Fehler zurück, aber die Fehlermeldung ist für JavaScript nicht verfügbar. Verwenden Sie die Registerkarte Konsole in den F12-Tools, um den Fehler anzuzeigen. Je nach Browser erhalten Sie einen Fehler (in der F12-Toolskonsole) ähnlich dem folgenden:

    • Verwenden von Microsoft Edge:

      SEC7120: [CORS] Der Ursprung https://localhost:44375 wurde https://localhost:44375 im Access-Control-Allow-Origin-Antwortheader für die ursprungsübergreifende Ressource unter nicht gefunden. https://webapi.azurewebsites.net/api/values/1

    • Verwenden von Chrome:

      Der Zugriff auf XMLHttpRequest at from origin wurde durch die CORS-Richtlinie blockiert: Für die angeforderte Ressource ist kein https://webapi.azurewebsites.net/api/values/1 https://localhost:44375 "Access-Control-Allow-Origin"-Header vorhanden.

CORS-fähige Endpunkte können mit einem Tool wie Fiddler oder Postman getestet werden. Wenn Sie ein Tool verwenden, muss sich der Ursprung der durch den Header angegebenen Anforderung von dem Host unterscheiden, Origin der die Anforderung empfängt. Wenn die Anforderung nicht ursprungsübergreifend ist, basierend auf dem Wert des Origin Headers:

  • Es ist nicht notwendig, dass CORS-Middleware die Anforderung verarbeiten kann.
  • CORS-Header werden in der Antwort nicht zurückgegeben.

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. Um dieses Szenario zu unterstützen, muss das IIS-CORS-Modul für die App installiert und konfiguriert werden.

Zusätzliche Ressourcen