Włączanie żądań między źródłami (CORS) w usłudze ASP.NET Core

Uwaga

Nie jest to najnowsza wersja tego artykułu. Aby zapoznać się z bieżącą wersją, zobacz ASP.NET Core 8.0 tego artykułu.

Autorzy: Rick Anderson i Kirk Larkin

W tym artykule pokazano, jak rozszerzenie Cross-O rigin Resource Sharing (CORS) jest włączone w aplikacji ASP.NET Core.

Zabezpieczenia przeglądarki uniemożliwiają stronie internetowej wykonywanie żądań do innej domeny niż ta, która obsłużyła stronę internetową. To ograniczenie określa się jako zasadę tego samego źródła. Zasada tego samego źródła uniemożliwia złośliwym witrynom odczytywanie poufnych danych z innej witryny. Czasami możesz zezwolić innym witrynom na wykonywanie żądań w aplikacji o innym źródle. Aby uzyskać więcej informacji, zobacz artykuł Mozilla CORS.

Współużytkowanie zasobów między źródłami (CORS):

  • Jest standardem W3C, który umożliwia serwerowi złagodzenie zasad tego samego źródła.
  • Nie jest funkcją zabezpieczeń, mechanizm CORS zrelaksuje zabezpieczenia. Interfejs API nie jest bezpieczniejszy, zezwalając na mechanizm CORS. Aby uzyskać więcej informacji, zobacz Jak działa mechanizm CORS.
  • Zezwala serwerowi na jawne zezwalanie na niektóre żądania między źródłami podczas odrzucania innych.
  • Jest bezpieczniejszy i bardziej elastyczny niż wcześniejsze techniki, takie jak JSONP.

Wyświetl lub pobierz przykładowy kod (jak pobrać)

To samo źródło

Dwa adresy URL mają to samo źródło, jeśli mają identyczne schematy, hosty i porty (RFC 6454).

Te dwa adresy URL mają to samo źródło:

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

Te adresy URL mają inne źródła niż poprzednie dwa adresy URL:

  • https://example.net: Inna domena
  • https://www.example.com/foo.html: Inna poddomena
  • http://example.com/foo.html: Inny schemat
  • https://example.com:9000/foo.html: Inny port

Włączanie mechanizmu CORS

Istnieją trzy sposoby włączania mechanizmu CORS:

Użycie atrybutu [EnableCors] z nazwanymi zasadami zapewnia najlepszą kontrolę w ograniczaniu punktów końcowych obsługujących mechanizm CORS.

Ostrzeżenie

UseCors musi być wywoływana w odpowiedniej kolejności. Aby uzyskać więcej informacji, zobacz Kolejność oprogramowania pośredniczącego. Na przykład UseCors należy wywołać metodę przed UseResponseCaching użyciem polecenia UseResponseCaching.

Każde podejście zostało szczegółowo opisane w poniższych sekcjach.

MECHANIZM CORS z nazwanymi zasadami i oprogramowaniem pośredniczącym

Oprogramowanie pośredniczące CORS obsługuje żądania między źródłami. Poniższy kod stosuje zasady CORS do wszystkich punktów końcowych aplikacji z określonymi źródłami:

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

Powyższy kod ma następujące działanie:

  • Ustawia nazwę zasad na _myAllowSpecificOrigins. Nazwa zasad jest dowolna.
  • Wywołuje metodę UseCors rozszerzenia i określa _myAllowSpecificOrigins zasady CORS. UseCors dodaje oprogramowanie pośredniczące CORS. Wywołanie UseCors musi zostać umieszczone po UseRoutingmetodzie , ale przed UseAuthorization. Aby uzyskać więcej informacji, zobacz Kolejność oprogramowania pośredniczącego.
  • Wywołania AddCors za pomocą wyrażenia lambda. Lambda przyjmuje CorsPolicyBuilder obiekt. Opcje konfiguracji, takie jak WithOrigins, zostały opisane w dalszej części tego artykułu.
  • _myAllowSpecificOrigins Włącza zasady CORS dla wszystkich punktów końcowych kontrolera. Zobacz Routing punktów końcowych, aby zastosować zasady CORS do określonych punktów końcowych.
  • W przypadku korzystania z oprogramowania pośredniczącego Buforowanie odpowiedzi wywołaj metodę przed UseResponseCaching.UseCors

W przypadku routingu punktów końcowych oprogramowanie pośredniczące CORS musi być skonfigurowane do wykonywania między wywołaniami do UseRouting i UseEndpoints.

Zobacz Testowanie mechanizmu CORS , aby uzyskać instrukcje dotyczące testowania kodu podobnego do poprzedniego kodu.

Wywołanie AddCors metody dodaje usługi CORS do kontenera usługi aplikacji:

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

Aby uzyskać więcej informacji, zobacz opcje zasad MECHANIZMU CORS w tym dokumencie.

CorsPolicyBuilder Metody można połączyć łańcuchem, jak pokazano w poniższym kodzie:

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

Uwaga: określony adres URL nie może zawierać ukośnika końcowego (/). Jeśli adres URL zakończy się ciągiem /, porównanie zwróci wartość false i nie zostanie zwrócony żaden nagłówek.

Kolejność składników UseCors i UseStaticFiles

UseStaticFiles Zazwyczaj jest wywoływana przed UseCors. Aplikacje korzystające z języka JavaScript do pobierania plików statycznych między witrynami muszą wywoływać przed UseStaticFiles.UseCors

MECHANIZM CORS z domyślnymi zasadami i oprogramowaniem pośredniczącym

Poniższy wyróżniony kod włącza domyślne zasady MECHANIZMU CORS:

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

Powyższy kod stosuje domyślne zasady CORS do wszystkich punktów końcowych kontrolera.

Włączanie mechanizmu Cors z routingiem punktów końcowych

W przypadku routingu punktu końcowego mechanizm CORS można włączyć dla poszczególnych punktów końcowych przy użyciu RequireCors zestawu metod rozszerzeń:

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

Powyższy kod:

  • app.UseCors włącza oprogramowanie pośredniczące CORS. Ponieważ nie skonfigurowano zasad domyślnych, app.UseCors() sam nie włącza mechanizmu CORS.
  • Punkty /echo końcowe kontrolera i zezwalają na żądania między źródłami przy użyciu określonych zasad.
  • Punkty /echo2 końcowe stron i Razor nie zezwalają na żądania między źródłami, ponieważ nie określono żadnych domyślnych zasad.

Atrybut [DisableCors] nie wyłącza mechanizmu CORS, który został włączony przez routing punktu końcowego za pomocą polecenia RequireCors.

Zobacz Testowanie mechanizmu CORS za pomocą atrybutu [EnableCors] i metody RequireCors, aby uzyskać instrukcje dotyczące testowania kodu podobnego do poprzedniego.

Włączanie mechanizmu CORS z atrybutami

Włączenie mechanizmu CORS za pomocą atrybutu [EnableCors] i zastosowanie nazwanych zasad tylko do tych punktów końcowych, które wymagają mechanizmu CORS, zapewnia najlepszą kontrolę.

Atrybut [EnableCors] zapewnia alternatywę dla stosowania mechanizmu CORS globalnie. Atrybut [EnableCors] umożliwia mechanizm CORS dla wybranych punktów końcowych, a nie wszystkich punktów końcowych:

  • [EnableCors] określa zasady domyślne.
  • [EnableCors("{Policy String}")] określa nazwane zasady.

Atrybut [EnableCors] można zastosować do:

  • Razor Strona PageModel
  • Kontroler
  • Metoda akcji kontrolera

Różne zasady można stosować do kontrolerów, modeli stron lub metod akcji za pomocą atrybutu [EnableCors] . [EnableCors] Gdy atrybut jest stosowany do kontrolera, modelu strony lub metody akcji, a mechanizm CORS jest włączony w programie pośredniczącym, stosowane są obie zasady. Zalecamy łączenie zasad. Użyj przycisku [EnableCors]atrybutu lub oprogramowania pośredniczącego, a nie obu w tej samej aplikacji.

Poniższy kod stosuje inne zasady do każdej metody:

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

Poniższy kod tworzy dwie zasady CORS:

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

Aby uzyskać najlepszą kontrolę nad ograniczaniem żądań CORS:

  • Użyj [EnableCors("MyPolicy")] z nazwanymi zasadami.
  • Nie należy definiować zasad domyślnych.
  • Nie używaj routingu punktów końcowych.

Kod w następnej sekcji spełnia poprzednią listę.

Zobacz Testowanie mechanizmu CORS , aby uzyskać instrukcje dotyczące testowania kodu podobnego do poprzedniego kodu.

Wyłączanie mechanizmu CORS

Atrybut [DisableCors] nie wyłącza mechanizmu CORS, który został włączony przez routing punktu końcowego.

Poniższy kod definiuje zasady "MyPolicy"MECHANIZMU CORS:

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

Poniższy kod wyłącza mechanizm CORS dla GetValues2 akcji:

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

}

Powyższy kod ma następujące działanie:

  • Nie włącza mechanizmu CORS z routingiem punktów końcowych.
  • Nie definiuje domyślnych zasad CORS.
  • Używa funkcji [EnableCors("MyPolicy")] w celu włączenia "MyPolicy" zasad CORS dla kontrolera.
  • Wyłącza mechanizm CORS dla GetValues2 metody .

Aby uzyskać instrukcje dotyczące testowania poprzedniego kodu, zobacz Testowanie mechanizmu CORS .

Opcje zasad MECHANIZMU CORS

W tej sekcji opisano różne opcje, które można ustawić w zasadach MECHANIZMU CORS:

AddPolicy jest wywoływana w pliku Program.cs. W przypadku niektórych opcji warto zapoznać się z sekcją Jak działa mechanizm CORS.

Ustawianie dozwolonych źródeł

AllowAnyOrigin: zezwala na żądania CORS ze wszystkich źródeł przy użyciu dowolnego schematu (http lub https). AllowAnyOrigin jest niezabezpieczona, ponieważ każda witryna internetowa może wysyłać żądania między źródłami do aplikacji.

Uwaga

Określanie AllowAnyOrigin i AllowCredentials jest niezabezpieczoną konfiguracją i może spowodować fałszerzowanie żądań między witrynami. Usługa CORS zwraca nieprawidłową odpowiedź CORS, gdy aplikacja jest skonfigurowana przy użyciu obu metod.

AllowAnyOrigin dotyczy żądań wstępnych i nagłówka Access-Control-Allow-Origin . Aby uzyskać więcej informacji, zobacz sekcję Wstępne żądania .

SetIsOriginAllowedToAllowWildcardSubdomains: Ustawia IsOriginAllowed właściwość zasad jako funkcję, która umożliwia źródłom dopasowanie skonfigurowanej domeny wieloznacznych podczas oceny, czy źródło jest dozwolone.

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

Ustawianie dozwolonych metod HTTP

AllowAnyMethod:

  • Zezwala na dowolną metodę HTTP:
  • Wpływa na żądania wstępne i Access-Control-Allow-Methods nagłówek. Aby uzyskać więcej informacji, zobacz sekcję Wstępne żądania .

Ustawianie dozwolonych nagłówków żądań

Aby zezwolić na wysyłanie określonych nagłówków w żądaniu CORS, nazywanym nagłówkami żądań autora, wywołaj WithHeaders i określ dozwolone nagłówki:

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

Aby zezwolić na wszystkie nagłówki żądań autora, wywołaj metodę AllowAnyHeader:

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 dotyczy żądań wstępnych i nagłówka Access-Control-Request-Headers . Aby uzyskać więcej informacji, zobacz sekcję Wstępne żądania .

Zasady oprogramowania pośredniczącego CORS są zgodne z określonymi nagłówkami określonymi przez WithHeaders usługę jest możliwe tylko wtedy, gdy nagłówki wysyłane w Access-Control-Request-Headers formacie dokładnie odpowiadają nagłówkom określonym w elemencie WithHeaders.

Rozważmy na przykład aplikację skonfigurowaną w następujący sposób:

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

Oprogramowanie pośredniczące CORS odrzuca żądanie wstępne z następującym nagłówkiem żądania, ponieważ Content-Language (HeaderNames.ContentLanguage) nie ma na liście :WithHeaders

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

Aplikacja zwraca odpowiedź 200 OK , ale nie wysyła nagłówków CORS z powrotem. W związku z tym przeglądarka nie podejmuje próby żądania między źródłami.

Ustawianie uwidocznionych nagłówków odpowiedzi

Domyślnie przeglądarka nie ujawnia wszystkich nagłówków odpowiedzi aplikacji. Aby uzyskać więcej informacji, zobacz Udostępnianie zasobów między źródłami W3C (terminologia): prosty nagłówek odpowiedzi.

Nagłówki odpowiedzi, które są dostępne domyślnie, to:

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

Specyfikacja MECHANIZMU CORS wywołuje te nagłówki prostych nagłówków odpowiedzi. Aby udostępnić inne nagłówki aplikacji, wywołaj metodę WithExposedHeaders:

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

Poświadczenia w żądaniach między źródłami

Poświadczenia wymagają specjalnej obsługi w żądaniu CORS. Domyślnie przeglądarka nie wysyła poświadczeń z żądaniem między źródłami. Poświadczenia obejmują cookieschematy uwierzytelniania s i HTTP. Aby wysyłać poświadczenia z żądaniem między źródłami, klient musi ustawić wartość XMLHttpRequest.withCredentialstrue.

Bezpośrednie użycie XMLHttpRequest :

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

Korzystanie z zapytania jQuery:

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

Korzystanie z interfejsu API pobierania:

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

Serwer musi zezwalać na poświadczenia. Aby zezwolić na poświadczenia między źródłami, wywołaj metodę AllowCredentials:

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

Odpowiedź HTTP zawiera Access-Control-Allow-Credentials nagłówek, który informuje przeglądarkę, że serwer zezwala na poświadczenia dla żądania między źródłami.

Jeśli przeglądarka wysyła poświadczenia, ale odpowiedź nie zawiera prawidłowego Access-Control-Allow-Credentials nagłówka, przeglądarka nie uwidacznia odpowiedzi na aplikację, a żądanie między źródłami zakończy się niepowodzeniem.

Zezwolenie na poświadczenia między źródłami jest zagrożeniem bezpieczeństwa. Witryna internetowa w innej domenie może wysyłać poświadczenia zalogowanego użytkownika do aplikacji w imieniu użytkownika bez wiedzy użytkownika.

Specyfikacja MECHANIZMU CORS stwierdza również, że ustawienie wartości origins na "*" (wszystkie źródła) jest nieprawidłowe, jeśli Access-Control-Allow-Credentials nagłówek jest obecny.

Żądania wstępne

W przypadku niektórych żądań CORS przeglądarka wysyła dodatkowe żądanie OPTIONS przed wysłaniem rzeczywistego żądania. To żądanie jest nazywane żądaniem wstępnym. Przeglądarka może pominąć żądanie wstępne, jeśli spełnione są wszystkie następujące warunki:

  • Metoda żądania to GET, HEAD lub POST.
  • Aplikacja nie ustawia nagłówków żądań innych niż Accept, , Accept-Language, Content-Language, Content-Typelub Last-Event-ID.
  • Nagłówek Content-Type , jeśli jest ustawiony, ma jedną z następujących wartości:
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

Reguła nagłówków żądań ustawiona dla żądania klienta ma zastosowanie do nagłówków ustawianych przez aplikację przez wywołanie setRequestHeaderXMLHttpRequest obiektu. Specyfikacja MECHANIZMU CORS wywołuje te nagłówki żądań autora. Reguła nie ma zastosowania do nagłówków, które można ustawić w przeglądarce, takich jak User-Agent, Hostlub Content-Length.

Poniżej przedstawiono przykładową odpowiedź podobną do żądania wstępnego wykonanego z przycisku [Put test] w sekcji Test CORS tego dokumentu.

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

Żądanie wstępne używa metody HTTP OPTIONS . Może zawierać następujące nagłówki:

Jeśli żądanie wstępne zostanie odrzucone, aplikacja zwróci 200 OK odpowiedź, ale nie ustawi nagłówków CORS. W związku z tym przeglądarka nie podejmuje próby żądania między źródłami. Aby zapoznać się z przykładem odmowy żądania wstępnego, zobacz sekcję Test CORS tego dokumentu.

Za pomocą narzędzi F12 aplikacja konsolowa wyświetla błąd podobny do jednego z następujących, w zależności od przeglądarki:

  • Firefox: Żądanie między źródłami zablokowane: Te same zasady pochodzenia nie zezwalają na odczytywanie zasobu zdalnego pod adresem https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5. (Przyczyna: żądanie CORS nie powiodło się). Dowiedz się więcej
  • Oparty na chromium: dostęp do pobierania z źródła "https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5https://cors3.azurewebsites.net" został zablokowany przez zasady CORS: Odpowiedź na żądanie wstępne nie przekazuje kontroli dostępu: Brak nagłówka "Access-Control-Allow-Origin" dla żądanego zasobu. Jeśli nieprzezroczysta odpowiedź spełnia Twoje potrzeby, ustaw tryb żądania na wartość "no-cors", aby pobrać zasób z wyłączonym mechanizmem CORS.

Aby zezwolić na określone nagłówki, wywołaj metodę WithHeaders:

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

Aby zezwolić na wszystkie nagłówki żądań autora, wywołaj metodę AllowAnyHeader:

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

Przeglądarki nie są spójne w sposobie ustawiania .Access-Control-Request-Headers Jeśli:

  • Nagłówki są ustawione na inne niż "*"
  • AllowAnyHeader jest wywoływany: uwzględnij co najmniej Accept, Content-Typei Origin, oraz wszelkie nagłówki niestandardowe, które mają być obsługiwane.

Kod automatycznego żądania wstępnego

Po zastosowaniu zasad CORS:

  • Globalnie przez wywołanie metody app.UseCors w pliku Program.cs.
  • Za pomocą atrybutu [EnableCors] .

ASP.NET Core odpowiada na żądanie OPCJE wstępne.

W sekcji Test CORS tego dokumentu pokazano to zachowanie.

[HttpOptions] atrybut dla żądań wstępnych

Gdy mechanizm CORS jest włączony z odpowiednimi zasadami, ASP.NET Core zwykle odpowiada na żądania wstępne CORS.

Poniższy kod używa atrybutu [HttpOptions] do tworzenia punktów końcowych dla żądań OPTIONS:

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

Aby uzyskać instrukcje dotyczące testowania poprzedniego kodu, zobacz Testowanie mechanizmu CORS za pomocą atrybutu [EnableCors] i metody RequireCors.

Ustawianie czasu wygaśnięcia przedlotu

Nagłówek Access-Control-Max-Age określa, jak długo można buforować odpowiedź na żądanie wstępne. Aby ustawić ten nagłówek, wywołaj metodę SetPreflightMaxAge:

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

Włączanie mechanizmu CORS w punkcie końcowym

Jak działa mechanizm CORS

W tej sekcji opisano, co dzieje się w żądaniu CORS na poziomie komunikatów HTTP.

  • MECHANIZM CORS nie jest funkcją zabezpieczeń. CORS to standard W3C, który umożliwia serwerowi złagodzenie zasad tego samego źródła.
    • Na przykład złośliwy aktor może użyć skryptów między witrynami (XSS) w witrynie i wykonać żądanie obejmujące wiele witryn do witryny obsługującej mechanizm CORS w celu kradzieży informacji.
  • Interfejs API nie jest bezpieczniejszy, zezwalając na mechanizm CORS.
    • Do klienta (przeglądarki) należy wymuszenie mechanizmu CORS. Serwer wykonuje żądanie i zwraca odpowiedź— klient zwraca błąd i blokuje odpowiedź. Na przykład dowolne z następujących narzędzi wyświetli odpowiedź serwera:
  • Jest to sposób na serwer, aby umożliwić przeglądarkom wykonywanie między źródłami żądania XHR lub Fetch API , które w przeciwnym razie byłoby zabronione.
    • Przeglądarki bez mechanizmu CORS nie mogą wykonywać żądań między źródłami. Przed corsem JSONP został użyty do obejścia tego ograniczenia. JSONP nie używa XHR, używa tagu <script> do odbierania odpowiedzi. Skrypty mogą być ładowane między źródłami.

Specyfikacja MECHANIZMU CORS wprowadziła kilka nowych nagłówków HTTP, które umożliwiają żądania między źródłami. Jeśli przeglądarka obsługuje mechanizm CORS, automatycznie ustawia te nagłówki dla żądań między źródłami. Niestandardowy kod JavaScript nie jest wymagany do włączenia mechanizmu CORS.

Przycisk TEST PUT w wdrożonej próbce

Poniżej przedstawiono przykład żądania między źródłami z przycisku Test wartości do https://cors1.azurewebsites.net/api/values. Nagłówek Origin :

  • Udostępnia domenę lokacji wysyłającej żądanie.
  • Jest wymagany i musi być inny niż host.

Nagłówki ogólne

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

Nagłówki odpowiedzi

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

Nagłówki żądań

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 ...

W OPTIONS żądaniach serwer ustawia nagłówek NagłówkiAccess-Control-Allow-Origin: {allowed origin} odpowiedzi w odpowiedzi. Na przykład wdrożone przykładowe żądanie przycisku OPTIONS Usuń [EnableCors] zawiera następujące nagłówki:

Nagłówki ogólne

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

Nagłówki odpowiedzi

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

Nagłówki żądań

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

W poprzednich nagłówkach Odpowiedzi serwer ustawia nagłówek Access-Control-Allow-Origin w odpowiedzi. Wartość https://cors1.azurewebsites.net tego nagłówka odpowiada nagłówkowi Origin z żądania.

Jeśli AllowAnyOrigin parametr jest wywoływany, zwracana jest wartość z symbolem Access-Control-Allow-Origin: *wieloznacznymi. AllowAnyOrigin zezwala na dowolne źródło.

Jeśli odpowiedź nie zawiera nagłówka Access-Control-Allow-Origin , żądanie między źródłami zakończy się niepowodzeniem. W szczególności przeglądarka nie zezwala na żądanie. Nawet jeśli serwer zwróci pomyślną odpowiedź, przeglądarka nie udostępni odpowiedzi aplikacji klienckiej.

Przekierowanie HTTP do protokołu HTTPS powoduje ERR_INVALID_REDIRECT w żądaniu wstępnym CORS

Żądania do punktu końcowego przy użyciu protokołu HTTP, które są przekierowywane do protokołu HTTPS przez UseHttpsRedirection niepowodzenie z .ERR_INVALID_REDIRECT on the CORS preflight request

Projekty interfejsu API mogą odrzucać żądania HTTP, a nie przekierowywać UseHttpsRedirection żądania do protokołu HTTPS.

Mechanizm CORS w usługach IIS

Podczas wdrażania w usługach IIS mechanizm CORS musi działać przed uwierzytelnianiem systemu Windows, jeśli serwer nie jest skonfigurowany do zezwalania na dostęp anonimowy. Aby obsługiwać ten scenariusz, moduł CORS usług IIS musi zostać zainstalowany i skonfigurowany dla aplikacji.

Testowanie mechanizmu CORS

Przykładowy plik do pobrania zawiera kod do testowania mechanizmu CORS. Zobacz , jak pobrać. Przykład jest projektem interfejsu API z dodanymi stronami Razor :

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

Ostrzeżenie

WithOrigins("https://localhost:<port>");należy używać tylko do testowania przykładowej aplikacji podobnej do przykładowego kodu pobierania.

Poniżej przedstawiono ValuesController punkty końcowe do testowania:

[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 jest dostarczany przez pakiet NuGet Rick.Docs.Samples.RouteInfo i wyświetla informacje o trasie.

Przetestuj poprzedni przykładowy kod przy użyciu jednego z następujących metod:

  • Użyj wdrożonej przykładowej aplikacji pod adresem https://cors3.azurewebsites.net/. Nie ma potrzeby pobierania przykładu.
  • Uruchom przykład przy dotnet run użyciu domyślnego adresu URL .https://localhost:5001
  • Uruchom przykład z programu Visual Studio z portem ustawionym na 44398 jako adres URL https://localhost:44398.

Za pomocą przeglądarki z narzędziami F12:

  • Wybierz przycisk Wartości i przejrzyj nagłówki na karcie Sieć.

  • Wybierz przycisk TEST PUT. Zobacz Wyświetlanie żądań OPTIONS, aby uzyskać instrukcje dotyczące wyświetlania żądania OPTIONS. Test PUT tworzy dwa żądania, żądanie wstępne OPTIONS i żądanie PUT.

  • Wybierz przycisk, GetValues2 [DisableCors] aby wyzwolić nieudane żądanie CORS. Jak wspomniano w dokumencie, odpowiedź zwraca 200 powodzenia, ale żądanie CORS nie jest wykonywane. Wybierz kartę Konsola, aby wyświetlić błąd CORS. W zależności od przeglądarki zostanie wyświetlony błąd podobny do następującego:

    Dostęp do pobierania 'https://cors1.azurewebsites.net/api/values/GetValues2' z źródła 'https://cors3.azurewebsites.net' został zablokowany przez zasady CORS: w żądanym zasobie nie ma nagłówka "Access-Control-Allow-Origin". Jeśli nieprzezroczysta odpowiedź spełnia Twoje potrzeby, ustaw tryb żądania na wartość "no-cors", aby pobrać zasób z wyłączonym mechanizmem CORS.

Punkty końcowe z obsługą mechanizmu CORS można przetestować za pomocą narzędzia, takiego jak curl lub Fiddler. W przypadku korzystania z narzędzia źródło żądania określonego przez Origin nagłówek musi się różnić od hosta odbierającego żądanie. Jeśli żądanie nie jest źródłem krzyżowym na podstawie wartości nagłówka Origin :

  • Nie ma potrzeby przetwarzania żądania przez oprogramowanie pośredniczące CORS.
  • Nagłówki CORS nie są zwracane w odpowiedzi.

Następujące polecenie używa curl polecenia , aby wysłać żądanie OPTIONS z informacjami:

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

Testowanie mechanizmu CORS za pomocą atrybutu [EnableCors] i metody RequireCors

Rozważmy następujący kod, który używa routingu punktów końcowych w celu włączenia mechanizmu CORS dla poszczególnych punktów końcowych przy użyciu polecenia RequireCors:

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

Zwróć uwagę, że tylko /echo punkt końcowy używa elementu , RequireCors aby zezwolić na żądania między źródłami przy użyciu określonych zasad. Poniższe kontrolery włączają mechanizm CORS przy użyciu atrybutu [EnableCors].

Poniżej przedstawiono TodoItems1Controller punkty końcowe do testowania:

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

Przetestuj powyższy kod ze strony testowej wdrożonego przykładu.

Przyciski Usuń [EnableCors] i GET [EnableCors] kończą się powodzeniem, ponieważ punkty końcowe mają [EnableCors] żądania wstępne i odpowiadają na nie. Inne punkty końcowe kończą się niepowodzeniem. Przycisk GET kończy się niepowodzeniem, ponieważ skrypt JavaScript wysyła:

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

Poniższe informacje TodoItems2Controller zawierają podobne punkty końcowe, ale zawierają jawny kod, który odpowiada na żądania OPTIONS:

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

Przetestuj powyższy kod ze strony testowej wdrożonego przykładu. Z listy rozwijanej Kontroler wybierz pozycję Wstępne, a następnie pozycję Ustaw kontroler. Wszystkie wywołania CORS do punktów końcowych kończą się powodzeniem TodoItems2Controller .

Dodatkowe zasoby

Autorzy: Rick Anderson i Kirk Larkin

W tym artykule pokazano, jak włączyć mechanizm CORS w aplikacji ASP.NET Core.

Zabezpieczenia przeglądarki uniemożliwiają stronie internetowej wykonywanie żądań do innej domeny niż ta, która obsłużyła stronę internetową. To ograniczenie określa się jako zasadę tego samego źródła. Zasada tego samego źródła uniemożliwia złośliwym witrynom odczytywanie poufnych danych z innej witryny. Czasami możesz zezwolić innym witrynom na wykonywanie żądań w aplikacji o innym źródle. Aby uzyskać więcej informacji, zobacz artykuł Mozilla CORS.

Współużytkowanie zasobów między źródłami (CORS):

  • Jest standardem W3C, który umożliwia serwerowi złagodzenie zasad tego samego źródła.
  • Nie jest funkcją zabezpieczeń, mechanizm CORS zrelaksuje zabezpieczenia. Interfejs API nie jest bezpieczniejszy, zezwalając na mechanizm CORS. Aby uzyskać więcej informacji, zobacz Jak działa mechanizm CORS.
  • Zezwala serwerowi na jawne zezwalanie na niektóre żądania między źródłami podczas odrzucania innych.
  • Jest bezpieczniejszy i bardziej elastyczny niż wcześniejsze techniki, takie jak JSONP.

Wyświetl lub pobierz przykładowy kod (jak pobrać)

To samo źródło

Dwa adresy URL mają to samo źródło, jeśli mają identyczne schematy, hosty i porty (RFC 6454).

Te dwa adresy URL mają to samo źródło:

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

Te adresy URL mają inne źródła niż poprzednie dwa adresy URL:

  • https://example.net: Inna domena
  • https://www.example.com/foo.html: Inna poddomena
  • http://example.com/foo.html: Inny schemat
  • https://example.com:9000/foo.html: Inny port

Włączanie mechanizmu CORS

Istnieją trzy sposoby włączania mechanizmu CORS:

Użycie atrybutu [EnableCors] z nazwanymi zasadami zapewnia najlepszą kontrolę w ograniczaniu punktów końcowych obsługujących mechanizm CORS.

Ostrzeżenie

UseCors musi być wywoływana w odpowiedniej kolejności. Aby uzyskać więcej informacji, zobacz Kolejność oprogramowania pośredniczącego. Na przykład UseCors należy wywołać metodę przed UseResponseCaching użyciem polecenia UseResponseCaching.

Każde podejście zostało szczegółowo opisane w poniższych sekcjach.

MECHANIZM CORS z nazwanymi zasadami i oprogramowaniem pośredniczącym

Oprogramowanie pośredniczące CORS obsługuje żądania między źródłami. Poniższy kod stosuje zasady CORS do wszystkich punktów końcowych aplikacji z określonymi źródłami:

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

Powyższy kod ma następujące działanie:

  • Ustawia nazwę zasad na _myAllowSpecificOrigins. Nazwa zasad jest dowolna.
  • Wywołuje metodę UseCors rozszerzenia i określa _myAllowSpecificOrigins zasady CORS. UseCors dodaje oprogramowanie pośredniczące CORS. Wywołanie UseCors musi zostać umieszczone po UseRoutingmetodzie , ale przed UseAuthorization. Aby uzyskać więcej informacji, zobacz Kolejność oprogramowania pośredniczącego.
  • Wywołania AddCors za pomocą wyrażenia lambda. Lambda przyjmuje CorsPolicyBuilder obiekt. Opcje konfiguracji, takie jak WithOrigins, zostały opisane w dalszej części tego artykułu.
  • _myAllowSpecificOrigins Włącza zasady CORS dla wszystkich punktów końcowych kontrolera. Zobacz Routing punktów końcowych, aby zastosować zasady CORS do określonych punktów końcowych.
  • W przypadku korzystania z oprogramowania pośredniczącego Buforowanie odpowiedzi wywołaj metodę przed UseResponseCaching.UseCors

W przypadku routingu punktów końcowych oprogramowanie pośredniczące CORS musi być skonfigurowane do wykonywania między wywołaniami do UseRouting i UseEndpoints.

Zobacz Testowanie mechanizmu CORS , aby uzyskać instrukcje dotyczące testowania kodu podobnego do poprzedniego kodu.

Wywołanie AddCors metody dodaje usługi CORS do kontenera usługi aplikacji:

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

Aby uzyskać więcej informacji, zobacz opcje zasad MECHANIZMU CORS w tym dokumencie.

CorsPolicyBuilder Metody można połączyć łańcuchem, jak pokazano w poniższym kodzie:

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

Uwaga: określony adres URL nie może zawierać ukośnika końcowego (/). Jeśli adres URL zakończy się ciągiem /, porównanie zwróci wartość false i nie zostanie zwrócony żaden nagłówek.

Ostrzeżenie

UseCors należy umieścić po i UseRouting przed UseAuthorization. Ma to na celu zapewnienie, że nagłówki CORS znajdują się w odpowiedzi zarówno na wywołania autoryzowane, jak i nieautoryzowane.

Kolejność składników UseCors i UseStaticFiles

UseStaticFiles Zazwyczaj jest wywoływana przed UseCors. Aplikacje korzystające z języka JavaScript do pobierania plików statycznych między witrynami muszą wywoływać przed UseStaticFiles.UseCors

MECHANIZM CORS z domyślnymi zasadami i oprogramowaniem pośredniczącym

Poniższy wyróżniony kod włącza domyślne zasady MECHANIZMU CORS:

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

Powyższy kod stosuje domyślne zasady CORS do wszystkich punktów końcowych kontrolera.

Włączanie mechanizmu Cors z routingiem punktów końcowych

W przypadku routingu punktu końcowego mechanizm CORS można włączyć dla poszczególnych punktów końcowych przy użyciu RequireCors zestawu metod rozszerzeń:

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

Powyższy kod:

  • app.UseCors włącza oprogramowanie pośredniczące CORS. Ponieważ nie skonfigurowano zasad domyślnych, app.UseCors() sam nie włącza mechanizmu CORS.
  • Punkty /echo końcowe kontrolera i zezwalają na żądania między źródłami przy użyciu określonych zasad.
  • Punkty /echo2 końcowe stron i Razor nie zezwalają na żądania między źródłami, ponieważ nie określono żadnych domyślnych zasad.

Atrybut [DisableCors] nie wyłącza mechanizmu CORS, który został włączony przez routing punktu końcowego za pomocą polecenia RequireCors.

W ASP.NET Core 7.0 [EnableCors] atrybut musi przekazać parametr lub ostrzeżenie ASP0023 jest generowane na podstawie niejednoznacznego dopasowania na trasie. program ASP.NET Core 8.0 lub nowszy nie generuje ASP0023 ostrzeżenia.

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

Zobacz Testowanie mechanizmu CORS za pomocą atrybutu [EnableCors] i metody RequireCors, aby uzyskać instrukcje dotyczące testowania kodu podobnego do poprzedniego.

Włączanie mechanizmu CORS z atrybutami

Włączenie mechanizmu CORS za pomocą atrybutu [EnableCors] i zastosowanie nazwanych zasad tylko do tych punktów końcowych, które wymagają mechanizmu CORS, zapewnia najlepszą kontrolę.

Atrybut [EnableCors] zapewnia alternatywę dla stosowania mechanizmu CORS globalnie. Atrybut [EnableCors] umożliwia mechanizm CORS dla wybranych punktów końcowych, a nie wszystkich punktów końcowych:

  • [EnableCors] określa zasady domyślne.
  • [EnableCors("{Policy String}")] określa nazwane zasady.

Atrybut [EnableCors] można zastosować do:

  • Razor Strona PageModel
  • Kontroler
  • Metoda akcji kontrolera

Różne zasady można stosować do kontrolerów, modeli stron lub metod akcji za pomocą atrybutu [EnableCors] . [EnableCors] Gdy atrybut jest stosowany do kontrolera, modelu strony lub metody akcji, a mechanizm CORS jest włączony w programie pośredniczącym, stosowane są obie zasady. Zalecamy łączenie zasad. Użyj przycisku [EnableCors]atrybutu lub oprogramowania pośredniczącego, a nie obu w tej samej aplikacji.

Poniższy kod stosuje inne zasady do każdej metody:

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

Poniższy kod tworzy dwie zasady CORS:

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

Aby uzyskać najlepszą kontrolę nad ograniczaniem żądań CORS:

  • Użyj [EnableCors("MyPolicy")] z nazwanymi zasadami.
  • Nie należy definiować zasad domyślnych.
  • Nie używaj routingu punktów końcowych.

Kod w następnej sekcji spełnia poprzednią listę.

Zobacz Testowanie mechanizmu CORS , aby uzyskać instrukcje dotyczące testowania kodu podobnego do poprzedniego kodu.

Wyłączanie mechanizmu CORS

Atrybut [DisableCors] nie wyłącza mechanizmu CORS, który został włączony przez routing punktu końcowego.

Poniższy kod definiuje zasady "MyPolicy"MECHANIZMU CORS:

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

Poniższy kod wyłącza mechanizm CORS dla GetValues2 akcji:

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

}

Powyższy kod ma następujące działanie:

  • Nie włącza mechanizmu CORS z routingiem punktów końcowych.
  • Nie definiuje domyślnych zasad CORS.
  • Używa funkcji [EnableCors("MyPolicy")] w celu włączenia "MyPolicy" zasad CORS dla kontrolera.
  • Wyłącza mechanizm CORS dla GetValues2 metody .

Aby uzyskać instrukcje dotyczące testowania poprzedniego kodu, zobacz Testowanie mechanizmu CORS .

Opcje zasad MECHANIZMU CORS

W tej sekcji opisano różne opcje, które można ustawić w zasadach MECHANIZMU CORS:

AddPolicy jest wywoływana w pliku Program.cs. W przypadku niektórych opcji warto zapoznać się z sekcją Jak działa mechanizm CORS.

Ustawianie dozwolonych źródeł

AllowAnyOrigin: zezwala na żądania CORS ze wszystkich źródeł przy użyciu dowolnego schematu (http lub https). AllowAnyOrigin jest niezabezpieczona, ponieważ każda witryna internetowa może wysyłać żądania między źródłami do aplikacji.

Uwaga

Określanie AllowAnyOrigin i AllowCredentials jest niezabezpieczoną konfiguracją i może spowodować fałszerzowanie żądań między witrynami. Usługa CORS zwraca nieprawidłową odpowiedź CORS, gdy aplikacja jest skonfigurowana przy użyciu obu metod.

AllowAnyOrigin dotyczy żądań wstępnych i nagłówka Access-Control-Allow-Origin . Aby uzyskać więcej informacji, zobacz sekcję Wstępne żądania .

SetIsOriginAllowedToAllowWildcardSubdomains: Ustawia IsOriginAllowed właściwość zasad jako funkcję, która umożliwia źródłom dopasowanie skonfigurowanej domeny wieloznacznych podczas oceny, czy źródło jest dozwolone.

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

Ustawianie dozwolonych metod HTTP

AllowAnyMethod:

  • Zezwala na dowolną metodę HTTP:
  • Wpływa na żądania wstępne i Access-Control-Allow-Methods nagłówek. Aby uzyskać więcej informacji, zobacz sekcję Wstępne żądania .

Ustawianie dozwolonych nagłówków żądań

Aby zezwolić na wysyłanie określonych nagłówków w żądaniu CORS, nazywanym nagłówkami żądań autora, wywołaj WithHeaders i określ dozwolone nagłówki:

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

Aby zezwolić na wszystkie nagłówki żądań autora, wywołaj metodę AllowAnyHeader:

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 dotyczy żądań wstępnych i nagłówka Access-Control-Request-Headers . Aby uzyskać więcej informacji, zobacz sekcję Wstępne żądania .

Zasady oprogramowania pośredniczącego CORS są zgodne z określonymi nagłówkami określonymi przez WithHeaders usługę jest możliwe tylko wtedy, gdy nagłówki wysyłane w Access-Control-Request-Headers formacie dokładnie odpowiadają nagłówkom określonym w elemencie WithHeaders.

Rozważmy na przykład aplikację skonfigurowaną w następujący sposób:

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

Oprogramowanie pośredniczące CORS odrzuca żądanie wstępne z następującym nagłówkiem żądania, ponieważ Content-Language (HeaderNames.ContentLanguage) nie ma na liście :WithHeaders

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

Aplikacja zwraca odpowiedź 200 OK , ale nie wysyła nagłówków CORS z powrotem. W związku z tym przeglądarka nie podejmuje próby żądania między źródłami.

Ustawianie uwidocznionych nagłówków odpowiedzi

Domyślnie przeglądarka nie ujawnia wszystkich nagłówków odpowiedzi aplikacji. Aby uzyskać więcej informacji, zobacz Udostępnianie zasobów między źródłami W3C (terminologia): prosty nagłówek odpowiedzi.

Nagłówki odpowiedzi, które są dostępne domyślnie, to:

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

Specyfikacja MECHANIZMU CORS wywołuje te nagłówki prostych nagłówków odpowiedzi. Aby udostępnić inne nagłówki aplikacji, wywołaj metodę WithExposedHeaders:

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

Poświadczenia w żądaniach między źródłami

Poświadczenia wymagają specjalnej obsługi w żądaniu CORS. Domyślnie przeglądarka nie wysyła poświadczeń z żądaniem między źródłami. Poświadczenia obejmują cookieschematy uwierzytelniania s i HTTP. Aby wysyłać poświadczenia z żądaniem między źródłami, klient musi ustawić wartość XMLHttpRequest.withCredentialstrue.

Bezpośrednie użycie XMLHttpRequest :

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

Korzystanie z zapytania jQuery:

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

Korzystanie z interfejsu API pobierania:

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

Serwer musi zezwalać na poświadczenia. Aby zezwolić na poświadczenia między źródłami, wywołaj metodę AllowCredentials:

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

Odpowiedź HTTP zawiera Access-Control-Allow-Credentials nagłówek, który informuje przeglądarkę, że serwer zezwala na poświadczenia dla żądania między źródłami.

Jeśli przeglądarka wysyła poświadczenia, ale odpowiedź nie zawiera prawidłowego Access-Control-Allow-Credentials nagłówka, przeglądarka nie uwidacznia odpowiedzi na aplikację, a żądanie między źródłami zakończy się niepowodzeniem.

Zezwolenie na poświadczenia między źródłami jest zagrożeniem bezpieczeństwa. Witryna internetowa w innej domenie może wysyłać poświadczenia zalogowanego użytkownika do aplikacji w imieniu użytkownika bez wiedzy użytkownika.

Specyfikacja MECHANIZMU CORS stwierdza również, że ustawienie wartości origins na "*" (wszystkie źródła) jest nieprawidłowe, jeśli Access-Control-Allow-Credentials nagłówek jest obecny.

Żądania wstępne

W przypadku niektórych żądań CORS przeglądarka wysyła dodatkowe żądanie OPTIONS przed wysłaniem rzeczywistego żądania. To żądanie jest nazywane żądaniem wstępnym. Przeglądarka może pominąć żądanie wstępne, jeśli spełnione są wszystkie następujące warunki:

  • Metoda żądania to GET, HEAD lub POST.
  • Aplikacja nie ustawia nagłówków żądań innych niż Accept, , Accept-Language, Content-Language, Content-Typelub Last-Event-ID.
  • Nagłówek Content-Type , jeśli jest ustawiony, ma jedną z następujących wartości:
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

Reguła nagłówków żądań ustawiona dla żądania klienta ma zastosowanie do nagłówków ustawianych przez aplikację przez wywołanie setRequestHeaderXMLHttpRequest obiektu. Specyfikacja MECHANIZMU CORS wywołuje te nagłówki żądań autora. Reguła nie ma zastosowania do nagłówków, które można ustawić w przeglądarce, takich jak User-Agent, Hostlub Content-Length.

Poniżej przedstawiono przykładową odpowiedź podobną do żądania wstępnego wykonanego z przycisku [Put test] w sekcji Test CORS tego dokumentu.

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

Żądanie wstępne używa metody HTTP OPTIONS . Może zawierać następujące nagłówki:

Jeśli żądanie wstępne zostanie odrzucone, aplikacja zwróci 200 OK odpowiedź, ale nie ustawi nagłówków CORS. W związku z tym przeglądarka nie podejmuje próby żądania między źródłami. Aby zapoznać się z przykładem odmowy żądania wstępnego, zobacz sekcję Test CORS tego dokumentu.

Za pomocą narzędzi F12 aplikacja konsolowa wyświetla błąd podobny do jednego z następujących, w zależności od przeglądarki:

  • Firefox: Żądanie między źródłami zablokowane: Te same zasady pochodzenia nie zezwalają na odczytywanie zasobu zdalnego pod adresem https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5. (Przyczyna: żądanie CORS nie powiodło się). Dowiedz się więcej
  • Oparty na chromium: dostęp do pobierania z źródła "https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5https://cors3.azurewebsites.net" został zablokowany przez zasady CORS: Odpowiedź na żądanie wstępne nie przekazuje kontroli dostępu: Brak nagłówka "Access-Control-Allow-Origin" dla żądanego zasobu. Jeśli nieprzezroczysta odpowiedź spełnia Twoje potrzeby, ustaw tryb żądania na wartość "no-cors", aby pobrać zasób z wyłączonym mechanizmem CORS.

Aby zezwolić na określone nagłówki, wywołaj metodę WithHeaders:

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

Aby zezwolić na wszystkie nagłówki żądań autora, wywołaj metodę AllowAnyHeader:

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

Przeglądarki nie są spójne w sposobie ustawiania .Access-Control-Request-Headers Jeśli:

  • Nagłówki są ustawione na inne niż "*"
  • AllowAnyHeader jest wywoływany: uwzględnij co najmniej Accept, Content-Typei Origin, oraz wszelkie nagłówki niestandardowe, które mają być obsługiwane.

Kod automatycznego żądania wstępnego

Po zastosowaniu zasad CORS:

  • Globalnie przez wywołanie metody app.UseCors w pliku Program.cs.
  • Za pomocą atrybutu [EnableCors] .

ASP.NET Core odpowiada na żądanie OPCJE wstępne.

W sekcji Test CORS tego dokumentu pokazano to zachowanie.

[HttpOptions] atrybut dla żądań wstępnych

Gdy mechanizm CORS jest włączony z odpowiednimi zasadami, ASP.NET Core zwykle odpowiada na żądania wstępne CORS.

Poniższy kod używa atrybutu [HttpOptions] do tworzenia punktów końcowych dla żądań OPTIONS:

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

Aby uzyskać instrukcje dotyczące testowania poprzedniego kodu, zobacz Testowanie mechanizmu CORS za pomocą atrybutu [EnableCors] i metody RequireCors.

Ustawianie czasu wygaśnięcia przedlotu

Nagłówek Access-Control-Max-Age określa, jak długo można buforować odpowiedź na żądanie wstępne. Aby ustawić ten nagłówek, wywołaj metodę SetPreflightMaxAge:

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

Włączanie mechanizmu CORS w punkcie końcowym

Jak działa mechanizm CORS

W tej sekcji opisano, co dzieje się w żądaniu CORS na poziomie komunikatów HTTP.

  • MECHANIZM CORS nie jest funkcją zabezpieczeń. CORS to standard W3C, który umożliwia serwerowi złagodzenie zasad tego samego źródła.
    • Na przykład złośliwy aktor może użyć skryptów między witrynami (XSS) w witrynie i wykonać żądanie obejmujące wiele witryn do witryny obsługującej mechanizm CORS w celu kradzieży informacji.
  • Interfejs API nie jest bezpieczniejszy, zezwalając na mechanizm CORS.
    • Do klienta (przeglądarki) należy wymuszenie mechanizmu CORS. Serwer wykonuje żądanie i zwraca odpowiedź— klient zwraca błąd i blokuje odpowiedź. Na przykład dowolne z następujących narzędzi wyświetli odpowiedź serwera:
  • Jest to sposób na serwer, aby umożliwić przeglądarkom wykonywanie między źródłami żądania XHR lub Fetch API , które w przeciwnym razie byłoby zabronione.
    • Przeglądarki bez mechanizmu CORS nie mogą wykonywać żądań między źródłami. Przed corsem JSONP został użyty do obejścia tego ograniczenia. JSONP nie używa XHR, używa tagu <script> do odbierania odpowiedzi. Skrypty mogą być ładowane między źródłami.

Specyfikacja MECHANIZMU CORS wprowadziła kilka nowych nagłówków HTTP, które umożliwiają żądania między źródłami. Jeśli przeglądarka obsługuje mechanizm CORS, automatycznie ustawia te nagłówki dla żądań między źródłami. Niestandardowy kod JavaScript nie jest wymagany do włączenia mechanizmu CORS.

Przycisk TEST PUT w wdrożonej próbce

Poniżej przedstawiono przykład żądania między źródłami z przycisku Test wartości do https://cors1.azurewebsites.net/api/values. Nagłówek Origin :

  • Udostępnia domenę lokacji wysyłającej żądanie.
  • Jest wymagany i musi być inny niż host.

Nagłówki ogólne

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

Nagłówki odpowiedzi

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

Nagłówki żądań

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 ...

W OPTIONS żądaniach serwer ustawia nagłówek NagłówkiAccess-Control-Allow-Origin: {allowed origin} odpowiedzi w odpowiedzi. Na przykład wdrożone przykładowe żądanie przycisku OPTIONS Usuń [EnableCors] zawiera następujące nagłówki:

Nagłówki ogólne

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

Nagłówki odpowiedzi

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

Nagłówki żądań

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

W poprzednich nagłówkach Odpowiedzi serwer ustawia nagłówek Access-Control-Allow-Origin w odpowiedzi. Wartość https://cors1.azurewebsites.net tego nagłówka odpowiada nagłówkowi Origin z żądania.

Jeśli AllowAnyOrigin parametr jest wywoływany, zwracana jest wartość z symbolem Access-Control-Allow-Origin: *wieloznacznymi. AllowAnyOrigin zezwala na dowolne źródło.

Jeśli odpowiedź nie zawiera nagłówka Access-Control-Allow-Origin , żądanie między źródłami zakończy się niepowodzeniem. W szczególności przeglądarka nie zezwala na żądanie. Nawet jeśli serwer zwróci pomyślną odpowiedź, przeglądarka nie udostępni odpowiedzi aplikacji klienckiej.

Przekierowanie HTTP do protokołu HTTPS powoduje ERR_INVALID_REDIRECT w żądaniu wstępnym CORS

Żądania do punktu końcowego przy użyciu protokołu HTTP, które są przekierowywane do protokołu HTTPS przez UseHttpsRedirection niepowodzenie z .ERR_INVALID_REDIRECT on the CORS preflight request

Projekty interfejsu API mogą odrzucać żądania HTTP, a nie przekierowywać UseHttpsRedirection żądania do protokołu HTTPS.

Mechanizm CORS w usługach IIS

Podczas wdrażania w usługach IIS mechanizm CORS musi działać przed uwierzytelnianiem systemu Windows, jeśli serwer nie jest skonfigurowany do zezwalania na dostęp anonimowy. Aby obsługiwać ten scenariusz, moduł CORS usług IIS musi zostać zainstalowany i skonfigurowany dla aplikacji.

Testowanie mechanizmu CORS

Przykładowy plik do pobrania zawiera kod do testowania mechanizmu CORS. Zobacz , jak pobrać. Przykład jest projektem interfejsu API z dodanymi stronami Razor :

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

Ostrzeżenie

WithOrigins("https://localhost:<port>");należy używać tylko do testowania przykładowej aplikacji podobnej do przykładowego kodu pobierania.

Poniżej przedstawiono ValuesController punkty końcowe do testowania:

[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 jest dostarczany przez pakiet NuGet Rick.Docs.Samples.RouteInfo i wyświetla informacje o trasie.

Przetestuj poprzedni przykładowy kod przy użyciu jednego z następujących metod:

  • Użyj wdrożonej przykładowej aplikacji pod adresem https://cors3.azurewebsites.net/. Nie ma potrzeby pobierania przykładu.
  • Uruchom przykład przy dotnet run użyciu domyślnego adresu URL .https://localhost:5001
  • Uruchom przykład z programu Visual Studio z portem ustawionym na 44398 jako adres URL https://localhost:44398.

Za pomocą przeglądarki z narzędziami F12:

  • Wybierz przycisk Wartości i przejrzyj nagłówki na karcie Sieć.

  • Wybierz przycisk TEST PUT. Zobacz Wyświetlanie żądań OPTIONS, aby uzyskać instrukcje dotyczące wyświetlania żądania OPTIONS. Test PUT tworzy dwa żądania, żądanie wstępne OPTIONS i żądanie PUT.

  • Wybierz przycisk, GetValues2 [DisableCors] aby wyzwolić nieudane żądanie CORS. Jak wspomniano w dokumencie, odpowiedź zwraca 200 powodzenia, ale żądanie CORS nie jest wykonywane. Wybierz kartę Konsola, aby wyświetlić błąd CORS. W zależności od przeglądarki zostanie wyświetlony błąd podobny do następującego:

    Dostęp do pobierania 'https://cors1.azurewebsites.net/api/values/GetValues2' z źródła 'https://cors3.azurewebsites.net' został zablokowany przez zasady CORS: w żądanym zasobie nie ma nagłówka "Access-Control-Allow-Origin". Jeśli nieprzezroczysta odpowiedź spełnia Twoje potrzeby, ustaw tryb żądania na wartość "no-cors", aby pobrać zasób z wyłączonym mechanizmem CORS.

Punkty końcowe z obsługą mechanizmu CORS można przetestować za pomocą narzędzia, takiego jak curl lub Fiddler. W przypadku korzystania z narzędzia źródło żądania określonego przez Origin nagłówek musi się różnić od hosta odbierającego żądanie. Jeśli żądanie nie jest źródłem krzyżowym na podstawie wartości nagłówka Origin :

  • Nie ma potrzeby przetwarzania żądania przez oprogramowanie pośredniczące CORS.
  • Nagłówki CORS nie są zwracane w odpowiedzi.

Następujące polecenie używa curl polecenia , aby wysłać żądanie OPTIONS z informacjami:

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

Testowanie mechanizmu CORS za pomocą atrybutu [EnableCors] i metody RequireCors

Rozważmy następujący kod, który używa routingu punktów końcowych w celu włączenia mechanizmu CORS dla poszczególnych punktów końcowych przy użyciu polecenia RequireCors:

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

Zwróć uwagę, że tylko /echo punkt końcowy używa elementu , RequireCors aby zezwolić na żądania między źródłami przy użyciu określonych zasad. Poniższe kontrolery włączają mechanizm CORS przy użyciu atrybutu [EnableCors].

Poniżej przedstawiono TodoItems1Controller punkty końcowe do testowania:

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

Przetestuj powyższy kod ze strony testowej wdrożonego przykładu.

Przyciski Usuń [EnableCors] i GET [EnableCors] kończą się powodzeniem, ponieważ punkty końcowe mają [EnableCors] żądania wstępne i odpowiadają na nie. Inne punkty końcowe kończą się niepowodzeniem. Przycisk GET kończy się niepowodzeniem, ponieważ skrypt JavaScript wysyła:

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

Poniższe informacje TodoItems2Controller zawierają podobne punkty końcowe, ale zawierają jawny kod, który odpowiada na żądania OPTIONS:

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

Przetestuj powyższy kod ze strony testowej wdrożonego przykładu. Z listy rozwijanej Kontroler wybierz pozycję Wstępne, a następnie pozycję Ustaw kontroler. Wszystkie wywołania CORS do punktów końcowych kończą się powodzeniem TodoItems2Controller .

Dodatkowe zasoby

Autorzy: Rick Anderson i Kirk Larkin

W tym artykule pokazano, jak włączyć mechanizm CORS w aplikacji ASP.NET Core.

Zabezpieczenia przeglądarki uniemożliwiają stronie internetowej wykonywanie żądań do innej domeny niż ta, która obsłużyła stronę internetową. To ograniczenie określa się jako zasadę tego samego źródła. Zasada tego samego źródła uniemożliwia złośliwym witrynom odczytywanie poufnych danych z innej witryny. Czasami możesz zezwolić innym witrynom na wykonywanie żądań w aplikacji o innym źródle. Aby uzyskać więcej informacji, zobacz artykuł Mozilla CORS.

Współużytkowanie zasobów między źródłami (CORS):

  • Jest standardem W3C, który umożliwia serwerowi złagodzenie zasad tego samego źródła.
  • Nie jest funkcją zabezpieczeń, mechanizm CORS zrelaksuje zabezpieczenia. Interfejs API nie jest bezpieczniejszy, zezwalając na mechanizm CORS. Aby uzyskać więcej informacji, zobacz Jak działa mechanizm CORS.
  • Zezwala serwerowi na jawne zezwalanie na niektóre żądania między źródłami podczas odrzucania innych.
  • Jest bezpieczniejszy i bardziej elastyczny niż wcześniejsze techniki, takie jak JSONP.

Wyświetl lub pobierz przykładowy kod (jak pobrać)

To samo źródło

Dwa adresy URL mają to samo źródło, jeśli mają identyczne schematy, hosty i porty (RFC 6454).

Te dwa adresy URL mają to samo źródło:

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

Te adresy URL mają inne źródła niż poprzednie dwa adresy URL:

  • https://example.net: Inna domena
  • https://www.example.com/foo.html: Inna poddomena
  • http://example.com/foo.html: Inny schemat
  • https://example.com:9000/foo.html: Inny port

Włączanie mechanizmu CORS

Istnieją trzy sposoby włączania mechanizmu CORS:

Użycie atrybutu [EnableCors] z nazwanymi zasadami zapewnia najlepszą kontrolę w ograniczaniu punktów końcowych obsługujących mechanizm CORS.

Ostrzeżenie

UseCors musi być wywoływana w odpowiedniej kolejności. Aby uzyskać więcej informacji, zobacz Kolejność oprogramowania pośredniczącego. Na przykład UseCors należy wywołać metodę przed UseResponseCaching użyciem polecenia UseResponseCaching.

Każde podejście zostało szczegółowo opisane w poniższych sekcjach.

MECHANIZM CORS z nazwanymi zasadami i oprogramowaniem pośredniczącym

Oprogramowanie pośredniczące CORS obsługuje żądania między źródłami. Poniższy kod stosuje zasady CORS do wszystkich punktów końcowych aplikacji z określonymi źródłami:

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

Powyższy kod ma następujące działanie:

  • Ustawia nazwę zasad na _myAllowSpecificOrigins. Nazwa zasad jest dowolna.
  • Wywołuje metodę UseCors rozszerzenia i określa _myAllowSpecificOrigins zasady CORS. UseCors dodaje oprogramowanie pośredniczące CORS. Wywołanie UseCors musi zostać umieszczone po UseRoutingmetodzie , ale przed UseAuthorization. Aby uzyskać więcej informacji, zobacz Kolejność oprogramowania pośredniczącego.
  • Wywołania AddCors za pomocą wyrażenia lambda. Lambda przyjmuje CorsPolicyBuilder obiekt. Opcje konfiguracji, takie jak WithOrigins, zostały opisane w dalszej części tego artykułu.
  • _myAllowSpecificOrigins Włącza zasady CORS dla wszystkich punktów końcowych kontrolera. Zobacz Routing punktów końcowych, aby zastosować zasady CORS do określonych punktów końcowych.
  • W przypadku korzystania z oprogramowania pośredniczącego Buforowanie odpowiedzi wywołaj metodę przed UseResponseCaching.UseCors

W przypadku routingu punktów końcowych oprogramowanie pośredniczące CORS musi być skonfigurowane do wykonywania między wywołaniami do UseRouting i UseEndpoints.

Zobacz Testowanie mechanizmu CORS , aby uzyskać instrukcje dotyczące testowania kodu podobnego do poprzedniego kodu.

Wywołanie AddCors metody dodaje usługi CORS do kontenera usługi aplikacji:

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

Aby uzyskać więcej informacji, zobacz opcje zasad MECHANIZMU CORS w tym dokumencie.

CorsPolicyBuilder Metody można połączyć łańcuchem, jak pokazano w poniższym kodzie:

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

Uwaga: określony adres URL nie może zawierać ukośnika końcowego (/). Jeśli adres URL zakończy się ciągiem /, porównanie zwróci wartość false i nie zostanie zwrócony żaden nagłówek.

Ostrzeżenie

UseCors należy umieścić po i UseRouting przed UseAuthorization. Ma to na celu zapewnienie, że nagłówki CORS znajdują się w odpowiedzi zarówno na wywołania autoryzowane, jak i nieautoryzowane.

Kolejność składników UseCors i UseStaticFiles

UseStaticFiles Zazwyczaj jest wywoływana przed UseCors. Aplikacje korzystające z języka JavaScript do pobierania plików statycznych między witrynami muszą wywoływać przed UseStaticFiles.UseCors

MECHANIZM CORS z domyślnymi zasadami i oprogramowaniem pośredniczącym

Poniższy wyróżniony kod włącza domyślne zasady MECHANIZMU CORS:

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

Powyższy kod stosuje domyślne zasady CORS do wszystkich punktów końcowych kontrolera.

Włączanie mechanizmu Cors z routingiem punktów końcowych

Włączenie mechanizmu CORS dla poszczególnych punktów końcowych przy użyciu RequireCorsnie obsługuje automatycznych żądań wstępnych. Aby uzyskać więcej informacji, zobacz ten problem z usługą GitHub i Przetestuj mechanizm CORS z routingiem punktów końcowych i [HttpOptions].

W przypadku routingu punktu końcowego mechanizm CORS można włączyć dla poszczególnych punktów końcowych przy użyciu RequireCors zestawu metod rozszerzeń:

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

Powyższy kod:

  • app.UseCors włącza oprogramowanie pośredniczące CORS. Ponieważ nie skonfigurowano zasad domyślnych, app.UseCors() sam nie włącza mechanizmu CORS.
  • Punkty /echo końcowe kontrolera i zezwalają na żądania między źródłami przy użyciu określonych zasad.
  • Punkty /echo2 końcowe stron i Razor nie zezwalają na żądania między źródłami, ponieważ nie określono żadnych domyślnych zasad.

Atrybut [DisableCors] nie wyłącza mechanizmu CORS, który został włączony przez routing punktu końcowego za pomocą polecenia RequireCors.

Aby uzyskać instrukcje dotyczące testowania kodu podobnego do poprzedniego, zobacz Testowanie mechanizmu CORS z routingiem punktu końcowego i [HttpOptions ].

Włączanie mechanizmu CORS z atrybutami

Włączenie mechanizmu CORS za pomocą atrybutu [EnableCors] i zastosowanie nazwanych zasad tylko do tych punktów końcowych, które wymagają mechanizmu CORS, zapewnia najlepszą kontrolę.

Atrybut [EnableCors] zapewnia alternatywę dla stosowania mechanizmu CORS globalnie. Atrybut [EnableCors] umożliwia mechanizm CORS dla wybranych punktów końcowych, a nie wszystkich punktów końcowych:

  • [EnableCors] określa zasady domyślne.
  • [EnableCors("{Policy String}")] określa nazwane zasady.

Atrybut [EnableCors] można zastosować do:

  • Razor Strona PageModel
  • Kontroler
  • Metoda akcji kontrolera

Różne zasady można stosować do kontrolerów, modeli stron lub metod akcji za pomocą atrybutu [EnableCors] . [EnableCors] Gdy atrybut jest stosowany do kontrolera, modelu strony lub metody akcji, a mechanizm CORS jest włączony w programie pośredniczącym, stosowane są obie zasady. Zalecamy łączenie zasad. Użyj przycisku [EnableCors]atrybutu lub oprogramowania pośredniczącego, a nie obu w tej samej aplikacji.

Poniższy kod stosuje inne zasady do każdej metody:

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

Poniższy kod tworzy dwie zasady CORS:

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

Aby uzyskać najlepszą kontrolę nad ograniczaniem żądań CORS:

  • Użyj [EnableCors("MyPolicy")] z nazwanymi zasadami.
  • Nie należy definiować zasad domyślnych.
  • Nie używaj routingu punktów końcowych.

Kod w następnej sekcji spełnia poprzednią listę.

Zobacz Testowanie mechanizmu CORS , aby uzyskać instrukcje dotyczące testowania kodu podobnego do poprzedniego kodu.

Wyłączanie mechanizmu CORS

Atrybut [DisableCors] nie wyłącza mechanizmu CORS, który został włączony przez routing punktu końcowego.

Poniższy kod definiuje zasady "MyPolicy"MECHANIZMU CORS:

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

Poniższy kod wyłącza mechanizm CORS dla GetValues2 akcji:

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

}

Powyższy kod ma następujące działanie:

  • Nie włącza mechanizmu CORS z routingiem punktów końcowych.
  • Nie definiuje domyślnych zasad CORS.
  • Używa funkcji [EnableCors("MyPolicy")] w celu włączenia "MyPolicy" zasad CORS dla kontrolera.
  • Wyłącza mechanizm CORS dla GetValues2 metody .

Aby uzyskać instrukcje dotyczące testowania poprzedniego kodu, zobacz Testowanie mechanizmu CORS .

Opcje zasad MECHANIZMU CORS

W tej sekcji opisano różne opcje, które można ustawić w zasadach MECHANIZMU CORS:

AddPolicy jest wywoływana w pliku Program.cs. W przypadku niektórych opcji warto zapoznać się z sekcją Jak działa mechanizm CORS.

Ustawianie dozwolonych źródeł

AllowAnyOrigin: zezwala na żądania CORS ze wszystkich źródeł przy użyciu dowolnego schematu (http lub https). AllowAnyOrigin jest niezabezpieczona, ponieważ każda witryna internetowa może wysyłać żądania między źródłami do aplikacji.

Uwaga

Określanie AllowAnyOrigin i AllowCredentials jest niezabezpieczoną konfiguracją i może spowodować fałszerzowanie żądań między witrynami. Usługa CORS zwraca nieprawidłową odpowiedź CORS, gdy aplikacja jest skonfigurowana przy użyciu obu metod.

AllowAnyOrigin dotyczy żądań wstępnych i nagłówka Access-Control-Allow-Origin . Aby uzyskać więcej informacji, zobacz sekcję Wstępne żądania .

SetIsOriginAllowedToAllowWildcardSubdomains: Ustawia IsOriginAllowed właściwość zasad jako funkcję, która umożliwia źródłom dopasowanie skonfigurowanej domeny wieloznacznych podczas oceny, czy źródło jest dozwolone.

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

Ustawianie dozwolonych metod HTTP

AllowAnyMethod:

  • Zezwala na dowolną metodę HTTP:
  • Wpływa na żądania wstępne i Access-Control-Allow-Methods nagłówek. Aby uzyskać więcej informacji, zobacz sekcję Wstępne żądania .

Ustawianie dozwolonych nagłówków żądań

Aby zezwolić na wysyłanie określonych nagłówków w żądaniu CORS, nazywanym nagłówkami żądań autora, wywołaj WithHeaders i określ dozwolone nagłówki:

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

Aby zezwolić na wszystkie nagłówki żądań autora, wywołaj metodę AllowAnyHeader:

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 dotyczy żądań wstępnych i nagłówka Access-Control-Request-Headers . Aby uzyskać więcej informacji, zobacz sekcję Wstępne żądania .

Zasady oprogramowania pośredniczącego CORS są zgodne z określonymi nagłówkami określonymi przez WithHeaders usługę jest możliwe tylko wtedy, gdy nagłówki wysyłane w Access-Control-Request-Headers formacie dokładnie odpowiadają nagłówkom określonym w elemencie WithHeaders.

Rozważmy na przykład aplikację skonfigurowaną w następujący sposób:

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

Oprogramowanie pośredniczące CORS odrzuca żądanie wstępne z następującym nagłówkiem żądania, ponieważ Content-Language (HeaderNames.ContentLanguage) nie ma na liście :WithHeaders

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

Aplikacja zwraca odpowiedź 200 OK , ale nie wysyła nagłówków CORS z powrotem. W związku z tym przeglądarka nie podejmuje próby żądania między źródłami.

Ustawianie uwidocznionych nagłówków odpowiedzi

Domyślnie przeglądarka nie ujawnia wszystkich nagłówków odpowiedzi aplikacji. Aby uzyskać więcej informacji, zobacz Udostępnianie zasobów między źródłami W3C (terminologia): prosty nagłówek odpowiedzi.

Nagłówki odpowiedzi, które są dostępne domyślnie, to:

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

Specyfikacja MECHANIZMU CORS wywołuje te nagłówki prostych nagłówków odpowiedzi. Aby udostępnić inne nagłówki aplikacji, wywołaj metodę WithExposedHeaders:

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

Poświadczenia w żądaniach między źródłami

Poświadczenia wymagają specjalnej obsługi w żądaniu CORS. Domyślnie przeglądarka nie wysyła poświadczeń z żądaniem między źródłami. Poświadczenia obejmują cookieschematy uwierzytelniania s i HTTP. Aby wysyłać poświadczenia z żądaniem między źródłami, klient musi ustawić wartość XMLHttpRequest.withCredentialstrue.

Bezpośrednie użycie XMLHttpRequest :

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

Korzystanie z zapytania jQuery:

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

Korzystanie z interfejsu API pobierania:

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

Serwer musi zezwalać na poświadczenia. Aby zezwolić na poświadczenia między źródłami, wywołaj metodę AllowCredentials:

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

Odpowiedź HTTP zawiera Access-Control-Allow-Credentials nagłówek, który informuje przeglądarkę, że serwer zezwala na poświadczenia dla żądania między źródłami.

Jeśli przeglądarka wysyła poświadczenia, ale odpowiedź nie zawiera prawidłowego Access-Control-Allow-Credentials nagłówka, przeglądarka nie uwidacznia odpowiedzi na aplikację, a żądanie między źródłami zakończy się niepowodzeniem.

Zezwolenie na poświadczenia między źródłami jest zagrożeniem bezpieczeństwa. Witryna internetowa w innej domenie może wysyłać poświadczenia zalogowanego użytkownika do aplikacji w imieniu użytkownika bez wiedzy użytkownika.

Specyfikacja MECHANIZMU CORS stwierdza również, że ustawienie wartości origins na "*" (wszystkie źródła) jest nieprawidłowe, jeśli Access-Control-Allow-Credentials nagłówek jest obecny.

Żądania wstępne

W przypadku niektórych żądań CORS przeglądarka wysyła dodatkowe żądanie OPTIONS przed wysłaniem rzeczywistego żądania. To żądanie jest nazywane żądaniem wstępnym. Przeglądarka może pominąć żądanie wstępne, jeśli spełnione są wszystkie następujące warunki:

  • Metoda żądania to GET, HEAD lub POST.
  • Aplikacja nie ustawia nagłówków żądań innych niż Accept, , Accept-Language, Content-Language, Content-Typelub Last-Event-ID.
  • Nagłówek Content-Type , jeśli jest ustawiony, ma jedną z następujących wartości:
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

Reguła nagłówków żądań ustawiona dla żądania klienta ma zastosowanie do nagłówków ustawianych przez aplikację przez wywołanie setRequestHeaderXMLHttpRequest obiektu. Specyfikacja MECHANIZMU CORS wywołuje te nagłówki żądań autora. Reguła nie ma zastosowania do nagłówków, które można ustawić w przeglądarce, takich jak User-Agent, Hostlub Content-Length.

Poniżej przedstawiono przykładową odpowiedź podobną do żądania wstępnego wykonanego z przycisku [Put test] w sekcji Test CORS tego dokumentu.

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

Żądanie wstępne używa metody HTTP OPTIONS . Może zawierać następujące nagłówki:

Jeśli żądanie wstępne zostanie odrzucone, aplikacja zwróci 200 OK odpowiedź, ale nie ustawi nagłówków CORS. W związku z tym przeglądarka nie podejmuje próby żądania między źródłami. Aby zapoznać się z przykładem odmowy żądania wstępnego, zobacz sekcję Test CORS tego dokumentu.

Za pomocą narzędzi F12 aplikacja konsolowa wyświetla błąd podobny do jednego z następujących, w zależności od przeglądarki:

  • Firefox: Żądanie między źródłami zablokowane: Te same zasady pochodzenia nie zezwalają na odczytywanie zasobu zdalnego pod adresem https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5. (Przyczyna: żądanie CORS nie powiodło się). Dowiedz się więcej
  • Oparty na chromium: dostęp do pobierania z źródła "https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5https://cors3.azurewebsites.net" został zablokowany przez zasady CORS: Odpowiedź na żądanie wstępne nie przekazuje kontroli dostępu: Brak nagłówka "Access-Control-Allow-Origin" dla żądanego zasobu. Jeśli nieprzezroczysta odpowiedź spełnia Twoje potrzeby, ustaw tryb żądania na wartość "no-cors", aby pobrać zasób z wyłączonym mechanizmem CORS.

Aby zezwolić na określone nagłówki, wywołaj metodę WithHeaders:

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

Aby zezwolić na wszystkie nagłówki żądań autora, wywołaj metodę AllowAnyHeader:

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

Przeglądarki nie są spójne w sposobie ustawiania .Access-Control-Request-Headers Jeśli:

  • Nagłówki są ustawione na inne niż "*"
  • AllowAnyHeader jest wywoływany: uwzględnij co najmniej Accept, Content-Typei Origin, oraz wszelkie nagłówki niestandardowe, które mają być obsługiwane.

Kod automatycznego żądania wstępnego

Po zastosowaniu zasad CORS:

  • Globalnie przez wywołanie metody app.UseCors w pliku Program.cs.
  • Za pomocą atrybutu [EnableCors] .

ASP.NET Core odpowiada na żądanie OPCJE wstępne.

Włączenie mechanizmu CORS dla poszczególnych punktów końcowych przy użyciu RequireCors obecnie nie obsługuje automatycznych żądań wstępnych.

W sekcji Test CORS tego dokumentu pokazano to zachowanie.

[HttpOptions] atrybut dla żądań wstępnych

Gdy mechanizm CORS jest włączony z odpowiednimi zasadami, ASP.NET Core zwykle odpowiada na żądania wstępne CORS. W niektórych scenariuszach może to nie być możliwe. Na przykład użycie mechanizmu CORS z routingiem punktów końcowych.

Poniższy kod używa atrybutu [HttpOptions] do tworzenia punktów końcowych dla żądań OPTIONS:

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

Aby uzyskać instrukcje dotyczące testowania poprzedniego kodu, zobacz Testowanie mechanizmu CORS przy użyciu routingu punktu końcowego i [HttpOptions ].

Ustawianie czasu wygaśnięcia przedlotu

Nagłówek Access-Control-Max-Age określa, jak długo można buforować odpowiedź na żądanie wstępne. Aby ustawić ten nagłówek, wywołaj metodę SetPreflightMaxAge:

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

Jak działa mechanizm CORS

W tej sekcji opisano, co dzieje się w żądaniu CORS na poziomie komunikatów HTTP.

  • MECHANIZM CORS nie jest funkcją zabezpieczeń. CORS to standard W3C, który umożliwia serwerowi złagodzenie zasad tego samego źródła.
    • Na przykład złośliwy aktor może użyć skryptów między witrynami (XSS) w witrynie i wykonać żądanie obejmujące wiele witryn do witryny obsługującej mechanizm CORS w celu kradzieży informacji.
  • Interfejs API nie jest bezpieczniejszy, zezwalając na mechanizm CORS.
    • Do klienta (przeglądarki) należy wymuszenie mechanizmu CORS. Serwer wykonuje żądanie i zwraca odpowiedź— klient zwraca błąd i blokuje odpowiedź. Na przykład dowolne z następujących narzędzi wyświetli odpowiedź serwera:
  • Jest to sposób na serwer, aby umożliwić przeglądarkom wykonywanie między źródłami żądania XHR lub Fetch API , które w przeciwnym razie byłoby zabronione.
    • Przeglądarki bez mechanizmu CORS nie mogą wykonywać żądań między źródłami. Przed corsem JSONP został użyty do obejścia tego ograniczenia. JSONP nie używa XHR, używa tagu <script> do odbierania odpowiedzi. Skrypty mogą być ładowane między źródłami.

Specyfikacja MECHANIZMU CORS wprowadziła kilka nowych nagłówków HTTP, które umożliwiają żądania między źródłami. Jeśli przeglądarka obsługuje mechanizm CORS, automatycznie ustawia te nagłówki dla żądań między źródłami. Niestandardowy kod JavaScript nie jest wymagany do włączenia mechanizmu CORS.

Przycisk TEST PUT w wdrożonej próbce

Poniżej przedstawiono przykład żądania między źródłami z przycisku Test wartości do https://cors1.azurewebsites.net/api/values. Nagłówek Origin :

  • Udostępnia domenę lokacji wysyłającej żądanie.
  • Jest wymagany i musi być inny niż host.

Nagłówki ogólne

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

Nagłówki odpowiedzi

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

Nagłówki żądań

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 ...

W OPTIONS żądaniach serwer ustawia nagłówek NagłówkiAccess-Control-Allow-Origin: {allowed origin} odpowiedzi w odpowiedzi. Na przykład wdrożone przykładowe żądanie przycisku OPTIONS Usuń [EnableCors] zawiera następujące nagłówki:

Nagłówki ogólne

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

Nagłówki odpowiedzi

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

Nagłówki żądań

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

W poprzednich nagłówkach Odpowiedzi serwer ustawia nagłówek Access-Control-Allow-Origin w odpowiedzi. Wartość https://cors1.azurewebsites.net tego nagłówka odpowiada nagłówkowi Origin z żądania.

Jeśli AllowAnyOrigin parametr jest wywoływany, zwracana jest wartość z symbolem Access-Control-Allow-Origin: *wieloznacznymi. AllowAnyOrigin zezwala na dowolne źródło.

Jeśli odpowiedź nie zawiera nagłówka Access-Control-Allow-Origin , żądanie między źródłami zakończy się niepowodzeniem. W szczególności przeglądarka nie zezwala na żądanie. Nawet jeśli serwer zwróci pomyślną odpowiedź, przeglądarka nie udostępni odpowiedzi aplikacji klienckiej.

Przekierowanie HTTP do protokołu HTTPS powoduje ERR_INVALID_REDIRECT w żądaniu wstępnym CORS

Żądania do punktu końcowego przy użyciu protokołu HTTP, które są przekierowywane do protokołu HTTPS przez UseHttpsRedirection niepowodzenie z .ERR_INVALID_REDIRECT on the CORS preflight request

Projekty interfejsu API mogą odrzucać żądania HTTP, a nie przekierowywać UseHttpsRedirection żądania do protokołu HTTPS.

Wyświetlanie żądań OPTIONS

Domyślnie przeglądarki Chrome i Edge nie wyświetlają żądań OPTIONS na karcie sieci narzędzi F12. Aby wyświetlić żądania OPTIONS w następujących przeglądarkach:

  • chrome://flags/#out-of-blink-cors lub edge://flags/#out-of-blink-cors
  • wyłącz flagę.
  • Ponownie uruchomić.

Przeglądarka Firefox domyślnie wyświetla żądania OPTIONS.

Mechanizm CORS w usługach IIS

Podczas wdrażania w usługach IIS mechanizm CORS musi działać przed uwierzytelnianiem systemu Windows, jeśli serwer nie jest skonfigurowany do zezwalania na dostęp anonimowy. Aby obsługiwać ten scenariusz, moduł CORS usług IIS musi zostać zainstalowany i skonfigurowany dla aplikacji.

Testowanie mechanizmu CORS

Przykładowy plik do pobrania zawiera kod do testowania mechanizmu CORS. Zobacz , jak pobrać. Przykład jest projektem interfejsu API z dodanymi stronami Razor :

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

Ostrzeżenie

WithOrigins("https://localhost:<port>");należy używać tylko do testowania przykładowej aplikacji podobnej do przykładowego kodu pobierania.

Poniżej przedstawiono ValuesController punkty końcowe do testowania:

[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 jest dostarczany przez pakiet NuGet Rick.Docs.Samples.RouteInfo i wyświetla informacje o trasie.

Przetestuj poprzedni przykładowy kod przy użyciu jednego z następujących metod:

  • Użyj wdrożonej przykładowej aplikacji pod adresem https://cors3.azurewebsites.net/. Nie ma potrzeby pobierania przykładu.
  • Uruchom przykład przy dotnet run użyciu domyślnego adresu URL .https://localhost:5001
  • Uruchom przykład z programu Visual Studio z portem ustawionym na 44398 jako adres URL https://localhost:44398.

Za pomocą przeglądarki z narzędziami F12:

  • Wybierz przycisk Wartości i przejrzyj nagłówki na karcie Sieć.

  • Wybierz przycisk TEST PUT. Zobacz Wyświetlanie żądań OPTIONS, aby uzyskać instrukcje dotyczące wyświetlania żądania OPTIONS. Test PUT tworzy dwa żądania, żądanie wstępne OPTIONS i żądanie PUT.

  • Wybierz przycisk, GetValues2 [DisableCors] aby wyzwolić nieudane żądanie CORS. Jak wspomniano w dokumencie, odpowiedź zwraca 200 powodzenia, ale żądanie CORS nie jest wykonywane. Wybierz kartę Konsola, aby wyświetlić błąd CORS. W zależności od przeglądarki zostanie wyświetlony błąd podobny do następującego:

    Dostęp do pobierania 'https://cors1.azurewebsites.net/api/values/GetValues2' z źródła 'https://cors3.azurewebsites.net' został zablokowany przez zasady CORS: w żądanym zasobie nie ma nagłówka "Access-Control-Allow-Origin". Jeśli nieprzezroczysta odpowiedź spełnia Twoje potrzeby, ustaw tryb żądania na wartość "no-cors", aby pobrać zasób z wyłączonym mechanizmem CORS.

Punkty końcowe z obsługą mechanizmu CORS można przetestować za pomocą narzędzia, takiego jak curl lub Fiddler. W przypadku korzystania z narzędzia źródło żądania określonego przez Origin nagłówek musi się różnić od hosta odbierającego żądanie. Jeśli żądanie nie jest źródłem krzyżowym na podstawie wartości nagłówka Origin :

  • Nie ma potrzeby przetwarzania żądania przez oprogramowanie pośredniczące CORS.
  • Nagłówki CORS nie są zwracane w odpowiedzi.

Następujące polecenie używa curl polecenia , aby wysłać żądanie OPTIONS z informacjami:

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

Testowanie mechanizmu CORS przy użyciu routingu punktu końcowego i [HttpOptions]

Włączenie mechanizmu CORS dla poszczególnych punktów końcowych przy użyciu RequireCors obecnie nie obsługuje automatycznych żądań wstępnych. Rozważmy następujący kod, który używa routingu punktu końcowego w celu włączenia mechanizmu CORS:

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

Poniżej przedstawiono TodoItems1Controller punkty końcowe do testowania:

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

Przetestuj powyższy kod ze strony testowej wdrożonego przykładu.

Przyciski Usuń [EnableCors] i GET [EnableCors] kończą się powodzeniem, ponieważ punkty końcowe mają [EnableCors] żądania wstępne i odpowiadają na nie. Inne punkty końcowe kończą się niepowodzeniem. Przycisk GET kończy się niepowodzeniem, ponieważ skrypt JavaScript wysyła:

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

Poniższe informacje TodoItems2Controller zawierają podobne punkty końcowe, ale zawierają jawny kod, który odpowiada na żądania OPTIONS:

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

Przetestuj powyższy kod ze strony testowej wdrożonego przykładu. Z listy rozwijanej Kontroler wybierz pozycję Wstępne, a następnie pozycję Ustaw kontroler. Wszystkie wywołania CORS do punktów końcowych kończą się powodzeniem TodoItems2Controller .

Dodatkowe zasoby

Autorzy: Rick Anderson i Kirk Larkin

W tym artykule pokazano, jak włączyć mechanizm CORS w aplikacji ASP.NET Core.

Zabezpieczenia przeglądarki uniemożliwiają stronie internetowej wykonywanie żądań do innej domeny niż ta, która obsłużyła stronę internetową. To ograniczenie określa się jako zasadę tego samego źródła. Zasada tego samego źródła uniemożliwia złośliwym witrynom odczytywanie poufnych danych z innej witryny. Czasami możesz zezwolić innym witrynom na wykonywanie żądań w aplikacji o innym źródle. Aby uzyskać więcej informacji, zobacz artykuł Mozilla CORS.

Współużytkowanie zasobów między źródłami (CORS):

  • Jest standardem W3C, który umożliwia serwerowi złagodzenie zasad tego samego źródła.
  • Nie jest funkcją zabezpieczeń, mechanizm CORS zrelaksuje zabezpieczenia. Interfejs API nie jest bezpieczniejszy, zezwalając na mechanizm CORS. Aby uzyskać więcej informacji, zobacz Jak działa mechanizm CORS.
  • Zezwala serwerowi na jawne zezwalanie na niektóre żądania między źródłami podczas odrzucania innych.
  • Jest bezpieczniejszy i bardziej elastyczny niż wcześniejsze techniki, takie jak JSONP.

Wyświetl lub pobierz przykładowy kod (jak pobrać)

To samo źródło

Dwa adresy URL mają to samo źródło, jeśli mają identyczne schematy, hosty i porty (RFC 6454).

Te dwa adresy URL mają to samo źródło:

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

Te adresy URL mają inne źródła niż poprzednie dwa adresy URL:

  • https://example.net: Inna domena
  • https://www.example.com/foo.html: Inna poddomena
  • http://example.com/foo.html: Inny schemat
  • https://example.com:9000/foo.html: Inny port

Włączanie mechanizmu CORS

Istnieją trzy sposoby włączania mechanizmu CORS:

Użycie atrybutu [EnableCors] z nazwanymi zasadami zapewnia najlepszą kontrolę w ograniczaniu punktów końcowych obsługujących mechanizm CORS.

Ostrzeżenie

UseCors musi być wywoływana w odpowiedniej kolejności. Aby uzyskać więcej informacji, zobacz Kolejność oprogramowania pośredniczącego. Na przykład UseCors należy wywołać metodę przed UseResponseCaching użyciem polecenia UseResponseCaching.

Każde podejście zostało szczegółowo opisane w poniższych sekcjach.

MECHANIZM CORS z nazwanymi zasadami i oprogramowaniem pośredniczącym

Oprogramowanie pośredniczące CORS obsługuje żądania między źródłami. Poniższy kod stosuje zasady CORS do wszystkich punktów końcowych aplikacji z określonymi źródłami:

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

Powyższy kod ma następujące działanie:

  • Ustawia nazwę zasad na _myAllowSpecificOrigins. Nazwa zasad jest dowolna.
  • Wywołuje metodę UseCors rozszerzenia i określa _myAllowSpecificOrigins zasady CORS. UseCors dodaje oprogramowanie pośredniczące CORS. Wywołanie UseCors musi zostać umieszczone po UseRoutingmetodzie , ale przed UseAuthorization. Aby uzyskać więcej informacji, zobacz Kolejność oprogramowania pośredniczącego.
  • Wywołania AddCors za pomocą wyrażenia lambda. Lambda przyjmuje CorsPolicyBuilder obiekt. Opcje konfiguracji, takie jak WithOrigins, zostały opisane w dalszej części tego artykułu.
  • _myAllowSpecificOrigins Włącza zasady CORS dla wszystkich punktów końcowych kontrolera. Zobacz Routing punktów końcowych, aby zastosować zasady CORS do określonych punktów końcowych.
  • W przypadku korzystania z oprogramowania pośredniczącego Buforowanie odpowiedzi wywołaj metodę przed UseResponseCaching.UseCors

W przypadku routingu punktów końcowych oprogramowanie pośredniczące CORS musi być skonfigurowane do wykonywania między wywołaniami do UseRouting i UseEndpoints.

Zobacz Testowanie mechanizmu CORS , aby uzyskać instrukcje dotyczące testowania kodu podobnego do poprzedniego kodu.

Wywołanie AddCors metody dodaje usługi CORS do kontenera usługi aplikacji:

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

Aby uzyskać więcej informacji, zobacz opcje zasad MECHANIZMU CORS w tym dokumencie.

CorsPolicyBuilder Metody można połączyć łańcuchem, jak pokazano w poniższym kodzie:

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

Uwaga: określony adres URL nie może zawierać ukośnika końcowego (/). Jeśli adres URL zakończy się ciągiem /, porównanie zwróci wartość false i nie zostanie zwrócony żaden nagłówek.

MECHANIZM CORS z domyślnymi zasadami i oprogramowaniem pośredniczącym

Poniższy wyróżniony kod włącza domyślne zasady MECHANIZMU CORS:

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

Powyższy kod stosuje domyślne zasady CORS do wszystkich punktów końcowych kontrolera.

Włączanie mechanizmu Cors z routingiem punktów końcowych

Włączenie mechanizmu CORS dla poszczególnych punktów końcowych przy użyciu RequireCorsnie obsługuje automatycznych żądań wstępnych. Aby uzyskać więcej informacji, zobacz ten problem z usługą GitHub i Przetestuj mechanizm CORS z routingiem punktów końcowych i [HttpOptions].

W przypadku routingu punktu końcowego mechanizm CORS można włączyć dla poszczególnych punktów końcowych przy użyciu RequireCors zestawu metod rozszerzeń:

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

Powyższy kod:

  • app.UseCors włącza oprogramowanie pośredniczące CORS. Ponieważ nie skonfigurowano zasad domyślnych, app.UseCors() sam nie włącza mechanizmu CORS.
  • Punkty /echo końcowe kontrolera i zezwalają na żądania między źródłami przy użyciu określonych zasad.
  • Punkty /echo2 końcowe stron i Razor nie zezwalają na żądania między źródłami, ponieważ nie określono żadnych domyślnych zasad.

Atrybut [DisableCors] nie wyłącza mechanizmu CORS, który został włączony przez routing punktu końcowego za pomocą polecenia RequireCors.

Aby uzyskać instrukcje dotyczące testowania kodu podobnego do poprzedniego, zobacz Testowanie mechanizmu CORS z routingiem punktu końcowego i [HttpOptions ].

Włączanie mechanizmu CORS z atrybutami

Włączenie mechanizmu CORS za pomocą atrybutu [EnableCors] i zastosowanie nazwanych zasad tylko do tych punktów końcowych, które wymagają mechanizmu CORS, zapewnia najlepszą kontrolę.

Atrybut [EnableCors] zapewnia alternatywę dla stosowania mechanizmu CORS globalnie. Atrybut [EnableCors] umożliwia mechanizm CORS dla wybranych punktów końcowych, a nie wszystkich punktów końcowych:

  • [EnableCors] określa zasady domyślne.
  • [EnableCors("{Policy String}")] określa nazwane zasady.

Atrybut [EnableCors] można zastosować do:

  • Razor Strona PageModel
  • Kontroler
  • Metoda akcji kontrolera

Różne zasady można stosować do kontrolerów, modeli stron lub metod akcji za pomocą atrybutu [EnableCors] . [EnableCors] Gdy atrybut jest stosowany do kontrolera, modelu strony lub metody akcji, a mechanizm CORS jest włączony w programie pośredniczącym, stosowane są obie zasady. Zalecamy łączenie zasad. Użyj przycisku [EnableCors]atrybutu lub oprogramowania pośredniczącego, a nie obu w tej samej aplikacji.

Poniższy kod stosuje inne zasady do każdej metody:

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

Poniższy kod tworzy dwie zasady CORS:

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

Aby uzyskać najlepszą kontrolę nad ograniczaniem żądań CORS:

  • Użyj [EnableCors("MyPolicy")] z nazwanymi zasadami.
  • Nie należy definiować zasad domyślnych.
  • Nie używaj routingu punktów końcowych.

Kod w następnej sekcji spełnia poprzednią listę.

Zobacz Testowanie mechanizmu CORS , aby uzyskać instrukcje dotyczące testowania kodu podobnego do poprzedniego kodu.

Wyłączanie mechanizmu CORS

Atrybut [DisableCors] nie wyłącza mechanizmu CORS, który został włączony przez routing punktu końcowego.

Poniższy kod definiuje zasady "MyPolicy"MECHANIZMU CORS:

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

Poniższy kod wyłącza mechanizm CORS dla GetValues2 akcji:

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

}

Powyższy kod ma następujące działanie:

  • Nie włącza mechanizmu CORS z routingiem punktów końcowych.
  • Nie definiuje domyślnych zasad CORS.
  • Używa funkcji [EnableCors("MyPolicy")] w celu włączenia "MyPolicy" zasad CORS dla kontrolera.
  • Wyłącza mechanizm CORS dla GetValues2 metody .

Aby uzyskać instrukcje dotyczące testowania poprzedniego kodu, zobacz Testowanie mechanizmu CORS .

Opcje zasad MECHANIZMU CORS

W tej sekcji opisano różne opcje, które można ustawić w zasadach MECHANIZMU CORS:

AddPolicy jest wywoływana w pliku Startup.ConfigureServices. W przypadku niektórych opcji warto zapoznać się z sekcją Jak działa mechanizm CORS.

Ustawianie dozwolonych źródeł

AllowAnyOrigin: zezwala na żądania CORS ze wszystkich źródeł przy użyciu dowolnego schematu (http lub https). AllowAnyOrigin jest niezabezpieczona, ponieważ każda witryna internetowa może wysyłać żądania między źródłami do aplikacji.

Uwaga

Określanie AllowAnyOrigin i AllowCredentials jest niezabezpieczoną konfiguracją i może spowodować fałszerzowanie żądań między witrynami. Usługa CORS zwraca nieprawidłową odpowiedź CORS, gdy aplikacja jest skonfigurowana przy użyciu obu metod.

AllowAnyOrigin dotyczy żądań wstępnych i nagłówka Access-Control-Allow-Origin . Aby uzyskać więcej informacji, zobacz sekcję Wstępne żądania .

SetIsOriginAllowedToAllowWildcardSubdomains: Ustawia IsOriginAllowed właściwość zasad jako funkcję, która umożliwia źródłom dopasowanie skonfigurowanej domeny wieloznacznych podczas oceny, czy źródło jest dozwolone.

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

Ustawianie dozwolonych metod HTTP

AllowAnyMethod:

  • Zezwala na dowolną metodę HTTP:
  • Wpływa na żądania wstępne i Access-Control-Allow-Methods nagłówek. Aby uzyskać więcej informacji, zobacz sekcję Wstępne żądania .

Ustawianie dozwolonych nagłówków żądań

Aby zezwolić na wysyłanie określonych nagłówków w żądaniu CORS, nazywanym nagłówkami żądań autora, wywołaj WithHeaders i określ dozwolone nagłówki:

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

Aby zezwolić na wszystkie nagłówki żądań autora, wywołaj metodę AllowAnyHeader:

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

AllowAnyHeader dotyczy żądań wstępnych i nagłówka Access-Control-Request-Headers . Aby uzyskać więcej informacji, zobacz sekcję Wstępne żądania .

Zasady oprogramowania pośredniczącego CORS są zgodne z określonymi nagłówkami określonymi przez WithHeaders usługę jest możliwe tylko wtedy, gdy nagłówki wysyłane w Access-Control-Request-Headers formacie dokładnie odpowiadają nagłówkom określonym w elemencie WithHeaders.

Rozważmy na przykład aplikację skonfigurowaną w następujący sposób:

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

Oprogramowanie pośredniczące CORS odrzuca żądanie wstępne z następującym nagłówkiem żądania, ponieważ Content-Language (HeaderNames.ContentLanguage) nie ma na liście :WithHeaders

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

Aplikacja zwraca odpowiedź 200 OK , ale nie wysyła nagłówków CORS z powrotem. W związku z tym przeglądarka nie podejmuje próby żądania między źródłami.

Ustawianie uwidocznionych nagłówków odpowiedzi

Domyślnie przeglądarka nie ujawnia wszystkich nagłówków odpowiedzi aplikacji. Aby uzyskać więcej informacji, zobacz Udostępnianie zasobów między źródłami W3C (terminologia): prosty nagłówek odpowiedzi.

Nagłówki odpowiedzi, które są dostępne domyślnie, to:

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

Specyfikacja MECHANIZMU CORS wywołuje te nagłówki prostych nagłówków odpowiedzi. Aby udostępnić inne nagłówki aplikacji, wywołaj metodę WithExposedHeaders:

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

Poświadczenia w żądaniach między źródłami

Poświadczenia wymagają specjalnej obsługi w żądaniu CORS. Domyślnie przeglądarka nie wysyła poświadczeń z żądaniem między źródłami. Poświadczenia obejmują cookieschematy uwierzytelniania s i HTTP. Aby wysyłać poświadczenia z żądaniem między źródłami, klient musi ustawić wartość XMLHttpRequest.withCredentialstrue.

Bezpośrednie użycie XMLHttpRequest :

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

Korzystanie z zapytania jQuery:

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

Korzystanie z interfejsu API pobierania:

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

Serwer musi zezwalać na poświadczenia. Aby zezwolić na poświadczenia między źródłami, wywołaj metodę AllowCredentials:

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

Odpowiedź HTTP zawiera Access-Control-Allow-Credentials nagłówek, który informuje przeglądarkę, że serwer zezwala na poświadczenia dla żądania między źródłami.

Jeśli przeglądarka wysyła poświadczenia, ale odpowiedź nie zawiera prawidłowego Access-Control-Allow-Credentials nagłówka, przeglądarka nie uwidacznia odpowiedzi na aplikację, a żądanie między źródłami zakończy się niepowodzeniem.

Zezwolenie na poświadczenia między źródłami jest zagrożeniem bezpieczeństwa. Witryna internetowa w innej domenie może wysyłać poświadczenia zalogowanego użytkownika do aplikacji w imieniu użytkownika bez wiedzy użytkownika.

Specyfikacja MECHANIZMU CORS stwierdza również, że ustawienie wartości origins na "*" (wszystkie źródła) jest nieprawidłowe, jeśli Access-Control-Allow-Credentials nagłówek jest obecny.

Żądania wstępne

W przypadku niektórych żądań CORS przeglądarka wysyła dodatkowe żądanie OPTIONS przed wysłaniem rzeczywistego żądania. To żądanie jest nazywane żądaniem wstępnym. Przeglądarka może pominąć żądanie wstępne, jeśli spełnione są wszystkie następujące warunki:

  • Metoda żądania to GET, HEAD lub POST.
  • Aplikacja nie ustawia nagłówków żądań innych niż Accept, , Accept-Language, Content-Language, Content-Typelub Last-Event-ID.
  • Nagłówek Content-Type , jeśli jest ustawiony, ma jedną z następujących wartości:
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

Reguła nagłówków żądań ustawiona dla żądania klienta ma zastosowanie do nagłówków ustawianych przez aplikację przez wywołanie setRequestHeaderXMLHttpRequest obiektu. Specyfikacja MECHANIZMU CORS wywołuje te nagłówki żądań autora. Reguła nie ma zastosowania do nagłówków, które można ustawić w przeglądarce, takich jak User-Agent, Hostlub Content-Length.

Poniżej przedstawiono przykładową odpowiedź podobną do żądania wstępnego wykonanego z przycisku [Put test] w sekcji Test CORS tego dokumentu.

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

Żądanie wstępne używa metody HTTP OPTIONS . Może zawierać następujące nagłówki:

Jeśli żądanie wstępne zostanie odrzucone, aplikacja zwróci 200 OK odpowiedź, ale nie ustawi nagłówków CORS. W związku z tym przeglądarka nie podejmuje próby żądania między źródłami. Aby zapoznać się z przykładem odmowy żądania wstępnego, zobacz sekcję Test CORS tego dokumentu.

Za pomocą narzędzi F12 aplikacja konsolowa wyświetla błąd podobny do jednego z następujących, w zależności od przeglądarki:

  • Firefox: Żądanie między źródłami zablokowane: Te same zasady pochodzenia nie zezwalają na odczytywanie zasobu zdalnego pod adresem https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5. (Przyczyna: żądanie CORS nie powiodło się). Dowiedz się więcej
  • Oparty na chromium: dostęp do pobierania z źródła "https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5https://cors3.azurewebsites.net" został zablokowany przez zasady CORS: Odpowiedź na żądanie wstępne nie przekazuje kontroli dostępu: Brak nagłówka "Access-Control-Allow-Origin" dla żądanego zasobu. Jeśli nieprzezroczysta odpowiedź spełnia Twoje potrzeby, ustaw tryb żądania na wartość "no-cors", aby pobrać zasób z wyłączonym mechanizmem CORS.

Aby zezwolić na określone nagłówki, wywołaj metodę WithHeaders:

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

Aby zezwolić na wszystkie nagłówki żądań autora, wywołaj metodę AllowAnyHeader:

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

Przeglądarki nie są spójne w sposobie ustawiania .Access-Control-Request-Headers Jeśli:

  • Nagłówki są ustawione na inne niż "*"
  • AllowAnyHeader jest wywoływany: uwzględnij co najmniej Accept, Content-Typei Origin, oraz wszelkie nagłówki niestandardowe, które mają być obsługiwane.

Kod automatycznego żądania wstępnego

Po zastosowaniu zasad CORS:

  • Globalnie przez wywołanie metody app.UseCors w pliku Startup.Configure.
  • Za pomocą atrybutu [EnableCors] .

ASP.NET Core odpowiada na żądanie OPCJE wstępne.

Włączenie mechanizmu CORS dla poszczególnych punktów końcowych przy użyciu RequireCors obecnie nie obsługuje automatycznych żądań wstępnych.

W sekcji Test CORS tego dokumentu pokazano to zachowanie.

[HttpOptions] atrybut dla żądań wstępnych

Gdy mechanizm CORS jest włączony z odpowiednimi zasadami, ASP.NET Core zwykle odpowiada na żądania wstępne CORS. W niektórych scenariuszach może to nie być możliwe. Na przykład użycie mechanizmu CORS z routingiem punktów końcowych.

Poniższy kod używa atrybutu [HttpOptions] do tworzenia punktów końcowych dla żądań OPTIONS:

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

Aby uzyskać instrukcje dotyczące testowania poprzedniego kodu, zobacz Testowanie mechanizmu CORS przy użyciu routingu punktu końcowego i [HttpOptions ].

Ustawianie czasu wygaśnięcia przedlotu

Nagłówek Access-Control-Max-Age określa, jak długo można buforować odpowiedź na żądanie wstępne. Aby ustawić ten nagłówek, wywołaj metodę SetPreflightMaxAge:

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

Jak działa mechanizm CORS

W tej sekcji opisano, co dzieje się w żądaniu CORS na poziomie komunikatów HTTP.

  • MECHANIZM CORS nie jest funkcją zabezpieczeń. CORS to standard W3C, który umożliwia serwerowi złagodzenie zasad tego samego źródła.
    • Na przykład złośliwy aktor może użyć skryptów między witrynami (XSS) w witrynie i wykonać żądanie obejmujące wiele witryn do witryny obsługującej mechanizm CORS w celu kradzieży informacji.
  • Interfejs API nie jest bezpieczniejszy, zezwalając na mechanizm CORS.
    • Do klienta (przeglądarki) należy wymuszenie mechanizmu CORS. Serwer wykonuje żądanie i zwraca odpowiedź— klient zwraca błąd i blokuje odpowiedź. Na przykład dowolne z następujących narzędzi wyświetli odpowiedź serwera:
  • Jest to sposób na serwer, aby umożliwić przeglądarkom wykonywanie między źródłami żądania XHR lub Fetch API , które w przeciwnym razie byłoby zabronione.
    • Przeglądarki bez mechanizmu CORS nie mogą wykonywać żądań między źródłami. Przed corsem JSONP został użyty do obejścia tego ograniczenia. JSONP nie używa XHR, używa tagu <script> do odbierania odpowiedzi. Skrypty mogą być ładowane między źródłami.

Specyfikacja MECHANIZMU CORS wprowadziła kilka nowych nagłówków HTTP, które umożliwiają żądania między źródłami. Jeśli przeglądarka obsługuje mechanizm CORS, automatycznie ustawia te nagłówki dla żądań między źródłami. Niestandardowy kod JavaScript nie jest wymagany do włączenia mechanizmu CORS.

Przycisk TEST PUT w wdrożonej próbce

Poniżej przedstawiono przykład żądania między źródłami z przycisku Test wartości do https://cors1.azurewebsites.net/api/values. Nagłówek Origin :

  • Udostępnia domenę lokacji wysyłającej żądanie.
  • Jest wymagany i musi być inny niż host.

Nagłówki ogólne

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

Nagłówki odpowiedzi

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

Nagłówki żądań

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 ...

W OPTIONS żądaniach serwer ustawia nagłówek NagłówkiAccess-Control-Allow-Origin: {allowed origin} odpowiedzi w odpowiedzi. Na przykład wdrożone przykładowe żądanie przycisku OPTIONS Usuń [EnableCors] zawiera następujące nagłówki:

Nagłówki ogólne

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

Nagłówki odpowiedzi

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

Nagłówki żądań

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

W poprzednich nagłówkach Odpowiedzi serwer ustawia nagłówek Access-Control-Allow-Origin w odpowiedzi. Wartość https://cors1.azurewebsites.net tego nagłówka odpowiada nagłówkowi Origin z żądania.

Jeśli AllowAnyOrigin parametr jest wywoływany, zwracana jest wartość z symbolem Access-Control-Allow-Origin: *wieloznacznymi. AllowAnyOrigin zezwala na dowolne źródło.

Jeśli odpowiedź nie zawiera nagłówka Access-Control-Allow-Origin , żądanie między źródłami zakończy się niepowodzeniem. W szczególności przeglądarka nie zezwala na żądanie. Nawet jeśli serwer zwróci pomyślną odpowiedź, przeglądarka nie udostępni odpowiedzi aplikacji klienckiej.

Wyświetlanie żądań OPTIONS

Domyślnie przeglądarki Chrome i Edge nie wyświetlają żądań OPTIONS na karcie sieci narzędzi F12. Aby wyświetlić żądania OPTIONS w następujących przeglądarkach:

  • chrome://flags/#out-of-blink-cors lub edge://flags/#out-of-blink-cors
  • wyłącz flagę.
  • Ponownie uruchomić.

Przeglądarka Firefox domyślnie wyświetla żądania OPTIONS.

Mechanizm CORS w usługach IIS

Podczas wdrażania w usługach IIS mechanizm CORS musi działać przed uwierzytelnianiem systemu Windows, jeśli serwer nie jest skonfigurowany do zezwalania na dostęp anonimowy. Aby obsługiwać ten scenariusz, moduł CORS usług IIS musi zostać zainstalowany i skonfigurowany dla aplikacji.

Testowanie mechanizmu CORS

Przykładowy plik do pobrania zawiera kod do testowania mechanizmu CORS. Zobacz , jak pobrać. Przykład jest projektem interfejsu API z dodanymi stronami Razor :

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

Ostrzeżenie

WithOrigins("https://localhost:<port>");należy używać tylko do testowania przykładowej aplikacji podobnej do przykładowego kodu pobierania.

Poniżej przedstawiono ValuesController punkty końcowe do testowania:

[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 jest dostarczany przez pakiet NuGet Rick.Docs.Samples.RouteInfo i wyświetla informacje o trasie.

Przetestuj poprzedni przykładowy kod przy użyciu jednego z następujących metod:

  • Użyj wdrożonej przykładowej aplikacji pod adresem https://cors3.azurewebsites.net/. Nie ma potrzeby pobierania przykładu.
  • Uruchom przykład przy dotnet run użyciu domyślnego adresu URL .https://localhost:5001
  • Uruchom przykład z programu Visual Studio z portem ustawionym na 44398 jako adres URL https://localhost:44398.

Za pomocą przeglądarki z narzędziami F12:

  • Wybierz przycisk Wartości i przejrzyj nagłówki na karcie Sieć.

  • Wybierz przycisk TEST PUT. Zobacz Wyświetlanie żądań OPTIONS, aby uzyskać instrukcje dotyczące wyświetlania żądania OPTIONS. Test PUT tworzy dwa żądania, żądanie wstępne OPTIONS i żądanie PUT.

  • Wybierz przycisk, GetValues2 [DisableCors] aby wyzwolić nieudane żądanie CORS. Jak wspomniano w dokumencie, odpowiedź zwraca 200 powodzenia, ale żądanie CORS nie jest wykonywane. Wybierz kartę Konsola, aby wyświetlić błąd CORS. W zależności od przeglądarki zostanie wyświetlony błąd podobny do następującego:

    Dostęp do pobierania 'https://cors1.azurewebsites.net/api/values/GetValues2' z źródła 'https://cors3.azurewebsites.net' został zablokowany przez zasady CORS: w żądanym zasobie nie ma nagłówka "Access-Control-Allow-Origin". Jeśli nieprzezroczysta odpowiedź spełnia Twoje potrzeby, ustaw tryb żądania na wartość "no-cors", aby pobrać zasób z wyłączonym mechanizmem CORS.

Punkty końcowe z obsługą mechanizmu CORS można przetestować za pomocą narzędzia, takiego jak curl lub Fiddler. W przypadku korzystania z narzędzia źródło żądania określonego przez Origin nagłówek musi się różnić od hosta odbierającego żądanie. Jeśli żądanie nie jest źródłem krzyżowym na podstawie wartości nagłówka Origin :

  • Nie ma potrzeby przetwarzania żądania przez oprogramowanie pośredniczące CORS.
  • Nagłówki CORS nie są zwracane w odpowiedzi.

Następujące polecenie używa curl polecenia , aby wysłać żądanie OPTIONS z informacjami:

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

Testowanie mechanizmu CORS przy użyciu routingu punktu końcowego i [HttpOptions]

Włączenie mechanizmu CORS dla poszczególnych punktów końcowych przy użyciu RequireCors obecnie nie obsługuje automatycznych żądań wstępnych. Rozważmy następujący kod, który używa routingu punktu końcowego w celu włączenia mechanizmu CORS:

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

Poniżej przedstawiono TodoItems1Controller punkty końcowe do testowania:

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

Przetestuj powyższy kod ze strony testowej wdrożonego przykładu.

Przyciski Usuń [EnableCors] i GET [EnableCors] kończą się powodzeniem, ponieważ punkty końcowe mają [EnableCors] żądania wstępne i odpowiadają na nie. Inne punkty końcowe kończą się niepowodzeniem. Przycisk GET kończy się niepowodzeniem, ponieważ skrypt JavaScript wysyła:

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

Poniższe informacje TodoItems2Controller zawierają podobne punkty końcowe, ale zawierają jawny kod, który odpowiada na żądania OPTIONS:

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

Przetestuj powyższy kod ze strony testowej wdrożonego przykładu. Z listy rozwijanej Kontroler wybierz pozycję Wstępne, a następnie pozycję Ustaw kontroler. Wszystkie wywołania CORS do punktów końcowych kończą się powodzeniem TodoItems2Controller .

Dodatkowe zasoby