Povolit požadavky z různých zdrojů (CORS) v ASP.NET Core

Note

Toto není nejnovější verze tohoto článku. Aktuální verzi najdete ve verzi .NET 10 tohoto článku.

Warning

Tato verze ASP.NET Core se už nepodporuje. Další informace najdete v zásadách podpory .NET a .NET Core. Aktuální verzi najdete ve verzi .NET 10 tohoto článku.

Autoři: Rick Anderson a Kirk Larkin

Tento článek ukazuje, jak v aplikaci ASP.NET Core povolit sdílení mezi různýmizdrojiprostředků (CORS).

Zabezpečení prohlížeče zabraňuje tomu, aby webová stránka odesílala požadavky do jiné domény, než je ta, která webovou stránku obsluhuje. Toto omezení se označuje jako zásada stejného zdroje. Zásada stejného zdroje brání škodlivým webům ve čtení citlivých dat z jiných webů. Někdy můžete chtít povolit jiným webům odesílat do vaší aplikace požadavky z jiného původu. Další informace naleznete v článku Mozilla CORS.

Sdílení prostředků mezi zdroji původu (CORS):

  • Je to standard W3C, který umožňuje serveru zmírnit politiku stejného původu.
  • Nejedná se o bezpečnostní funkci, CORS oslabuje zabezpečení. Rozhraní API není bezpečnější jen proto, že povoluje CORS. Další informace najdete v tématu Jak CORS funguje.
  • Umožňuje serveru explicitně povolit některé požadavky mezi zdroji a zároveň odmítnout jiné.
  • Je bezpečnější a flexibilnější než dřívější techniky, například JSONP.

Zobrazení nebo stažení ukázkového kódu (postup stažení)

Stejný původ

Dvě adresy URL mají stejný původ, pokud mají stejná schémata, hostitele a porty (RFC 6454).

Tyto dvě adresy URL mají stejný původ:

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

Tyto adresy URL mají jiný původ než předchozí dvě adresy URL:

  • https://example.net: Jiná doména
  • https://contoso.example.com/foo.html: Jiná subdoména
  • http://example.com/foo.html: Jiné schéma
  • https://example.com:9000/foo.html: Jiný port

Povolit CORS

CORS můžete povolit třemi způsoby:

Použití atributu [EnableCors] s pojmenovanou zásadou poskytuje nejlepší kontrolu v omezení koncových bodů, které podporují CORS.

Warning

UseCors musí být volána ve správném pořadí. Další informace najdete v tématu Pořadí middlewaru. Například UseCors musí být volána před UseResponseCaching při použití UseResponseCaching.

Každý přístup je podrobně popsaný v následujících částech.

CORS s pojmenovanými zásadami a middlewarem

Middleware CORS zpracovává požadavky z různých zdrojů. Následující kód použije zásadu CORS pro všechny koncové body aplikace se zadanými zdroji:

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

Předchozí kód:

Při směrování koncových bodů musí být middleware CORS nakonfigurován tak, aby se spouštěl mezi volánímiUseRouting a UseEndpoints.

Volání metody AddCors přidá služby CORS do kontejneru služeb aplikace:

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

Další informace najdete v tématu Možnosti zásad CORS v tomto dokumentu.

Metody CorsPolicyBuilder mohou být zřetězeny, jak je znázorněno v následujícím kódu:

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

Poznámka: Zadaná adresa URL nesmí obsahovat koncové lomítko (/). Pokud adresa URL končí na /, porovnání vrátí false a nevrátí se žádné záhlaví.

Pořadí UseCors a UseStaticFiles

Obvykle se UseStaticFiles volá před UseCors. Aplikace, které používají JavaScript k načítání statických souborů z jiného webu, musí volat UseCors před UseStaticFiles.

CORS s výchozími zásadami a middlewarem

Následující zvýrazněný kód povolí výchozí zásady 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();

Předchozí kód použije výchozí zásady CORS pro všechny koncové body kontroleru.

Povolte CORS pomocí směrování koncových bodů

Pomocí směrování koncového bodu je možné CORS povolit pro jednotlivé koncové body pomocí RequireCors sady rozšiřujících metod:

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

V předchozím kódu:

  • app.UseCors povolí middleware CORS. Protože není nakonfigurovaná výchozí politika, samotné app.UseCors() CORS nepovolí.
  • Koncové body /echo a kontroleru umožňují požadavky z různých zdrojů podle zadaných zásad.
  • Koncové body stránek /echo2 a Razorneumožňují požadavky z různých zdrojů, protože nebyla zadána žádná výchozí zásada.

Atribut [DisableCors] nezakazujeCORS, které bylo povoleno směrováním koncového bodu s RequireCors.

Pokyny k testování kódu podobného předchozímu kódu najdete v části Test CORS s atributem [EnableCors] a metodou RequireCors.

Povolit CORS pomocí atributů

Povolení CORS pomocí atributu [EnableCors] a použití pojmenované zásady pouze na koncové body, které vyžadují CORS, poskytuje nejlepší kontrolu.

Atribut [EnableCors] poskytuje alternativu k použití CORS globálně. Tento [EnableCors] atribut umožňuje CORS pro vybrané koncové body, nikoli pro všechny koncové body:

  • [EnableCors] určuje výchozí zásadu.
  • [EnableCors("{Policy String}")] určuje pojmenovanou zásadu.

Atribut [EnableCors] lze použít na:

  • Razor Stránka PageModel
  • Controller
  • Metoda akce kontroleru

U kontrolerů, modelů stránek nebo metod akcí s atributem [EnableCors] je možné použít různé zásady. [EnableCors] Když se atribut použije u kontroleru, modelu stránky nebo metody akce a CORS je v middlewaru povolený, použijí se obě zásady. Nedoporučujeme kombinovat zásady. Použijte [EnableCors] atribut nebo middleware, ne oba ve stejné aplikaci.

Následující kód použije pro každou metodu jinou zásadu:

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

Následující kód vytvoří dvě zásady 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();

Pro co nejpřesnější kontrolu omezení požadavků CORS:

Kód v další části odpovídá předchozímu seznamu.

Zakázání CORS

Atribut [DisableCors] nezakazujeCORS, které bylo povoleno směrováním koncového bodu.

Následující kód definuje zásadu "MyPolicy"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();

Následující kód zakáže CORS pro GetValues2 akci:

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

}

Předchozí kód:

Pokyny k testování předchozího kódu najdete v části Test CORS .

Možnosti zásad CORS

Tato část popisuje různé možnosti, které je možné nastavit v zásadách CORS:

AddPolicy je voláno v Program.cs. U některých možností může být užitečné nejprve přečíst část Jak CORS funguje .

Nastavení povolených zdrojů

AllowAnyOrigin: Umožňuje požadavky CORS ze všech zdrojů s jakýmkoli schématem (http nebo https). AllowAnyOrigin není zabezpečená, protože jakýkoli web může na aplikaci odesílat cross-origin požadavky.

Warning

Zadání AllowAnyOrigin a AllowCredentials představuje nezabezpečenou konfiguraci a může vést k padělání požadavků mezi weby. Služba CORS vrátí neplatnou odpověď CORS, když je aplikace nakonfigurovaná s oběma metodami. Obejití předdefinovaných kontrol pomocí SetIsOriginAllowed(_ => true) společně s AllowCredentials je také nezabezpečená konfigurace.

AllowAnyOrigin ovlivňuje předběžné požadavky a hlavičku Access-Control-Allow-Origin . Další informace najdete v části Předběžné požadavky .

SetIsOriginAllowedToAllowWildcardSubdomains: Nastaví IsOriginAllowed vlastnost zásady na funkci, která umožňuje, aby zdroje odpovídaly nakonfigurované zástupné doméně při vyhodnocování, zda je původ povolený.

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

V předchozím kódu je SetIsOriginAllowedToAllowWildcardSubdomains volána se zástupným znakem domény "https://*.example.com". Toto nastavení umožňuje CORS žádosti z jakékoli subdomény example.com, jako https://subdomain.example.com nebo https://api.example.com. Zástupný znak * musí být zahrnut v původu, aby umožnil porovnávání subdomén pomocí zástupných znaků.

Nastavení povolených metod HTTP

AllowAnyMethod:

  • Povoluje libovolnou metodu HTTP:
  • Ovlivňuje předběžné požadavky a hlavičku Access-Control-Allow-Methods . Další informace najdete v části Předběžné požadavky .

Nastavení hlaviček povolených požadavků

Chcete-li povolit odesílání konkrétních hlaviček v požadavku CORS, označovaných jako hlavičky požadavku autora, zavolejte WithHeaders a zadejte povolené hlavičky:

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

Pokud chcete povolit všechna záhlaví žádosti autora, zavolejte 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 ovlivňuje preflight požadavky a hlavičku Access-Control-Request-Headers. Další informace najdete v části Předběžné požadavky .

Shoda zásady middlewaru CORS s konkrétními hlavičkami zadanými pomocí WithHeaders je možná pouze tehdy, když hlavičky odeslané v Access-Control-Request-Headers přesně odpovídají hlavičkám uvedeným v WithHeaders.

Představte si například aplikaci nakonfigurovanou takto:

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

Middleware CORS odmítne předběžný požadavek s následující hlavičkou požadavku, protože Content-Language (HeaderNames.ContentLanguage) není uvedený v WithHeaders:

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

Aplikace vrátí 204 No Content odpověď, ale neodesílá hlavičky CORS zpět. Prohlížeč se proto nepokouší o požadavek na jiný původ.

Nastavení vystavených hlaviček odpovědí

Ve výchozím nastavení prohlížeč nezpřístupňuje do aplikace všechny hlavičky odpovědi. Další informace najdete v tématu Sdílení prostředků mezi různými zdroji W3C (terminologie): jednoduchá hlavička odpovědi.

Hlavičky odpovědi, které jsou ve výchozím nastavení k dispozici, jsou:

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

Specifikace CORS tyto hlavičky označuje jako jednoduché hlavičky odpovědi. Pokud chcete aplikaci zpřístupnit další hlavičky, zavolejte 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();

Přihlašovací údaje v požadavcích mezi zdroji

Přihlašovací údaje vyžadují speciální zpracování v požadavku CORS. Ve výchozím nastavení prohlížeč neodesílá přihlašovací údaje s požadavkem z jiného původu. Přihlašovací údaje zahrnují soubory cookie a schémata ověřování HTTP. Chcete-li odeslat přihlašovací údaje s požadavkem mezi zdroji, musí klient nastavit XMLHttpRequest.withCredentials na hodnotu true.

Přímé použití XMLHttpRequest :

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

Pomocí jQuery:

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

Použití rozhraní Fetch API:

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

Server musí přihlašovací údaje povolit. Chcete-li povolit pověření pro různé zdroje, zavolejte 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();

Odpověď HTTP obsahuje hlavičku Access-Control-Allow-Credentials , která prohlížeči říká, že server povoluje přihlašovací údaje pro požadavek mezi zdroji.

Pokud prohlížeč odešle přihlašovací údaje, ale odpověď neobsahuje platnou Access-Control-Allow-Credentials hlavičku, prohlížeč nezobrazí odpověď aplikaci a požadavek mezi zdroji selže.

Povolení přihlašovacích údajů mezi různými zdroji představuje bezpečnostní riziko. Web v jiné doméně může odeslat přihlašovací údaje přihlášeného uživatele do aplikace jménem uživatele bez vědomí uživatele.

Specifikace CORS také uvádí, že nastavení původu na "*" (všechny zdroje) je neplatné, pokud je hlavička Access-Control-Allow-Credentials přítomna.

Preflightové požadavky

U některých požadavků CORS prohlížeč před provedením skutečného požadavku odešle další požadavek OPTIONS . Tento požadavek se nazývá předběžný požadavek. Prohlížeč může předběžný požadavek přeskočit, pokud jsou splněny všechny následující podmínky:

  • Metoda požadavku je GET, HEAD nebo POST.
  • Aplikace nenastavuje jiné hlavičky požadavků než Accept, Accept-Language, Content-Language, , Content-Typenebo Last-Event-ID.
  • Hlavička Content-Type , pokud je nastavená, má jednu z následujících hodnot:
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

Pravidlo hlavičky požadavku nastavené pro požadavek klienta se vztahuje na hlavičky, které aplikace nastaví voláním setRequestHeader objektu XMLHttpRequest . Specifikace CORS označuje tyto hlavičky jako hlavičky požadavku autora. Pravidlo se nevztahuje na hlavičky, které může prohlížeč nastavit, například User-Agent, Hostnebo Content-Length.

Note

Tento článek obsahuje adresy URL vytvořené nasazením ukázkového kódu na dva weby https://cors3.azurewebsites.net Azure a https://cors.azurewebsites.net.

Následuje příklad odpovědi podobné předběžnému požadavku vytvořenému z tlačítka [Put test] v části Test CORS tohoto 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

Předběžný požadavek používá metodu HTTP OPTIONS . Může obsahovat následující hlavičky:

Pokud je preflight požadavek zamítnut, aplikace vrátí odpověď 204 No Content, ale nenastaví hlavičky CORS. Prohlížeč se proto nepokouší o požadavek na jiný původ. Příklad zamítnutého preflightového požadavku najdete v části Test CORS tohoto dokumentu.

Pomocí nástrojů F12 konzolová aplikace zobrazí v závislosti na prohlížeči chybu podobnou jedné z následujících možností:

  • Firefox: Požadavek mezi různými zdroji byl zablokován: Zásada stejného původu nepovoluje přístup ke vzdálenému prostředku na adrese https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5. (Důvod: Požadavek CORS nebyl úspěšný). Zjistit více
  • Založeno na Chromiu: Přístup k načtení na adrese 'https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5' z původu 'https://cors3.azurewebsites.net' byl zablokován zásadami CORS: Odpověď na předběžný požadavek neprošla kontrolou řízení přístupu: v požadovaném prostředku není přítomna žádná hlavička 'Access-Control-Allow-Origin'. Pokud vám vyhovuje neprůhledná odpověď, nastavte režim požadavku na 'no-cors' pro načtení prostředku s vypnutým CORS.

Pokud chcete povolit konkrétní záhlaví, zavolejte 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();

Pokud chcete povolit všechna záhlaví žádosti autora, zavolejte 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();

Prohlížeče nejsou konzistentní ve způsobu jejich nastavení Access-Control-Request-Headers. Pokud máte některou z těchto:

  • Záhlaví jsou nastavená na cokoli jiného než "*"
  • AllowAnyHeader se nazývá: Zahrňte alespoň Accept, Content-Type a Origin a všechny vlastní hlavičky, které chcete podporovat.

Automatický předletový kód požadavku

Pokud se použije zásada CORS:

  • Globálně voláním app.UseCors v Program.cs.
  • Použití atributu [EnableCors]

ASP.NET Core odpovídá na předběžný dotaz OPTIONS.

Toto chování ukazuje část Test CORS tohoto dokumentu.

Atribut [HttpOptions] pro předběžné požadavky

Když je CORS povolená s příslušnými zásadami, ASP.NET Core obvykle automaticky reaguje na předběžné požadavky CORS.

Následující kód používá atribut [HttpOptions] k vytvoření koncových bodů pro požadavky 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);
    }

Pokyny k testování předchozího kódu najdete v části Test CORS s atributem [EnableCors] a metodou RequireCors.

Nastavení doby předběžného vypršení platnosti

Hlavička Access-Control-Max-Age určuje, jak dlouho může být odpověď na předběžný požadavek uložena do mezipaměti. Chcete-li nastavit toto záhlaví, zavolejte 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();

Povolte CORS na koncovém bodu

Jak CORS funguje

Tato část popisuje, co se stane v požadavku CORS na úrovni zpráv HTTP.

  • CORS není bezpečnostní funkce. CORS je standard W3C, který umožňuje serveru uvolnit zásady stejného původu.
    • Například by škodlivý útočník mohl proti vašemu webu použít Cross-Site Scripting (XSS) a odeslat požadavek mezi weby na svůj web s povoleným CORS, aby odcizil informace.
  • API není bezpečnější tím, že umožňuje CORS.
    • Je na klientovi (prohlížeči), aby vynucoval CORS. Server spustí požadavek a vrátí odpověď. Je to klient, který vrací chybu a blokuje odpověď. Například některý z následujících nástrojů zobrazí odpověď serveru:
  • Je to způsob, jak server umožňuje prohlížečům provést požadavek XHR nebo Fetch API z jiné domény, který by jinak byl zakázán.
    • Prohlížeče bez CORS nemůžou provádět žádosti mezi zdroji. Před CORS se k obejití tohoto omezení použil JSONP . JSONP nepoužívá XHR, k přijetí odpovědi používá <script> značku. Skripty je povoleno načítat z jiného původu.

Specifikace CORS zavedla několik nových hlaviček HTTP, které umožňují požadavky mezi zdroji. Pokud prohlížeč podporuje CORS, nastaví tato záhlaví automaticky u požadavků z jiného původu. K povolení CORS se nevyžaduje vlastní javascriptový kód.

Následuje příklad požadavku mezi různými zdroji z testovacího tlačítka Values do https://cors1.azurewebsites.net/api/values. Hlavička Origin :

  • Poskytuje doménu webu, který odesílá požadavek.
  • Vyžaduje se a musí se lišit od hostitele.

Obecné hlavičky

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

Hlavičky odpovědi

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

Hlavičky požadavků

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

V požadavcích OPTIONS server v odpovědi nastaví hlavičku Response headersAccess-Control-Allow-Origin: {allowed origin}. Například v ukázkovém kódu Delete [EnableCors] obsahuje požadavek na tlačítko OPTIONS následující hlavičky:

Obecné hlavičky

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

Hlavičky odpovědi

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

Hlavičky požadavků

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

V předchozích hlavičkách odpovědi server v odpovědi nastaví hlavičku Access-Control-Allow-Origin. Hodnota https://cors1.azurewebsites.net této hlavičky odpovídá Origin hlavičce požadavku.

Pokud je zavoláno AllowAnyOrigin, vrátí se Access-Control-Allow-Origin: *, zástupná hodnota. AllowAnyOrigin umožňuje jakýkoli původ.

Pokud odpověď neobsahuje hlavičku Access-Control-Allow-Origin, požadavek mezi různými zdroji selže. Konkrétně prohlížeč požadavek zakáže. I když server vrátí úspěšnou odpověď, prohlížeč nepřístupní odpověď klientské aplikaci.

Přesměrování z HTTP na HTTPS způsobuje chybu ERR_INVALID_REDIRECT u předběžného požadavku CORS.

Požadavky na koncový bod používající HTTP, které UseHttpsRedirection přesměruje na HTTPS, selžou s chybou ERR_INVALID_REDIRECT on the CORS preflight request.

Projekty API mohou odmítat požadavky HTTP namísto použití UseHttpsRedirection k přesměrování požadavků na HTTPS.

CORS ve službě IIS

Při nasazování do služby IIS musí CORS běžet před ověřováním systému Windows, pokud server není nakonfigurovaný tak, aby povoloval anonymní přístup. Pro podporu tohoto scénáře je potřeba nainstalovat a nakonfigurovat modul CORS služby IIS pro aplikaci.

Testování CORS

Ukázkový soubor ke stažení obsahuje kód pro testování CORS. Podívejte se, jak stahovat. Ukázka je projekt rozhraní API s přidanými stránkami 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();

Warning

WithOrigins("https://localhost:<port>"); lze použít pouze k testování ukázkové aplikace podobné jako ukázkový kód ke stažení.

Note

Pokud používáte launchSettings.json v sadě Visual Studio nebo konfigurujete nastavení ladění jazyka C# ve VS Code a k místnímu ladění používáte službu IIS Express, ujistěte se, že jste nakonfigurovali službu IIS Express pro "anonymousAuthentication": true. Pokud je "anonymousAuthentication" nastaveno na false, hostitel webového prostředí ASP.NET Core neuvidí žádné předběžné dotazy. Konkrétně pokud používáte ověřování NTLM ("windowsAuthentication": true), prvním krokem výzvy NTLM je odeslání webového prohlížeče a výzvy 401, což může usnadnit ověření správné konfigurace předletové trasy.

ValuesController Následující text uvádí koncové body pro testování:

[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 poskytuje balíček NuGet Rick.Docs.Samples.RouteInfo a zobrazí informace o trase.

Otestujte předchozí vzorový kód pomocí jednoho z následujících přístupů:

  • Spusťte ukázku pomocí dotnet run s výchozí adresou URL https://localhost:5001.
  • Spusťte ukázku ze sady Visual Studio s portem nastaveným na 44398 pro adresu URL souboru https://localhost:44398.

Použití prohlížeče s nástroji F12:

  • Vyberte tlačítko Hodnoty a zkontrolujte záhlaví na kartě Síť.

  • Vyberte tlačítko PUT test. Pokyny k zobrazení požadavku OPTIONS najdete v části Zobrazení MOŽNOSTÍ . Test PUT vytvoří dva požadavky, předběžný požadavek OPTIONS a požadavek PUT.

  • GetValues2 [DisableCors] Výběrem tlačítka aktivujte neúspěšný požadavek CORS. Jak je uvedeno v dokumentaci, odpověď vrátí stavový kód 200 (OK), ale požadavek CORS se neodešle. Vyberte kartu Konzola a zobrazte chybu CORS. V závislosti na prohlížeči se zobrazí chyba podobná této:

    Zásady CORS blokovaly přístup k načtení 'https://cors1.azurewebsites.net/api/values/GetValues2' z zdroje 'https://cors3.azurewebsites.net' : U požadovaného prostředku není k dispozici žádná hlavička Access-Control-Allow-Origin. Pokud vám vyhovuje neprůhledná odpověď, nastavte režim požadavku na 'no-cors' pro načtení prostředku s vypnutým CORS.

Koncové body s povoleným CORS lze testovat pomocí nástrojů, jako jsou curl nebo Fiddler. Při použití nástroje se původ požadavku určeného Origin hlavičkou musí lišit od hostitele, který požadavek přijímá. Pokud požadavek není na základě hodnoty hlavičky považován za Origin:

  • Není nutné, aby middleware CORS zpracovával požadavek.
  • Hlavičky CORS nejsou v odpovědi vráceny.

Následující příkaz používá curl k vydání požadavku OPTIONS s informacemi:

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

Testování CORS s atributem [EnableCors] a metodou RequireCors

Zvažte následující kód, který používá směrování koncových bodů k povolení CORS na základě jednotlivých koncových bodů pomocí 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();

Všimněte si, že pouze koncový bod /echo používá RequireCors k povolení požadavků z různých zdrojů pomocí zadané zásady. Následující kontrolery povolují CORS pomocí atributu [EnableCors].

Následující TodoItems1Controller poskytuje koncové body pro testování:

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

Tlačítka Delete [EnableCors] a GET [EnableCors] jsou úspěšná, protože koncové body mají [EnableCors] a reagují na předběžné požadavky. Ostatní koncové body selžou. Tlačítko GET selže, protože JavaScript odesílá:

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

Následující TodoItems2Controller poskytuje podobné endpointy, ale obsahuje explicitní kód pro zpracování požadavků 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);
}

Předchozí kód je možné otestovat nasazením ukázky do Azure. V rozevíracím seznamu Kontroler vyberte Preflight a potom Nastavit kontroler. Všechna volání CORS do TodoItems2Controller koncových bodů jsou úspěšná.

Dodatečné zdroje

Autoři: Rick Anderson a Kirk Larkin

Tento článek ukazuje, jak povolit CORS v aplikaci ASP.NET Core.

Zabezpečení prohlížeče zabraňuje tomu, aby webová stránka odesílala požadavky do jiné domény, než je ta, která webovou stránku obsluhuje. Toto omezení se označuje jako zásada stejného zdroje. Zásada stejného zdroje brání škodlivým webům ve čtení citlivých dat z jiných webů. Někdy můžete chtít povolit jiným webům odesílat do vaší aplikace požadavky z jiného původu. Další informace naleznete v článku Mozilla CORS.

Sdílení prostředků mezi zdroji původu (CORS):

  • Je to standard W3C, který umožňuje serveru zmírnit politiku stejného původu.
  • Nejedná se o bezpečnostní funkci, CORS oslabuje zabezpečení. Rozhraní API není bezpečnější jen proto, že povoluje CORS. Další informace najdete v tématu Jak CORS funguje.
  • Umožňuje serveru explicitně povolit některé požadavky mezi zdroji a zároveň odmítnout jiné.
  • Je bezpečnější a flexibilnější než dřívější techniky, například JSONP.

Zobrazení nebo stažení ukázkového kódu (postup stažení)

Stejný původ

Dvě adresy URL mají stejný původ, pokud mají stejná schémata, hostitele a porty (RFC 6454).

Tyto dvě adresy URL mají stejný původ:

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

Tyto adresy URL mají jiný původ než předchozí dvě adresy URL:

  • https://example.net: Jiná doména
  • https://www.example.com/foo.html: Jiná subdoména
  • http://example.com/foo.html: Jiné schéma
  • https://example.com:9000/foo.html: Jiný port

Povolit CORS

CORS můžete povolit třemi způsoby:

Použití atributu [EnableCors] s pojmenovanou zásadou poskytuje nejlepší kontrolu v omezení koncových bodů, které podporují CORS.

Warning

UseCors musí být volána ve správném pořadí. Další informace najdete v tématu Pořadí middlewaru. Například UseCors musí být volána před UseResponseCaching při použití UseResponseCaching.

Každý přístup je podrobně popsaný v následujících částech.

CORS s pojmenovanými zásadami a middlewarem

Middleware CORS zpracovává požadavky z různých zdrojů. Následující kód použije zásadu CORS pro všechny koncové body aplikace se zadanými zdroji:

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

Předchozí kód:

Při směrování koncových bodů musí být middleware CORS nakonfigurován tak, aby se spouštěl mezi volánímiUseRouting a UseEndpoints.

Volání metody AddCors přidá služby CORS do kontejneru služeb aplikace:

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

Další informace najdete v tématu Možnosti zásad CORS v tomto dokumentu.

Metody CorsPolicyBuilder mohou být zřetězeny, jak je znázorněno v následujícím kódu:

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

Poznámka: Zadaná adresa URL nesmí obsahovat koncové lomítko (/). Pokud adresa URL končí na /, porovnání vrátí false a nevrátí se žádné záhlaví.

Warning

UseCors musí být umístěn za UseRouting a před UseAuthorization. To zajistí, aby hlavičky CORS byly zahrnuty do odpovědi pro autorizovaná i neautorizovaná volání.

Pořadí UseCors a UseStaticFiles

Obvykle se UseStaticFiles volá před UseCors. Aplikace, které používají JavaScript k načítání statických souborů z jiného webu, musí volat UseCors před UseStaticFiles.

CORS s výchozími zásadami a middlewarem

Následující zvýrazněný kód povolí výchozí zásady 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();

Předchozí kód použije výchozí zásady CORS pro všechny koncové body kontroleru.

Povolte CORS pomocí směrování koncových bodů

Pomocí směrování koncového bodu je možné CORS povolit pro jednotlivé koncové body pomocí RequireCors sady rozšiřujících metod:

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

V předchozím kódu:

  • app.UseCors povolí middleware CORS. Protože není nakonfigurovaná výchozí politika, samotné app.UseCors() CORS nepovolí.
  • Koncové body /echo a kontroleru umožňují požadavky z různých zdrojů podle zadaných zásad.
  • Koncové body stránek /echo2 a Razorneumožňují požadavky z různých zdrojů, protože nebyla zadána žádná výchozí zásada.

Atribut [DisableCors] nezakazujeCORS, které bylo povoleno směrováním koncového bodu s RequireCors.

V .NET 7 musí být atributu [EnableCors] předán parametr, jinak se kvůli nejednoznačné shodě trasy vygeneruje upozornění ASP0023. .NET 8 nebo novější negeneruje ASP0023 upozornění.

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

Pokyny k testování kódu podobného předchozímu kódu najdete v části Test CORS s atributem [EnableCors] a metodou RequireCors.

Povolit CORS pomocí atributů

Povolení CORS pomocí atributu [EnableCors] a použití pojmenované zásady pouze na koncové body, které vyžadují CORS, poskytuje nejlepší kontrolu.

Atribut [EnableCors] poskytuje alternativu k použití CORS globálně. Tento [EnableCors] atribut umožňuje CORS pro vybrané koncové body, nikoli pro všechny koncové body:

  • [EnableCors] určuje výchozí zásadu.
  • [EnableCors("{Policy String}")] určuje pojmenovanou zásadu.

Atribut [EnableCors] lze použít na:

  • Razor Stránka PageModel
  • Controller
  • Metoda akce kontroleru

U kontrolerů, modelů stránek nebo metod akcí s atributem [EnableCors] je možné použít různé zásady. [EnableCors] Když se atribut použije u kontroleru, modelu stránky nebo metody akce a CORS je v middlewaru povolený, použijí se obě zásady. Nedoporučujeme kombinovat zásady. Použijte [EnableCors] atribut nebo middleware, ne oba ve stejné aplikaci.

Následující kód použije pro každou metodu jinou zásadu:

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

Následující kód vytvoří dvě zásady 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();

Pro co nejpřesnější kontrolu omezení požadavků CORS:

Kód v další části odpovídá předchozímu seznamu.

Zakázání CORS

Atribut [DisableCors] nezakazujeCORS, které bylo povoleno směrováním koncového bodu.

Následující kód definuje zásadu "MyPolicy"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();

Následující kód zakáže CORS pro GetValues2 akci:

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

}

Předchozí kód:

Pokyny k testování předchozího kódu najdete v části Test CORS .

Možnosti zásad CORS

Tato část popisuje různé možnosti, které je možné nastavit v zásadách CORS:

AddPolicy je voláno v Program.cs. U některých možností může být užitečné nejprve přečíst část Jak CORS funguje .

Nastavení povolených zdrojů

AllowAnyOrigin: Umožňuje požadavky CORS ze všech zdrojů s jakýmkoli schématem (http nebo https). AllowAnyOrigin není zabezpečená, protože jakýkoli web může na aplikaci odesílat cross-origin požadavky.

Note

Zadání AllowAnyOrigin a AllowCredentials představuje nezabezpečenou konfiguraci a může vést k padělání požadavků mezi weby. Služba CORS vrátí neplatnou odpověď CORS, když je aplikace nakonfigurovaná s oběma metodami.

AllowAnyOrigin ovlivňuje předběžné požadavky a hlavičku Access-Control-Allow-Origin . Další informace najdete v části Předběžné požadavky .

SetIsOriginAllowedToAllowWildcardSubdomains: Nastaví IsOriginAllowed vlastnost zásady na funkci, která umožňuje, aby zdroje odpovídaly nakonfigurované zástupné doméně při vyhodnocování, zda je původ povolený.

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

V předchozím kódu je SetIsOriginAllowedToAllowWildcardSubdomains volána se zástupným znakem domény "https://*.example.com". Toto nastavení umožňuje CORS žádosti z jakékoli subdomény example.com, jako https://subdomain.example.com nebo https://api.example.com. Zástupný znak * musí být zahrnut v původu, aby umožnil porovnávání subdomén pomocí zástupných znaků.

Nastavení povolených metod HTTP

AllowAnyMethod:

  • Povoluje libovolnou metodu HTTP:
  • Ovlivňuje předběžné požadavky a hlavičku Access-Control-Allow-Methods . Další informace najdete v části Předběžné požadavky .

Nastavení hlaviček povolených požadavků

Chcete-li povolit odesílání konkrétních hlaviček v požadavku CORS, označovaných jako hlavičky požadavku autora, zavolejte WithHeaders a zadejte povolené hlavičky:

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

Pokud chcete povolit všechna záhlaví žádosti autora, zavolejte 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 ovlivňuje preflight požadavky a hlavičku Access-Control-Request-Headers. Další informace najdete v části Předběžné požadavky .

Shoda zásady middlewaru CORS s konkrétními hlavičkami zadanými pomocí WithHeaders je možná pouze tehdy, když hlavičky odeslané v Access-Control-Request-Headers přesně odpovídají hlavičkám uvedeným v WithHeaders.

Představte si například aplikaci nakonfigurovanou takto:

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

Middleware CORS odmítne předběžný požadavek s následující hlavičkou požadavku, protože Content-Language (HeaderNames.ContentLanguage) není uvedený v WithHeaders:

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

Aplikace vrátí odpověď 200 OK , ale neodesílá hlavičky CORS zpět. Prohlížeč se proto nepokouší o požadavek na jiný původ.

Nastavení vystavených hlaviček odpovědí

Ve výchozím nastavení prohlížeč nezpřístupňuje do aplikace všechny hlavičky odpovědi. Další informace najdete v tématu Sdílení prostředků mezi různými zdroji W3C (terminologie): jednoduchá hlavička odpovědi.

Hlavičky odpovědi, které jsou ve výchozím nastavení k dispozici, jsou:

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

Specifikace CORS tyto hlavičky označuje jako jednoduché hlavičky odpovědi. Pokud chcete aplikaci zpřístupnit další hlavičky, zavolejte 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();

Přihlašovací údaje v požadavcích mezi zdroji

Přihlašovací údaje vyžadují speciální zpracování v požadavku CORS. Ve výchozím nastavení prohlížeč neodesílá přihlašovací údaje s požadavkem z jiného původu. Přihlašovací údaje zahrnují soubory cookie a schémata ověřování HTTP. Chcete-li odeslat přihlašovací údaje s požadavkem mezi zdroji, musí klient nastavit XMLHttpRequest.withCredentials na hodnotu true.

Přímé použití XMLHttpRequest :

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

Pomocí jQuery:

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

Použití rozhraní Fetch API:

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

Server musí přihlašovací údaje povolit. Chcete-li povolit pověření pro různé zdroje, zavolejte 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();

Odpověď HTTP obsahuje hlavičku Access-Control-Allow-Credentials , která prohlížeči říká, že server povoluje přihlašovací údaje pro požadavek mezi zdroji.

Pokud prohlížeč odešle přihlašovací údaje, ale odpověď neobsahuje platnou Access-Control-Allow-Credentials hlavičku, prohlížeč nezobrazí odpověď aplikaci a požadavek mezi zdroji selže.

Povolení přihlašovacích údajů mezi různými zdroji představuje bezpečnostní riziko. Web v jiné doméně může odeslat přihlašovací údaje přihlášeného uživatele do aplikace jménem uživatele bez vědomí uživatele.

Specifikace CORS také uvádí, že nastavení původu na "*" (všechny zdroje) je neplatné, pokud je hlavička Access-Control-Allow-Credentials přítomna.

Preflightové požadavky

U některých požadavků CORS prohlížeč před provedením skutečného požadavku odešle další požadavek OPTIONS . Tento požadavek se nazývá předběžný požadavek. Prohlížeč může předběžný požadavek přeskočit, pokud jsou splněny všechny následující podmínky:

  • Metoda požadavku je GET, HEAD nebo POST.
  • Aplikace nenastavuje jiné hlavičky požadavků než Accept, Accept-Language, Content-Language, , Content-Typenebo Last-Event-ID.
  • Hlavička Content-Type , pokud je nastavená, má jednu z následujících hodnot:
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

Pravidlo hlavičky požadavku nastavené pro požadavek klienta se vztahuje na hlavičky, které aplikace nastaví voláním setRequestHeader objektu XMLHttpRequest . Specifikace CORS označuje tyto hlavičky jako hlavičky požadavku autora. Pravidlo se nevztahuje na hlavičky, které může prohlížeč nastavit, například User-Agent, Hostnebo Content-Length.

Následuje příklad odpovědi podobné předběžnému požadavku vytvořenému z tlačítka [Put test] v části Test CORS tohoto 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

Předběžný požadavek používá metodu HTTP OPTIONS . Může obsahovat následující hlavičky:

Pokud je preflight požadavek zamítnut, aplikace vrátí odpověď 200 OK, ale nenastaví hlavičky CORS. Prohlížeč se proto nepokouší o požadavek na jiný původ. Příklad zamítnutého preflightového požadavku najdete v části Test CORS tohoto dokumentu.

Pomocí nástrojů F12 konzolová aplikace zobrazí v závislosti na prohlížeči chybu podobnou jedné z následujících možností:

  • Firefox: Požadavek mezi různými zdroji byl zablokován: Zásada stejného původu nepovoluje přístup ke vzdálenému prostředku na adrese https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5. (Důvod: Požadavek CORS nebyl úspěšný). Zjistit více
  • Založeno na Chromiu: Přístup k načtení na adrese 'https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5' z původu 'https://cors3.azurewebsites.net' byl zablokován zásadami CORS: Odpověď na předběžný požadavek neprošla kontrolou řízení přístupu: v požadovaném prostředku není přítomna žádná hlavička 'Access-Control-Allow-Origin'. Pokud vám vyhovuje neprůhledná odpověď, nastavte režim požadavku na 'no-cors' pro načtení prostředku s vypnutým CORS.

Pokud chcete povolit konkrétní záhlaví, zavolejte 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();

Pokud chcete povolit všechna záhlaví žádosti autora, zavolejte 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();

Prohlížeče nejsou konzistentní ve způsobu jejich nastavení Access-Control-Request-Headers. Pokud máte některou z těchto:

  • Záhlaví jsou nastavená na cokoli jiného než "*"
  • AllowAnyHeader se nazývá: Zahrňte alespoň Accept, Content-Type a Origin a všechny vlastní hlavičky, které chcete podporovat.

Automatický předletový kód požadavku

Pokud se použije zásada CORS:

  • Globálně voláním app.UseCors v Program.cs.
  • Použití atributu [EnableCors]

ASP.NET Core odpovídá na předběžný dotaz OPTIONS.

Toto chování ukazuje část Test CORS tohoto dokumentu.

Atribut [HttpOptions] pro předběžné požadavky

Když je CORS povolená s příslušnými zásadami, ASP.NET Core obvykle automaticky reaguje na předběžné požadavky CORS.

Následující kód používá atribut [HttpOptions] k vytvoření koncových bodů pro požadavky 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);
    }

Pokyny k testování předchozího kódu najdete v části Test CORS s atributem [EnableCors] a metodou RequireCors.

Nastavení doby předběžného vypršení platnosti

Hlavička Access-Control-Max-Age určuje, jak dlouho může být odpověď na předběžný požadavek uložena do mezipaměti. Chcete-li nastavit toto záhlaví, zavolejte 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();

Povolte CORS na koncovém bodu

Jak CORS funguje

Tato část popisuje, co se stane v požadavku CORS na úrovni zpráv HTTP.

  • CORS není bezpečnostní funkce. CORS je standard W3C, který umožňuje serveru uvolnit zásady stejného původu.
    • Například by škodlivý útočník mohl proti vašemu webu použít Cross-Site Scripting (XSS) a odeslat požadavek mezi weby na svůj web s povoleným CORS, aby odcizil informace.
  • API není bezpečnější tím, že umožňuje CORS.
    • Je na klientovi (prohlížeči), aby vynucoval CORS. Server spustí požadavek a vrátí odpověď. Je to klient, který vrací chybu a blokuje odpověď. Například některý z následujících nástrojů zobrazí odpověď serveru:
  • Je to způsob, jak server umožňuje prohlížečům provést požadavek XHR nebo Fetch API z jiné domény, který by jinak byl zakázán.
    • Prohlížeče bez CORS nemůžou provádět žádosti mezi zdroji. Před CORS se k obejití tohoto omezení použil JSONP . JSONP nepoužívá XHR, k přijetí odpovědi používá <script> značku. Skripty je povoleno načítat z jiného původu.

Specifikace CORS zavedla několik nových hlaviček HTTP, které umožňují požadavky mezi zdroji. Pokud prohlížeč podporuje CORS, nastaví tato záhlaví automaticky u požadavků z jiného původu. K povolení CORS se nevyžaduje vlastní javascriptový kód.

V nasazené ukázce vyberte testovací tlačítko PUT. Hlavička Origin :

  • Poskytuje doménu webu, který odesílá požadavek.
  • Vyžaduje se a musí se lišit od hostitele.

Obecné hlavičky

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

Hlavičky odpovědi

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

Hlavičky požadavků

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

V požadavcích OPTIONS server v odpovědi nastaví hlavičku Response headersAccess-Control-Allow-Origin: {allowed origin}. Například v ukázkovém kódu Delete [EnableCors] obsahuje požadavek na tlačítko OPTIONS následující hlavičky:

Obecné hlavičky

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

Hlavičky odpovědi

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

Hlavičky požadavků

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

V předchozích hlavičkách odpovědi server v odpovědi nastaví hlavičku Access-Control-Allow-Origin. Hodnota https://cors1.azurewebsites.net této hlavičky odpovídá Origin hlavičce požadavku.

Pokud je zavoláno AllowAnyOrigin, vrátí se Access-Control-Allow-Origin: *, zástupná hodnota. AllowAnyOrigin umožňuje jakýkoli původ.

Pokud odpověď neobsahuje hlavičku Access-Control-Allow-Origin, požadavek mezi různými zdroji selže. Konkrétně prohlížeč požadavek zakáže. I když server vrátí úspěšnou odpověď, prohlížeč nepřístupní odpověď klientské aplikaci.

Přesměrování z HTTP na HTTPS způsobuje chybu ERR_INVALID_REDIRECT u předběžného požadavku CORS.

Požadavky na koncový bod používající HTTP, které UseHttpsRedirection přesměruje na HTTPS, selžou s chybou ERR_INVALID_REDIRECT on the CORS preflight request.

Projekty API mohou odmítat požadavky HTTP namísto použití UseHttpsRedirection k přesměrování požadavků na HTTPS.

CORS ve službě IIS

Při nasazování do služby IIS musí CORS běžet před ověřováním systému Windows, pokud server není nakonfigurovaný tak, aby povoloval anonymní přístup. Pro podporu tohoto scénáře je potřeba nainstalovat a nakonfigurovat modul CORS služby IIS pro aplikaci.

Testování CORS

Ukázkový soubor ke stažení obsahuje kód pro testování CORS. Podívejte se, jak stahovat. Ukázka je projekt rozhraní API s přidanými stránkami 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();

Warning

WithOrigins("https://localhost:<port>"); lze použít pouze k testování ukázkové aplikace podobné jako ukázkový kód ke stažení.

ValuesController Následující text uvádí koncové body pro testování:

[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 poskytuje balíček NuGet Rick.Docs.Samples.RouteInfo a zobrazí informace o trase.

Otestujte předchozí vzorový kód pomocí jednoho z následujících přístupů:

  • Spusťte ukázku pomocí dotnet run s výchozí adresou URL https://localhost:5001.
  • Spusťte ukázku ze sady Visual Studio s portem nastaveným na 44398 pro adresu URL souboru https://localhost:44398.

Použití prohlížeče s nástroji F12:

  • Vyberte tlačítko Hodnoty a zkontrolujte záhlaví na kartě Síť.

  • Vyberte tlačítko PUT test. Pokyny k zobrazení požadavku OPTIONS najdete v části Zobrazení MOŽNOSTÍ . Test PUT vytvoří dva požadavky, předběžný požadavek OPTIONS a požadavek PUT.

  • GetValues2 [DisableCors] Výběrem tlačítka aktivujte neúspěšný požadavek CORS. Jak je uvedeno v dokumentaci, odpověď vrátí stavový kód 200 (OK), ale požadavek CORS se neodešle. Vyberte kartu Konzola a zobrazte chybu CORS. V závislosti na prohlížeči se zobrazí chyba podobná této:

    Zásady CORS blokovaly přístup k načtení 'https://cors1.azurewebsites.net/api/values/GetValues2' z zdroje 'https://cors3.azurewebsites.net' : U požadovaného prostředku není k dispozici žádná hlavička Access-Control-Allow-Origin. Pokud vám vyhovuje neprůhledná odpověď, nastavte režim požadavku na 'no-cors' pro načtení prostředku s vypnutým CORS.

Koncové body s povoleným CORS lze testovat pomocí nástrojů, jako jsou curl nebo Fiddler. Při použití nástroje se původ požadavku určeného Origin hlavičkou musí lišit od hostitele, který požadavek přijímá. Pokud požadavek není na základě hodnoty hlavičky považován za Origin:

  • Není nutné, aby middleware CORS zpracovával požadavek.
  • Hlavičky CORS nejsou v odpovědi vráceny.

Následující příkaz používá curl k vydání požadavku OPTIONS s informacemi:

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

Testování CORS s atributem [EnableCors] a metodou RequireCors

Zvažte následující kód, který používá směrování koncových bodů k povolení CORS na základě jednotlivých koncových bodů pomocí 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();

Všimněte si, že pouze koncový bod /echo používá RequireCors k povolení požadavků z různých zdrojů pomocí zadané zásady. Následující kontrolery povolují CORS pomocí atributu [EnableCors].

Následující TodoItems1Controller poskytuje koncové body pro testování:

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

Tlačítka Delete [EnableCors] a GET [EnableCors] jsou úspěšná, protože koncové body mají [EnableCors] a reagují na předběžné požadavky. Ostatní koncové body selžou. Tlačítko GET selže, protože JavaScript odesílá:

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

Následující TodoItems2Controller poskytuje podobné endpointy, ale obsahuje explicitní kód pro zpracování požadavků 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);
}

Předchozí kód lze otestovat nasazením ukázky do Azure. V rozevíracím seznamu Controller vyberte Preflight a potom Set Controller. Všechna volání CORS do TodoItems2Controller koncových bodů jsou úspěšná.

Dodatečné zdroje

Autoři: Rick Anderson a Kirk Larkin

Tento článek ukazuje, jak povolit CORS v aplikaci ASP.NET Core.

Zabezpečení prohlížeče zabraňuje tomu, aby webová stránka odesílala požadavky do jiné domény, než je ta, která webovou stránku obsluhuje. Toto omezení se označuje jako zásada stejného zdroje. Zásada stejného zdroje brání škodlivým webům ve čtení citlivých dat z jiných webů. Někdy můžete chtít povolit jiným webům odesílat do vaší aplikace požadavky z jiného původu. Další informace naleznete v článku Mozilla CORS.

Sdílení prostředků mezi zdroji původu (CORS):

  • Je to standard W3C, který umožňuje serveru zmírnit politiku stejného původu.
  • Nejedná se o bezpečnostní funkci, CORS oslabuje zabezpečení. Rozhraní API není bezpečnější jen proto, že povoluje CORS. Další informace najdete v tématu Jak CORS funguje.
  • Umožňuje serveru explicitně povolit některé požadavky mezi zdroji a zároveň odmítnout jiné.
  • Je bezpečnější a flexibilnější než dřívější techniky, například JSONP.

Zobrazení nebo stažení ukázkového kódu (postup stažení)

Stejný původ

Dvě adresy URL mají stejný původ, pokud mají stejná schémata, hostitele a porty (RFC 6454).

Tyto dvě adresy URL mají stejný původ:

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

Tyto adresy URL mají jiný původ než předchozí dvě adresy URL:

  • https://example.net: Jiná doména
  • https://www.example.com/foo.html: Jiná subdoména
  • http://example.com/foo.html: Jiné schéma
  • https://example.com:9000/foo.html: Jiný port

Povolit CORS

CORS můžete povolit třemi způsoby:

Použití atributu [EnableCors] s pojmenovanou zásadou poskytuje nejlepší kontrolu v omezení koncových bodů, které podporují CORS.

Warning

UseCors musí být volána ve správném pořadí. Další informace najdete v tématu Pořadí middlewaru. Například UseCors musí být volána před UseResponseCaching při použití UseResponseCaching.

Každý přístup je podrobně popsaný v následujících částech.

CORS s pojmenovanými zásadami a middlewarem

Middleware CORS zpracovává požadavky z různých zdrojů. Následující kód použije zásadu CORS pro všechny koncové body aplikace se zadanými zdroji:

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

Předchozí kód:

Při směrování koncových bodů musí být middleware CORS nakonfigurován tak, aby se spouštěl mezi volánímiUseRouting a UseEndpoints.

Volání metody AddCors přidá služby CORS do kontejneru služeb aplikace:

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

Další informace najdete v tématu Možnosti zásad CORS v tomto dokumentu.

Metody CorsPolicyBuilder mohou být zřetězeny, jak je znázorněno v následujícím kódu:

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

Poznámka: Zadaná adresa URL nesmí obsahovat koncové lomítko (/). Pokud adresa URL končí na /, porovnání vrátí false a nevrátí se žádné záhlaví.

Warning

UseCors musí být umístěn za UseRouting a před UseAuthorization. To zajistí, aby hlavičky CORS byly zahrnuty do odpovědi pro autorizovaná i neautorizovaná volání.

Pořadí UseCors a UseStaticFiles

Obvykle se UseStaticFiles volá před UseCors. Aplikace, které používají JavaScript k načítání statických souborů z jiného webu, musí volat UseCors před UseStaticFiles.

CORS s výchozími zásadami a middlewarem

Následující zvýrazněný kód povolí výchozí zásady 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();

Předchozí kód použije výchozí zásady CORS pro všechny koncové body kontroleru.

Povolte CORS pomocí směrování koncových bodů

Povolení CORS pro jednotlivé koncové body pomocí RequireCorsnepodporuje automatické požadavky preflight. Další informace najdete v tomto problému na GitHubu a Test CORS se směrováním koncových bodů a [HttpOptions].

Pomocí směrování koncového bodu je možné CORS povolit pro jednotlivé koncové body pomocí RequireCors sady rozšiřujících metod:

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

V předchozím kódu:

  • app.UseCors povolí middleware CORS. Protože není nakonfigurovaná výchozí politika, samotné app.UseCors() CORS nepovolí.
  • Koncové body /echo a kontroleru umožňují požadavky z různých zdrojů podle zadaných zásad.
  • Koncové body stránek /echo2 a Razorneumožňují požadavky z různých zdrojů, protože nebyla zadána žádná výchozí zásada.

Atribut [DisableCors] nezakazujeCORS, které bylo povoleno směrováním koncového bodu s RequireCors.

Pokyny k testování kódu podobného předchozímu kódu najdete v části Test CORS se směrováním koncových bodů a [HttpOptions].

Povolit CORS pomocí atributů

Povolení CORS pomocí atributu [EnableCors] a použití pojmenované zásady pouze na koncové body, které vyžadují CORS, poskytuje nejlepší kontrolu.

Atribut [EnableCors] poskytuje alternativu k použití CORS globálně. Tento [EnableCors] atribut umožňuje CORS pro vybrané koncové body, nikoli pro všechny koncové body:

  • [EnableCors] určuje výchozí zásadu.
  • [EnableCors("{Policy String}")] určuje pojmenovanou zásadu.

Atribut [EnableCors] lze použít na:

  • Razor Stránka PageModel
  • Controller
  • Metoda akce kontroleru

U kontrolerů, modelů stránek nebo metod akcí s atributem [EnableCors] je možné použít různé zásady. [EnableCors] Když se atribut použije u kontroleru, modelu stránky nebo metody akce a CORS je v middlewaru povolený, použijí se obě zásady. Nedoporučujeme kombinovat zásady. Použijte [EnableCors] atribut nebo middleware, ne oba ve stejné aplikaci.

Následující kód použije pro každou metodu jinou zásadu:

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

Následující kód vytvoří dvě zásady 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();

Pro co nejpřesnější kontrolu omezení požadavků CORS:

Kód v další části odpovídá předchozímu seznamu.

Zakázání CORS

Atribut [DisableCors] nezakazujeCORS, které bylo povoleno směrováním koncového bodu.

Následující kód definuje zásadu "MyPolicy"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();

Následující kód zakáže CORS pro GetValues2 akci:

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

}

Předchozí kód:

Pokyny k testování předchozího kódu najdete v části Test CORS .

Možnosti zásad CORS

Tato část popisuje různé možnosti, které je možné nastavit v zásadách CORS:

AddPolicy je voláno v Program.cs. U některých možností může být užitečné nejprve přečíst část Jak CORS funguje .

Nastavení povolených zdrojů

AllowAnyOrigin: Umožňuje požadavky CORS ze všech zdrojů s jakýmkoli schématem (http nebo https). AllowAnyOrigin není zabezpečená, protože jakýkoli web může na aplikaci odesílat cross-origin požadavky.

Note

Zadání AllowAnyOrigin a AllowCredentials představuje nezabezpečenou konfiguraci a může vést k padělání požadavků mezi weby. Služba CORS vrátí neplatnou odpověď CORS, když je aplikace nakonfigurovaná s oběma metodami.

AllowAnyOrigin ovlivňuje předběžné požadavky a hlavičku Access-Control-Allow-Origin . Další informace najdete v části Předběžné požadavky .

SetIsOriginAllowedToAllowWildcardSubdomains: Nastaví IsOriginAllowed vlastnost zásady na funkci, která umožňuje, aby zdroje odpovídaly nakonfigurované zástupné doméně při vyhodnocování, zda je původ povolený.

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

V předchozím kódu je SetIsOriginAllowedToAllowWildcardSubdomains volána se zástupným znakem domény "https://*.example.com". Toto nastavení umožňuje CORS žádosti z jakékoli subdomény example.com, jako https://subdomain.example.com nebo https://api.example.com. Zástupný znak * musí být zahrnut v původu, aby umožnil porovnávání subdomén pomocí zástupných znaků.

Nastavení povolených metod HTTP

AllowAnyMethod:

  • Povoluje libovolnou metodu HTTP:
  • Ovlivňuje předběžné požadavky a hlavičku Access-Control-Allow-Methods . Další informace najdete v části Předběžné požadavky .

Nastavení hlaviček povolených požadavků

Chcete-li povolit odesílání konkrétních hlaviček v požadavku CORS, označovaných jako hlavičky požadavku autora, zavolejte WithHeaders a zadejte povolené hlavičky:

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

Pokud chcete povolit všechna záhlaví žádosti autora, zavolejte 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 ovlivňuje preflight požadavky a hlavičku Access-Control-Request-Headers. Další informace najdete v části Předběžné požadavky .

Shoda zásady middlewaru CORS s konkrétními hlavičkami zadanými pomocí WithHeaders je možná pouze tehdy, když hlavičky odeslané v Access-Control-Request-Headers přesně odpovídají hlavičkám uvedeným v WithHeaders.

Představte si například aplikaci nakonfigurovanou takto:

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

Middleware CORS odmítne předběžný požadavek s následující hlavičkou požadavku, protože Content-Language (HeaderNames.ContentLanguage) není uvedený v WithHeaders:

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

Aplikace vrátí odpověď 200 OK , ale neodesílá hlavičky CORS zpět. Prohlížeč se proto nepokouší o požadavek na jiný původ.

Nastavení vystavených hlaviček odpovědí

Ve výchozím nastavení prohlížeč nezpřístupňuje do aplikace všechny hlavičky odpovědi. Další informace najdete v tématu Sdílení prostředků mezi různými zdroji W3C (terminologie): jednoduchá hlavička odpovědi.

Hlavičky odpovědi, které jsou ve výchozím nastavení k dispozici, jsou:

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

Specifikace CORS tyto hlavičky označuje jako jednoduché hlavičky odpovědi. Pokud chcete aplikaci zpřístupnit další hlavičky, zavolejte 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();

Přihlašovací údaje v požadavcích mezi zdroji

Přihlašovací údaje vyžadují speciální zpracování v požadavku CORS. Ve výchozím nastavení prohlížeč neodesílá přihlašovací údaje s požadavkem z jiného původu. Přihlašovací údaje zahrnují soubory cookie a schémata ověřování HTTP. Chcete-li odeslat přihlašovací údaje s požadavkem mezi zdroji, musí klient nastavit XMLHttpRequest.withCredentials na hodnotu true.

Přímé použití XMLHttpRequest :

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

Pomocí jQuery:

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

Použití rozhraní Fetch API:

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

Server musí přihlašovací údaje povolit. Chcete-li povolit pověření pro různé zdroje, zavolejte 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();

Odpověď HTTP obsahuje hlavičku Access-Control-Allow-Credentials , která prohlížeči říká, že server povoluje přihlašovací údaje pro požadavek mezi zdroji.

Pokud prohlížeč odešle přihlašovací údaje, ale odpověď neobsahuje platnou Access-Control-Allow-Credentials hlavičku, prohlížeč nezobrazí odpověď aplikaci a požadavek mezi zdroji selže.

Povolení přihlašovacích údajů mezi různými zdroji představuje bezpečnostní riziko. Web v jiné doméně může odeslat přihlašovací údaje přihlášeného uživatele do aplikace jménem uživatele bez vědomí uživatele.

Specifikace CORS také uvádí, že nastavení původu na "*" (všechny zdroje) je neplatné, pokud je hlavička Access-Control-Allow-Credentials přítomna.

Preflightové požadavky

U některých požadavků CORS prohlížeč před provedením skutečného požadavku odešle další požadavek OPTIONS . Tento požadavek se nazývá předběžný požadavek. Prohlížeč může předběžný požadavek přeskočit, pokud jsou splněny všechny následující podmínky:

  • Metoda požadavku je GET, HEAD nebo POST.
  • Aplikace nenastavuje jiné hlavičky požadavků než Accept, Accept-Language, Content-Language, , Content-Typenebo Last-Event-ID.
  • Hlavička Content-Type , pokud je nastavená, má jednu z následujících hodnot:
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

Pravidlo hlavičky požadavku nastavené pro požadavek klienta se vztahuje na hlavičky, které aplikace nastaví voláním setRequestHeader objektu XMLHttpRequest . Specifikace CORS označuje tyto hlavičky jako hlavičky požadavku autora. Pravidlo se nevztahuje na hlavičky, které může prohlížeč nastavit, například User-Agent, Hostnebo Content-Length.

Následuje příklad odpovědi podobné předběžnému požadavku vytvořenému z tlačítka [Put test] v části Test CORS tohoto 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

Předběžný požadavek používá metodu HTTP OPTIONS . Může obsahovat následující hlavičky:

Pokud je preflight požadavek zamítnut, aplikace vrátí odpověď 200 OK, ale nenastaví hlavičky CORS. Prohlížeč se proto nepokouší o požadavek na jiný původ. Příklad zamítnutého preflightového požadavku najdete v části Test CORS tohoto dokumentu.

Pomocí nástrojů F12 konzolová aplikace zobrazí v závislosti na prohlížeči chybu podobnou jedné z následujících možností:

  • Firefox: Požadavek mezi různými zdroji byl zablokován: Zásada stejného původu nepovoluje přístup ke vzdálenému prostředku na adrese https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5. (Důvod: Požadavek CORS nebyl úspěšný). Zjistit více
  • Založeno na Chromiu: Přístup k načtení na adrese 'https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5' z původu 'https://cors3.azurewebsites.net' byl zablokován zásadami CORS: Odpověď na předběžný požadavek neprošla kontrolou řízení přístupu: v požadovaném prostředku není přítomna žádná hlavička 'Access-Control-Allow-Origin'. Pokud vám vyhovuje neprůhledná odpověď, nastavte režim požadavku na 'no-cors' pro načtení prostředku s vypnutým CORS.

Pokud chcete povolit konkrétní záhlaví, zavolejte 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();

Pokud chcete povolit všechna záhlaví žádosti autora, zavolejte 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();

Prohlížeče nejsou konzistentní ve způsobu jejich nastavení Access-Control-Request-Headers. Pokud máte některou z těchto:

  • Záhlaví jsou nastavená na cokoli jiného než "*"
  • AllowAnyHeader se nazývá: Zahrňte alespoň Accept, Content-Type a Origin a všechny vlastní hlavičky, které chcete podporovat.

Automatický předletový kód požadavku

Pokud se použije zásada CORS:

  • Globálně voláním app.UseCors v Program.cs.
  • Použití atributu [EnableCors]

ASP.NET Core odpovídá na předběžný dotaz OPTIONS.

Povolení CORS pro jednotlivé endpointy pomocí RequireCors aktuálně nepodporuje automatické požadavky preflight.

Toto chování ukazuje část Test CORS tohoto dokumentu.

Atribut [HttpOptions] pro předběžné požadavky

Když je CORS povolená s příslušnými zásadami, ASP.NET Core obvykle automaticky reaguje na předběžné požadavky CORS. V některých scénářích to nemusí být tento případ. Například použití CORS se směrováním koncových bodů.

Následující kód používá atribut [HttpOptions] k vytvoření koncových bodů pro požadavky 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);
    }

Pokyny k otestování předchozího kódu najdete v tématu Testování CORS se směrováním koncových bodů a [HttpOptions].

Nastavení doby předběžného vypršení platnosti

Hlavička Access-Control-Max-Age určuje, jak dlouho může být odpověď na předběžný požadavek uložena do mezipaměti. Chcete-li nastavit toto záhlaví, zavolejte 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 CORS funguje

Tato část popisuje, co se stane v požadavku CORS na úrovni zpráv HTTP.

  • CORS není bezpečnostní funkce. CORS je standard W3C, který umožňuje serveru uvolnit zásady stejného původu.
    • Například by škodlivý útočník mohl proti vašemu webu použít Cross-Site Scripting (XSS) a odeslat požadavek mezi weby na svůj web s povoleným CORS, aby odcizil informace.
  • API není bezpečnější tím, že umožňuje CORS.
    • Je na klientovi (prohlížeči), aby vynucoval CORS. Server spustí požadavek a vrátí odpověď. Je to klient, který vrací chybu a blokuje odpověď. Například některý z následujících nástrojů zobrazí odpověď serveru:
  • Je to způsob, jak server umožňuje prohlížečům provést požadavek XHR nebo Fetch API z jiné domény, který by jinak byl zakázán.
    • Prohlížeče bez CORS nemůžou provádět žádosti mezi zdroji. Před CORS se k obejití tohoto omezení použil JSONP . JSONP nepoužívá XHR, k přijetí odpovědi používá <script> značku. Skripty je povoleno načítat z jiného původu.

Specifikace CORS zavedla několik nových hlaviček HTTP, které umožňují požadavky mezi zdroji. Pokud prohlížeč podporuje CORS, nastaví tato záhlaví automaticky u požadavků z jiného původu. K povolení CORS se nevyžaduje vlastní javascriptový kód.

Následuje příklad požadavku mezi různými zdroji z testovacího tlačítka Values do https://cors1.azurewebsites.net/api/values. Hlavička Origin :

  • Poskytuje doménu webu, který odesílá požadavek.
  • Vyžaduje se a musí se lišit od hostitele.

Obecné hlavičky

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

Hlavičky odpovědi

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

Hlavičky požadavků

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

V požadavcích OPTIONS server v odpovědi nastaví hlavičku Response headersAccess-Control-Allow-Origin: {allowed origin}. Například požadavek pro tlačítko Odstranit v nasazeném OPTIONS obsahuje následující hlavičky:

Obecné hlavičky

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

Hlavičky odpovědi

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

Hlavičky požadavků

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

V předchozích hlavičkách odpovědi server v odpovědi nastaví hlavičku Access-Control-Allow-Origin. Hodnota https://cors1.azurewebsites.net této hlavičky odpovídá Origin hlavičce požadavku.

Pokud je zavoláno AllowAnyOrigin, vrátí se Access-Control-Allow-Origin: *, zástupná hodnota. AllowAnyOrigin umožňuje jakýkoli původ.

Pokud odpověď neobsahuje hlavičku Access-Control-Allow-Origin, požadavek mezi různými zdroji selže. Konkrétně prohlížeč požadavek zakáže. I když server vrátí úspěšnou odpověď, prohlížeč nepřístupní odpověď klientské aplikaci.

Přesměrování z HTTP na HTTPS způsobuje chybu ERR_INVALID_REDIRECT u předběžného požadavku CORS.

Požadavky na koncový bod používající HTTP, které UseHttpsRedirection přesměruje na HTTPS, selžou s chybou ERR_INVALID_REDIRECT on the CORS preflight request.

Projekty API mohou odmítat požadavky HTTP namísto použití UseHttpsRedirection k přesměrování požadavků na HTTPS.

Zobrazit požadavky OPTIONS

Ve výchozím nastavení prohlížeče Chrome a Edge nezobrazují požadavky OPTIONS na kartě sítě nástrojů F12. Zobrazení požadavků OPTIONS v těchto prohlížečích:

  • chrome://flags/#out-of-blink-cors nebo edge://flags/#out-of-blink-cors
  • zakažte příznak.
  • restart.

Firefox ve výchozím nastavení zobrazuje požadavky OPTIONS.

CORS ve službě IIS

Při nasazování do služby IIS musí CORS běžet před ověřováním systému Windows, pokud server není nakonfigurovaný tak, aby povoloval anonymní přístup. Pro podporu tohoto scénáře je potřeba nainstalovat a nakonfigurovat modul CORS služby IIS pro aplikaci.

Testování CORS

Ukázkový soubor ke stažení obsahuje kód pro testování CORS. Podívejte se, jak stahovat. Ukázka je projekt rozhraní API s přidanými stránkami 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();

Warning

WithOrigins("https://localhost:<port>"); lze použít pouze k testování ukázkové aplikace podobné jako ukázkový kód ke stažení.

ValuesController Následující text uvádí koncové body pro testování:

[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 poskytuje balíček NuGet Rick.Docs.Samples.RouteInfo a zobrazí informace o trase.

Otestujte předchozí vzorový kód pomocí jednoho z následujících přístupů:

  • Spusťte ukázku pomocí dotnet run s výchozí adresou URL https://localhost:5001.
  • Spusťte ukázku ze sady Visual Studio s portem nastaveným na 44398 pro adresu URL souboru https://localhost:44398.

Použití prohlížeče s nástroji F12:

  • Vyberte tlačítko Hodnoty a zkontrolujte záhlaví na kartě Síť.

  • Vyberte tlačítko PUT test. Pokyny k zobrazení požadavku OPTIONS najdete v části Zobrazení MOŽNOSTÍ . Test PUT vytvoří dva požadavky, předběžný požadavek OPTIONS a požadavek PUT.

  • GetValues2 [DisableCors] Výběrem tlačítka aktivujte neúspěšný požadavek CORS. Jak je uvedeno v dokumentaci, odpověď vrátí stavový kód 200 (OK), ale požadavek CORS se neodešle. Vyberte kartu Konzola a zobrazte chybu CORS. V závislosti na prohlížeči se zobrazí chyba podobná této:

    Zásady CORS blokovaly přístup k načtení 'https://cors1.azurewebsites.net/api/values/GetValues2' z zdroje 'https://cors3.azurewebsites.net' : U požadovaného prostředku není k dispozici žádná hlavička Access-Control-Allow-Origin. Pokud vám vyhovuje neprůhledná odpověď, nastavte režim požadavku na 'no-cors' pro načtení prostředku s vypnutým CORS.

Koncové body s povoleným CORS lze testovat pomocí nástrojů, jako jsou curl nebo Fiddler. Při použití nástroje se původ požadavku určeného Origin hlavičkou musí lišit od hostitele, který požadavek přijímá. Pokud požadavek není na základě hodnoty hlavičky považován za Origin:

  • Není nutné, aby middleware CORS zpracovával požadavek.
  • Hlavičky CORS nejsou v odpovědi vráceny.

Následující příkaz používá curl k vydání požadavku OPTIONS s informacemi:

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

Testování CORS pomocí směrování koncových bodů a [HttpOptions]

Povolení CORS pro jednotlivé endpointy pomocí RequireCors v současnosti nepodporujeautomatické požadavky preflight. Zvažte následující kód, který používá směrování koncových bodů k povolení 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();

Následující TodoItems1Controller poskytuje koncové body pro testování:

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

Otestujte předchozí kód z testovací stránky (https://cors1.azurewebsites.net/test?number=1) nasazené ukázky.

Tlačítka Delete [EnableCors] a GET [EnableCors] jsou úspěšná, protože koncové body mají [EnableCors] a reagují na předběžné požadavky. Ostatní koncové body selžou. Tlačítko GET selže, protože JavaScript odesílá:

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

Následující TodoItems2Controller poskytuje podobné endpointy, ale obsahuje explicitní kód pro zpracování požadavků 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);
}

Předchozí kód lze otestovat nasazením ukázky do Azure. V rozevíracím seznamu Controller vyberte Preflight a potom Set Controller. Všechna volání CORS do TodoItems2Controller koncových bodů jsou úspěšná.

Dodatečné zdroje

Autoři: Rick Anderson a Kirk Larkin

Tento článek ukazuje, jak povolit CORS v aplikaci ASP.NET Core.

Zabezpečení prohlížeče zabraňuje tomu, aby webová stránka odesílala požadavky do jiné domény, než je ta, která webovou stránku obsluhuje. Toto omezení se označuje jako zásada stejného zdroje. Zásada stejného zdroje brání škodlivým webům ve čtení citlivých dat z jiných webů. Někdy můžete chtít povolit jiným webům odesílat do vaší aplikace požadavky z jiného původu. Další informace naleznete v článku Mozilla CORS.

Sdílení prostředků mezi zdroji původu (CORS):

  • Je to standard W3C, který umožňuje serveru zmírnit politiku stejného původu.
  • Nejedná se o bezpečnostní funkci, CORS oslabuje zabezpečení. Rozhraní API není bezpečnější jen proto, že povoluje CORS. Další informace najdete v tématu Jak CORS funguje.
  • Umožňuje serveru explicitně povolit některé požadavky mezi zdroji a zároveň odmítnout jiné.
  • Je bezpečnější a flexibilnější než dřívější techniky, například JSONP.

Zobrazení nebo stažení ukázkového kódu (postup stažení)

Stejný původ

Dvě adresy URL mají stejný původ, pokud mají stejná schémata, hostitele a porty (RFC 6454).

Tyto dvě adresy URL mají stejný původ:

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

Tyto adresy URL mají jiný původ než předchozí dvě adresy URL:

  • https://example.net: Jiná doména
  • https://www.example.com/foo.html: Jiná subdoména
  • http://example.com/foo.html: Jiné schéma
  • https://example.com:9000/foo.html: Jiný port

Povolit CORS

CORS můžete povolit třemi způsoby:

Použití atributu [EnableCors] s pojmenovanou zásadou poskytuje nejlepší kontrolu v omezení koncových bodů, které podporují CORS.

Warning

UseCors musí být volána ve správném pořadí. Další informace najdete v tématu Pořadí middlewaru. Například UseCors musí být volána před UseResponseCaching při použití UseResponseCaching.

Každý přístup je podrobně popsaný v následujících částech.

CORS s pojmenovanými zásadami a middlewarem

Middleware CORS zpracovává požadavky z různých zdrojů. Následující kód použije zásadu CORS pro všechny koncové body aplikace se zadanými zdroji:

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

Předchozí kód:

Při směrování koncových bodů musí být middleware CORS nakonfigurován tak, aby se spouštěl mezi volánímiUseRouting a UseEndpoints.

Pokyny k testování kódu podobného předchozímu kódu najdete v části Test CORS .

Volání metody AddCors přidá služby CORS do kontejneru služeb aplikace:

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

Další informace najdete v tématu Možnosti zásad CORS v tomto dokumentu.

Metody CorsPolicyBuilder mohou být zřetězeny, jak je znázorněno v následujícím kódu:

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

Poznámka: Zadaná adresa URL nesmí obsahovat koncové lomítko (/). Pokud adresa URL končí na /, porovnání vrátí false a nevrátí se žádné záhlaví.

CORS s výchozími zásadami a middlewarem

Následující zvýrazněný kód povolí výchozí zásady 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();
        });
    }
}

Předchozí kód použije výchozí zásady CORS pro všechny koncové body kontroleru.

Povolte CORS pomocí směrování koncových bodů

Povolení CORS pro jednotlivé koncové body pomocí RequireCorsnepodporuje automatické požadavky preflight. Další informace najdete v tomto problému na GitHubu a Test CORS se směrováním koncových bodů a [HttpOptions].

Pomocí směrování koncového bodu je možné CORS povolit pro jednotlivé koncové body pomocí RequireCors sady rozšiřujících metod:

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

V předchozím kódu:

  • app.UseCors povolí middleware CORS. Protože není nakonfigurovaná výchozí politika, samotné app.UseCors() CORS nepovolí.
  • Koncové body /echo a kontroleru umožňují požadavky z různých zdrojů podle zadaných zásad.
  • Koncové body stránek /echo2 a Razorneumožňují požadavky z různých zdrojů, protože nebyla zadána žádná výchozí zásada.

Atribut [DisableCors] nezakazujeCORS, které bylo povoleno směrováním koncového bodu s RequireCors.

Pokyny k testování kódu podobného předchozímu kódu najdete v části Test CORS se směrováním koncových bodů a [HttpOptions].

Povolit CORS pomocí atributů

Povolení CORS pomocí atributu [EnableCors] a použití pojmenované zásady pouze na koncové body, které vyžadují CORS, poskytuje nejlepší kontrolu.

Atribut [EnableCors] poskytuje alternativu k použití CORS globálně. Tento [EnableCors] atribut umožňuje CORS pro vybrané koncové body, nikoli pro všechny koncové body:

  • [EnableCors] určuje výchozí zásadu.
  • [EnableCors("{Policy String}")] určuje pojmenovanou zásadu.

Atribut [EnableCors] lze použít na:

  • Razor Stránka PageModel
  • Controller
  • Metoda akce kontroleru

U kontrolerů, modelů stránek nebo metod akcí s atributem [EnableCors] je možné použít různé zásady. [EnableCors] Když se atribut použije u kontroleru, modelu stránky nebo metody akce a CORS je v middlewaru povolený, použijí se obě zásady. Nedoporučujeme kombinovat zásady. Použijte [EnableCors] atribut nebo middleware, ne oba ve stejné aplikaci.

Následující kód použije pro každou metodu jinou zásadu:

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

Následující kód vytvoří dvě zásady 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();
        });
    }
}

Pro co nejpřesnější kontrolu omezení požadavků CORS:

Kód v další části odpovídá předchozímu seznamu.

Pokyny k testování kódu podobného předchozímu kódu najdete v části Test CORS .

Zakázání CORS

Atribut [DisableCors] nezakazujeCORS, které bylo povoleno směrováním koncového bodu.

Následující kód definuje zásadu "MyPolicy"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();
        });
    }
}

Následující kód zakáže CORS pro GetValues2 akci:

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

}

Předchozí kód:

Pokyny k testování předchozího kódu najdete v části Test CORS .

Možnosti zásad CORS

Tato část popisuje různé možnosti, které je možné nastavit v zásadách CORS:

AddPolicy je voláno v Startup.ConfigureServices. U některých možností může být užitečné nejprve přečíst část Jak CORS funguje .

Nastavení povolených zdrojů

AllowAnyOrigin: Umožňuje požadavky CORS ze všech zdrojů s jakýmkoli schématem (http nebo https). AllowAnyOrigin není zabezpečená, protože jakýkoli web může na aplikaci odesílat cross-origin požadavky.

Note

Zadání AllowAnyOrigin a AllowCredentials představuje nezabezpečenou konfiguraci a může vést k padělání požadavků mezi weby. Služba CORS vrátí neplatnou odpověď CORS, když je aplikace nakonfigurovaná s oběma metodami.

AllowAnyOrigin ovlivňuje předběžné požadavky a hlavičku Access-Control-Allow-Origin . Další informace najdete v části Předběžné požadavky .

SetIsOriginAllowedToAllowWildcardSubdomains: Nastaví IsOriginAllowed vlastnost zásady na funkci, která umožňuje, aby zdroje odpovídaly nakonfigurované zástupné doméně při vyhodnocování, zda je původ povolený.

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

V předchozím kódu je SetIsOriginAllowedToAllowWildcardSubdomains volána se zástupným znakem domény "https://*.example.com". Toto nastavení umožňuje CORS žádosti z jakékoli subdomény example.com, jako https://subdomain.example.com nebo https://api.example.com. Zástupný znak * musí být zahrnut v původu, aby umožnil porovnávání subdomén pomocí zástupných znaků.

Nastavení povolených metod HTTP

AllowAnyMethod:

  • Povoluje libovolnou metodu HTTP:
  • Ovlivňuje předběžné požadavky a hlavičku Access-Control-Allow-Methods . Další informace najdete v části Předběžné požadavky .

Nastavení hlaviček povolených požadavků

Chcete-li povolit odesílání konkrétních hlaviček v požadavku CORS, označovaných jako hlavičky požadavku autora, zavolejte WithHeaders a zadejte povolené hlavičky:

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

Pokud chcete povolit všechna záhlaví žádosti autora, zavolejte AllowAnyHeader:

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

AllowAnyHeader ovlivňuje preflight požadavky a hlavičku Access-Control-Request-Headers. Další informace najdete v části Předběžné požadavky .

Shoda zásady middlewaru CORS s konkrétními hlavičkami zadanými pomocí WithHeaders je možná pouze tehdy, když hlavičky odeslané v Access-Control-Request-Headers přesně odpovídají hlavičkám uvedeným v WithHeaders.

Představte si například aplikaci nakonfigurovanou takto:

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

Middleware CORS odmítne předběžný požadavek s následující hlavičkou požadavku, protože Content-Language (HeaderNames.ContentLanguage) není uvedený v WithHeaders:

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

Aplikace vrátí odpověď 200 OK , ale neodesílá hlavičky CORS zpět. Prohlížeč se proto nepokouší o požadavek na jiný původ.

Nastavení vystavených hlaviček odpovědí

Ve výchozím nastavení prohlížeč nezpřístupňuje do aplikace všechny hlavičky odpovědi. Další informace najdete v tématu Sdílení prostředků mezi různými zdroji W3C (terminologie): jednoduchá hlavička odpovědi.

Hlavičky odpovědi, které jsou ve výchozím nastavení k dispozici, jsou:

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

Specifikace CORS tyto hlavičky označuje jako jednoduché hlavičky odpovědi. Pokud chcete aplikaci zpřístupnit další hlavičky, zavolejte WithExposedHeaders:

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

Přihlašovací údaje v požadavcích mezi zdroji

Přihlašovací údaje vyžadují speciální zpracování v požadavku CORS. Ve výchozím nastavení prohlížeč neodesílá přihlašovací údaje s požadavkem z jiného původu. Přihlašovací údaje zahrnují soubory cookie a schémata ověřování HTTP. Chcete-li odeslat přihlašovací údaje s požadavkem mezi zdroji, musí klient nastavit XMLHttpRequest.withCredentials na hodnotu true.

Přímé použití XMLHttpRequest :

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

Pomocí jQuery:

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

Použití rozhraní Fetch API:

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

Server musí přihlašovací údaje povolit. Chcete-li povolit pověření pro různé zdroje, zavolejte AllowCredentials:

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

Odpověď HTTP obsahuje hlavičku Access-Control-Allow-Credentials , která prohlížeči říká, že server povoluje přihlašovací údaje pro požadavek mezi zdroji.

Pokud prohlížeč odešle přihlašovací údaje, ale odpověď neobsahuje platnou Access-Control-Allow-Credentials hlavičku, prohlížeč nezobrazí odpověď aplikaci a požadavek mezi zdroji selže.

Povolení přihlašovacích údajů mezi různými zdroji představuje bezpečnostní riziko. Web v jiné doméně může odeslat přihlašovací údaje přihlášeného uživatele do aplikace jménem uživatele bez vědomí uživatele.

Specifikace CORS také uvádí, že nastavení původu na "*" (všechny zdroje) je neplatné, pokud je hlavička Access-Control-Allow-Credentials přítomna.

Preflightové požadavky

U některých požadavků CORS prohlížeč před provedením skutečného požadavku odešle další požadavek OPTIONS . Tento požadavek se nazývá předběžný požadavek. Prohlížeč může předběžný požadavek přeskočit, pokud jsou splněny všechny následující podmínky:

  • Metoda požadavku je GET, HEAD nebo POST.
  • Aplikace nenastavuje jiné hlavičky požadavků než Accept, Accept-Language, Content-Language, , Content-Typenebo Last-Event-ID.
  • Hlavička Content-Type , pokud je nastavená, má jednu z následujících hodnot:
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

Pravidlo hlavičky požadavku nastavené pro požadavek klienta se vztahuje na hlavičky, které aplikace nastaví voláním setRequestHeader objektu XMLHttpRequest . Specifikace CORS označuje tyto hlavičky jako hlavičky požadavku autora. Pravidlo se nevztahuje na hlavičky, které může prohlížeč nastavit, například User-Agent, Hostnebo Content-Length.

Následuje příklad odpovědi podobné předběžnému požadavku vytvořenému z tlačítka [Put test] v části Test CORS tohoto 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

Předběžný požadavek používá metodu HTTP OPTIONS . Může obsahovat následující hlavičky:

Pokud je preflight požadavek zamítnut, aplikace vrátí odpověď 200 OK, ale nenastaví hlavičky CORS. Prohlížeč se proto nepokouší o požadavek na jiný původ. Příklad zamítnutého preflightového požadavku najdete v části Test CORS tohoto dokumentu.

Pomocí nástrojů F12 konzolová aplikace zobrazí v závislosti na prohlížeči chybu podobnou jedné z následujících možností:

  • Firefox: Požadavek mezi různými zdroji byl zablokován: Zásada stejného původu nepovoluje přístup ke vzdálenému prostředku na adrese https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5. (Důvod: Požadavek CORS nebyl úspěšný). Zjistit více
  • Založeno na Chromiu: Přístup k načtení na adrese 'https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5' z původu 'https://cors3.azurewebsites.net' byl zablokován zásadami CORS: Odpověď na předběžný požadavek neprošla kontrolou řízení přístupu: v požadovaném prostředku není přítomna žádná hlavička 'Access-Control-Allow-Origin'. Pokud vám vyhovuje neprůhledná odpověď, nastavte režim požadavku na 'no-cors' pro načtení prostředku s vypnutým CORS.

Pokud chcete povolit konkrétní záhlaví, zavolejte WithHeaders:

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

Pokud chcete povolit všechna záhlaví žádosti autora, zavolejte AllowAnyHeader:

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

Prohlížeče nejsou konzistentní ve způsobu jejich nastavení Access-Control-Request-Headers. Pokud máte některou z těchto:

  • Záhlaví jsou nastavená na cokoli jiného než "*"
  • AllowAnyHeader se nazývá: Zahrňte alespoň Accept, Content-Type a Origin a všechny vlastní hlavičky, které chcete podporovat.

Automatický předletový kód požadavku

Pokud se použije zásada CORS:

  • Globálně voláním app.UseCors v Startup.Configure.
  • Použití atributu [EnableCors]

ASP.NET Core odpovídá na předběžný dotaz OPTIONS.

Povolení CORS pro jednotlivé endpointy pomocí RequireCors aktuálně nepodporuje automatické požadavky preflight.

Toto chování ukazuje část Test CORS tohoto dokumentu.

Atribut [HttpOptions] pro předběžné požadavky

Když je CORS povolená s příslušnými zásadami, ASP.NET Core obvykle automaticky reaguje na předběžné požadavky CORS. V některých scénářích to nemusí být tento případ. Například použití CORS se směrováním koncových bodů.

Následující kód používá atribut [HttpOptions] k vytvoření koncových bodů pro požadavky 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);
    }

Pokyny k otestování předchozího kódu najdete v tématu Testování CORS se směrováním koncových bodů a [HttpOptions].

Nastavení doby předběžného vypršení platnosti

Hlavička Access-Control-Max-Age určuje, jak dlouho může být odpověď na předběžný požadavek uložena do mezipaměti. Chcete-li nastavit toto záhlaví, zavolejte SetPreflightMaxAge:

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

Jak CORS funguje

Tato část popisuje, co se stane v požadavku CORS na úrovni zpráv HTTP.

  • CORS není bezpečnostní funkce. CORS je standard W3C, který umožňuje serveru uvolnit zásady stejného původu.
    • Například by škodlivý útočník mohl proti vašemu webu použít Cross-Site Scripting (XSS) a odeslat požadavek mezi weby na svůj web s povoleným CORS, aby odcizil informace.
  • API není bezpečnější tím, že umožňuje CORS.
    • Je na klientovi (prohlížeči), aby vynucoval CORS. Server spustí požadavek a vrátí odpověď. Je to klient, který vrací chybu a blokuje odpověď. Například některý z následujících nástrojů zobrazí odpověď serveru:
  • Je to způsob, jak server umožňuje prohlížečům provést požadavek XHR nebo Fetch API z jiné domény, který by jinak byl zakázán.
    • Prohlížeče bez CORS nemůžou provádět žádosti mezi zdroji. Před CORS se k obejití tohoto omezení použil JSONP . JSONP nepoužívá XHR, k přijetí odpovědi používá <script> značku. Skripty je povoleno načítat z jiného původu.

Specifikace CORS zavedla několik nových hlaviček HTTP, které umožňují požadavky mezi zdroji. Pokud prohlížeč podporuje CORS, nastaví tato záhlaví automaticky u požadavků z jiného původu. K povolení CORS se nevyžaduje vlastní javascriptový kód.

Následuje příklad požadavku mezi různými zdroji z testovacího tlačítka Values do https://cors1.azurewebsites.net/api/values. Hlavička Origin :

  • Poskytuje doménu webu, který odesílá požadavek.
  • Vyžaduje se a musí se lišit od hostitele.

Obecné hlavičky

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

Hlavičky odpovědi

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

Hlavičky požadavků

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

V požadavcích OPTIONS server v odpovědi nastaví hlavičku Response headersAccess-Control-Allow-Origin: {allowed origin}. Například požadavek pro tlačítko Odstranit v nasazeném OPTIONS obsahuje následující hlavičky:

Obecné hlavičky

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

Hlavičky odpovědi

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

Hlavičky požadavků

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

V předchozích hlavičkách odpovědi server v odpovědi nastaví hlavičku Access-Control-Allow-Origin. Hodnota https://cors1.azurewebsites.net této hlavičky odpovídá Origin hlavičce požadavku.

Pokud je zavoláno AllowAnyOrigin, vrátí se Access-Control-Allow-Origin: *, zástupná hodnota. AllowAnyOrigin umožňuje jakýkoli původ.

Pokud odpověď neobsahuje hlavičku Access-Control-Allow-Origin, požadavek mezi různými zdroji selže. Konkrétně prohlížeč požadavek zakáže. I když server vrátí úspěšnou odpověď, prohlížeč nepřístupní odpověď klientské aplikaci.

Zobrazit požadavky OPTIONS

Ve výchozím nastavení prohlížeče Chrome a Edge nezobrazují požadavky OPTIONS na kartě sítě nástrojů F12. Zobrazení požadavků OPTIONS v těchto prohlížečích:

  • chrome://flags/#out-of-blink-cors nebo edge://flags/#out-of-blink-cors
  • zakažte příznak.
  • restart.

Firefox ve výchozím nastavení zobrazuje požadavky OPTIONS.

CORS ve službě IIS

Při nasazování do služby IIS musí CORS běžet před ověřováním systému Windows, pokud server není nakonfigurovaný tak, aby povoloval anonymní přístup. Pro podporu tohoto scénáře je potřeba nainstalovat a nakonfigurovat modul CORS služby IIS pro aplikaci.

Testování CORS

Ukázkový soubor ke stažení obsahuje kód pro testování CORS. Podívejte se, jak stahovat. Ukázka je projekt rozhraní API s přidanými stránkami 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();
        });
    }
}

Warning

WithOrigins("https://localhost:<port>"); lze použít pouze k testování ukázkové aplikace podobné jako ukázkový kód ke stažení.

ValuesController Následující text uvádí koncové body pro testování:

[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 poskytuje balíček NuGet Rick.Docs.Samples.RouteInfo a zobrazí informace o trase.

Otestujte předchozí vzorový kód pomocí jednoho z následujících přístupů:

  • Spusťte ukázku pomocí dotnet run s výchozí adresou URL https://localhost:5001.
  • Spusťte ukázku ze sady Visual Studio s portem nastaveným na 44398 pro adresu URL souboru https://localhost:44398.

Použití prohlížeče s nástroji F12:

  • Vyberte tlačítko Hodnoty a zkontrolujte záhlaví na kartě Síť.

  • Vyberte tlačítko PUT test. Pokyny k zobrazení požadavku OPTIONS najdete v části Zobrazení MOŽNOSTÍ . Test PUT vytvoří dva požadavky, předběžný požadavek OPTIONS a požadavek PUT.

  • GetValues2 [DisableCors] Výběrem tlačítka aktivujte neúspěšný požadavek CORS. Jak je uvedeno v dokumentaci, odpověď vrátí stavový kód 200 (OK), ale požadavek CORS se neodešle. Vyberte kartu Konzola a zobrazte chybu CORS. V závislosti na prohlížeči se zobrazí chyba podobná této:

    Zásady CORS blokovaly přístup k načtení 'https://cors1.azurewebsites.net/api/values/GetValues2' z zdroje 'https://cors3.azurewebsites.net' : U požadovaného prostředku není k dispozici žádná hlavička Access-Control-Allow-Origin. Pokud vám vyhovuje neprůhledná odpověď, nastavte režim požadavku na 'no-cors' pro načtení prostředku s vypnutým CORS.

Koncové body s povoleným CORS lze testovat pomocí nástrojů, jako jsou curl nebo Fiddler. Při použití nástroje se původ požadavku určeného Origin hlavičkou musí lišit od hostitele, který požadavek přijímá. Pokud požadavek není na základě hodnoty hlavičky považován za Origin:

  • Není nutné, aby middleware CORS zpracovával požadavek.
  • Hlavičky CORS nejsou v odpovědi vráceny.

Následující příkaz používá curl k vydání požadavku OPTIONS s informacemi:

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

Testování CORS pomocí směrování koncových bodů a [HttpOptions]

Povolení CORS pro jednotlivé endpointy pomocí RequireCors v současnosti nepodporujeautomatické požadavky preflight. Zvažte následující kód, který používá směrování koncových bodů k povolení 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();
        });
    }
}

Následující TodoItems1Controller poskytuje koncové body pro testování:

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

Otestujte předchozí kód z testovací stránky (https://cors1.azurewebsites.net/test?number=1) nasazené ukázky.

Tlačítka Delete [EnableCors] a GET [EnableCors] jsou úspěšná, protože koncové body mají [EnableCors] a reagují na předběžné požadavky. Ostatní koncové body selžou. Tlačítko GET selže, protože JavaScript odesílá:

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

Následující TodoItems2Controller poskytuje podobné endpointy, ale obsahuje explicitní kód pro zpracování požadavků 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);
}

Předchozí kód lze otestovat nasazením ukázky do Azure. V rozevíracím seznamu Controller vyberte Preflight a potom Set Controller. Všechna volání CORS do TodoItems2Controller koncových bodů jsou úspěšná.

Dodatečné zdroje