Povolení žádostí mezi zdroji (CORS) v ASP.NET Core

Poznámka:

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

Důležité

Tyto informace se týkají předběžného vydání produktu, který může být podstatně změněn před komerčním vydáním. Microsoft neposkytuje žádné záruky, výslovné ani předpokládané, týkající se zde uváděných informací.

Aktuální verzi najdete ve verzi .NET 8 tohoto článku.

Autoři: Rick Anderson a Kirk Larkin

Tento článek ukazuje, jak je c ross-O rigin Resource Sharing (CORS) povolen 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ůže být vhodné povolit jiným webům, aby vaše aplikace zpřístupňovala žádosti mezi zdroji. Další informace naleznete v článku Mozilla CORS.

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

  • Je standard W3C, který umožňuje serveru uvolnit zásady stejného původu.
  • Není to funkce zabezpečení, CORS uvolní zabezpečení. Rozhraní API není bezpečnější tím, že umožňuje 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, jako JSje ONP.

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

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

Upozorňující

UseCors musí být volána ve správném pořadí. Další informace naleznete v tématu Pořadí middlewaru. UseCors Například musí být volána před UseResponseCaching použitím 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 mezi zdroji. 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:

  • Nastaví název zásady na _myAllowSpecificOrigins. Název zásady je libovolný.
  • Volá metodu UseCors rozšíření a určuje _myAllowSpecificOrigins zásady CORS. UseCors přidá middleware CORS. Hovor UseCors musí být umístěn za UseRouting, ale před UseAuthorization. Další informace naleznete v tématu Pořadí middlewaru.
  • Volání AddCors pomocí výrazu lambda Lambda přebírá CorsPolicyBuilder objekt. Možnosti konfigurace, například WithOrigins, jsou popsány dále v tomto článku.
  • Povolí zásadu _myAllowSpecificOrigins CORS pro všechny koncové body kontroleru. Podívejte se na směrování koncových bodů, abyste použili zásadu CORS na konkrétní koncové body.
  • Při použití odpovědi Ukládání do mezipaměti Middleware zavolejte UseCors před UseResponseCaching.

Se směrováním koncového bodu musí být middleware CORS nakonfigurovaný tak, aby se prováděl mezi voláními a UseRoutingUseEndpoints.

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

Volání AddCors metody přidá služby CORS do kontejneru služby 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ězený, 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 se /adresa URL ukončí, vrátí se porovnání false a nevrátí se žádná hlavička.

Pořadí UseCors a UseStaticFiles

Obvykle se UseStaticFiles volá před UseCors. Aplikace, které používají JavaScript k načtení statických souborů mezi weby, musí před voláním UseStaticFilesvolat UseCors .

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.

Povolení Cors se směrováním 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. Vzhledem k tomu, že se nenakonfigurovala výchozí zásada, app.UseCors() samotná možnost CORS nepovoluje.
  • Koncové /echo body kontroleru umožňují požadavky mezi zdroji pomocí zadaných zásad.
  • Koncové /echo2 body stránky Razor neumožňují požadavky mezi zdroji, protože nebyly zadány žádné výchozí zásady.

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.

Povolení CORS s atributy

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
  • Ovladač
  • 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. Doporučujeme kombinovat zásady. Pomocí tlačítka [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();

Nejlepší kontrolu nad omezováním požadavků CORS:

  • Používá se [EnableCors("MyPolicy")] s pojmenovanými zásadami.
  • Nedefinujte výchozí zásadu.
  • Nepoužívejte směrování koncového bodu.

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:

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ána 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 CORS požadavky ze všech původů s jakýmkoli schématem (http nebo https). AllowAnyOrigin je nezabezpečený, protože každý web může do aplikace vyhovět žádostem mezi zdroji.

Poznámka:

AllowAnyOrigin Určení a AllowCredentials je nezabezpečená konfigurace 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();

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ů

Pokud chcete povolit odesílání konkrétních hlaviček v požadavku CORS, označované jako hlavičky žádosti autora, volání WithHeaders a zadání povolených hlaviček:

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 předběžné požadavky a hlavičku Hlavičky žádostí o přístup. Další informace najdete v části Předběžné požadavky .

Zásady middlewaru CORS odpovídají konkrétním hlavičkám určeným WithHeaders pouze tehdy, když hlavičky odeslané přesně Access-Control-Request-Headers 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 mezi zdroji.

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 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 volá tyto hlavičky jednoduchých hlaviček 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 mezi zdroji. Přihlašovací údaje zahrnují cookieschémata ověřování HTTP. Chcete-li odeslat přihlašovací údaje s žádostí mezi zdroji, musí klient nastavit XMLHttpRequest.withCredentials na truehodnotu .

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. Pokud chcete povolit přihlašovací údaje mezi zdroji, 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 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.

Předběžné 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 volá 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 předběžný požadavek odepřen, aplikace vrátí 200 OK odpověď, ale nenastaví hlavičky CORS. Prohlížeč se proto nepokouší o požadavek mezi zdroji. Příklad odepřené předběžné žádosti najdete v části Testovací 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: Blokovaný požadavek mezi zdroji: Stejné zásady původu nepovolují čtení vzdáleného prostředku na adrese https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5. (Důvod: Požadavek CORS nebyl úspěšný). Další informace
  • Chromium: Zásady CORS zablokovaly přístup k načtení nahttps://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5 "' z původu'https://cors3.azurewebsites.net: Odpověď na předběžný požadavek neprojde kontrolou řízení přístupu: U požadovaného prostředku není k dispozici žádná hlavička Access-Control-Allow-Origin. Pokud vaše potřeby obsluhují neprůspatnou odpověď, nastavte režim požadavku na no-cors, aby se načítal prostředek se zakázaný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 je volána: Zahrňte alespoň Accept, Content-Typea , a Originnavíc všechny vlastní hlavičky, které chcete podporovat.

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

Při použití zásad CORS:

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

ASP.NET Core reaguje na předběžný požadavek 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();

Povolení CORS v koncovém bodu

Jak CORS funguje

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

  • CORS není funkce zabezpečení. CORS je standard W3C, který umožňuje serveru uvolnit zásady stejného původu.
    • Například herec se zlými úmysly může na vašem webu použít skriptování mezi weby (XSS) a provést žádost mezi weby s podporou CORS k krádeži informací.
  • Rozhraní API není bezpečnější tím, že umožňuje CORS.
    • Je na klientovi (prohlížeči) a vynucuje 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 serveru umožnit prohlížečům spouštět požadavek XHR nebo Fetch API mezi zdroji, které by jinak bylo zakázáno.
    • Prohlížeče bez CORS nemůžou provádět žádosti mezi zdroji. Před CORS JSse onP použil k obcházení tohoto omezení. JSONP nepoužívá XHR, k přijetí odpovědi používá <script> značku. Skripty je možné načíst mezi zdroji.

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 pro žádosti mezi zdroji. K povolení CORS se nevyžaduje vlastní javascriptový kód.

Tlačítko TEST PUT na nasazené ukázce

Následuje příklad požadavku mezi zdroji z tlačítka Test hodnot do https://cors1.azurewebsites.net/api/values. Hlavička Origin :

  • Poskytuje doménu lokality, která požadavek provádí.
  • 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žadavku

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 OPTIONS požadavcích server nastaví hlavičku hlavičkyAccess-Control-Allow-Origin: {allowed origin} odpovědi v odpovědi. Například nasazená ukázka obsahuje požadavek na tlačítko OPTIONS Delete [EnableCors] 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žadavku

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 nastaví v odpovědi hlavičku Access-Control-Allow-Origin . Hodnota https://cors1.azurewebsites.net této hlavičky odpovídá Origin hlavičce požadavku.

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

Pokud odpověď hlavičku Access-Control-Allow-Origin neobsahuje, požadavek mezi 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í HTTP na HTTPS způsobuje ERR_INVALID_REDIRECT předběžné žádosti CORS.

Požadavky na koncový bod pomocí protokolu HTTP, které jsou přesměrované na HTTPS, selžouUseHttpsRedirection.ERR_INVALID_REDIRECT on the CORS preflight request

Projekty rozhraní API můžou odmítnout požadavky HTTP místo toho UseHttpsRedirection , aby přesměrovály požadavky 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 si stáhnout. 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();

Upozorňující

WithOrigins("https://localhost:<port>"); by se měla použít pouze k testování ukázkové aplikace podobné ukázkového kódu ke stažení.

ValuesController Následující body poskytují 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ů:

  • Použijte nasazenou ukázkovou aplikaci na adrese https://cors3.azurewebsites.net/. Ukázku není nutné stahovat.
  • Spusťte ukázku s dotnet run použitím výchozí adresy URL https://localhost:5001souboru .
  • 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 TEST PUT. 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 dokumentu, odpověď vrátí úspěch 200, ale požadavek CORS není proveden. Výběrem karty Konzola zobrazíte 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 vaše potřeby obsluhují neprůspatnou odpověď, nastavte režim požadavku na no-cors, aby se načítal prostředek se zakázaným CORS.

Koncové body s podporou CORS je možné testovat pomocí nástroje, jako je 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í mezi zdroji založený na hodnotě hlavičky Origin :

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

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 /echo koncový bod používá RequireCors k povolení požadavků mezi zdroji pomocí zadané zásady. Následující kontrolery povolují CORS pomocí atributu [EnableCors].

TodoItems1Controller Následující body poskytují 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);
}

Otestujte předchozí kód z testovací stránky 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"
 },

TodoItems2Controller Následující body poskytují podobné koncové body, ale obsahují explicitní kód pro reakci na 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);
    }

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

Otestujte předchozí kód z testovací stránky nasazené ukázky. V rozevíracím seznamu Kontroler vyberte Předlet a pak Nastavte kontroler. Všechna volání CORS do TodoItems2Controller koncových bodů jsou úspěšná.

Další materiály

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ůže být vhodné povolit jiným webům, aby vaše aplikace zpřístupňovala žádosti mezi zdroji. Další informace naleznete v článku Mozilla CORS.

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

  • Je standard W3C, který umožňuje serveru uvolnit zásady stejného původu.
  • Není to funkce zabezpečení, CORS uvolní zabezpečení. Rozhraní API není bezpečnější tím, že umožňuje 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, jako JSje ONP.

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

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

Upozorňující

UseCors musí být volána ve správném pořadí. Další informace naleznete v tématu Pořadí middlewaru. UseCors Například musí být volána před UseResponseCaching použitím 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 mezi zdroji. 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:

  • Nastaví název zásady na _myAllowSpecificOrigins. Název zásady je libovolný.
  • Volá metodu UseCors rozšíření a určuje _myAllowSpecificOrigins zásady CORS. UseCors přidá middleware CORS. Hovor UseCors musí být umístěn za UseRouting, ale před UseAuthorization. Další informace naleznete v tématu Pořadí middlewaru.
  • Volání AddCors pomocí výrazu lambda Lambda přebírá CorsPolicyBuilder objekt. Možnosti konfigurace, například WithOrigins, jsou popsány dále v tomto článku.
  • Povolí zásadu _myAllowSpecificOrigins CORS pro všechny koncové body kontroleru. Podívejte se na směrování koncových bodů, abyste použili zásadu CORS na konkrétní koncové body.
  • Při použití odpovědi Ukládání do mezipaměti Middleware zavolejte UseCors před UseResponseCaching.

Se směrováním koncového bodu musí být middleware CORS nakonfigurovaný tak, aby se prováděl mezi voláními a UseRoutingUseEndpoints.

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

Volání AddCors metody přidá služby CORS do kontejneru služby 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ězený, 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 se /adresa URL ukončí, vrátí se porovnání false a nevrátí se žádná hlavička.

Upozorňující

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čtení statických souborů mezi weby, musí před voláním UseStaticFilesvolat UseCors .

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.

Povolení Cors se směrováním 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. Vzhledem k tomu, že se nenakonfigurovala výchozí zásada, app.UseCors() samotná možnost CORS nepovoluje.
  • Koncové /echo body kontroleru umožňují požadavky mezi zdroji pomocí zadaných zásad.
  • Koncové /echo2 body stránky Razor neumožňují požadavky mezi zdroji, protože nebyly zadány žádné výchozí zásady.

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

V ASP.NET Core 7.0 [EnableCors] musí atribut předat parametr nebo ASP0023 Upozornění se vygeneruje z nejednoznačné shody na trase. ASP.NET Core 8.0 a 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.

Povolení CORS s atributy

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
  • Ovladač
  • 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. Doporučujeme kombinovat zásady. Pomocí tlačítka [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();

Nejlepší kontrolu nad omezováním požadavků CORS:

  • Používá se [EnableCors("MyPolicy")] s pojmenovanými zásadami.
  • Nedefinujte výchozí zásadu.
  • Nepoužívejte směrování koncového bodu.

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:

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ána 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 CORS požadavky ze všech původů s jakýmkoli schématem (http nebo https). AllowAnyOrigin je nezabezpečený, protože každý web může do aplikace vyhovět žádostem mezi zdroji.

Poznámka:

AllowAnyOrigin Určení a AllowCredentials je nezabezpečená konfigurace 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();

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ů

Pokud chcete povolit odesílání konkrétních hlaviček v požadavku CORS, označované jako hlavičky žádosti autora, volání WithHeaders a zadání povolených hlaviček:

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 předběžné požadavky a hlavičku Hlavičky žádostí o přístup. Další informace najdete v části Předběžné požadavky .

Zásady middlewaru CORS odpovídají konkrétním hlavičkám určeným WithHeaders pouze tehdy, když hlavičky odeslané přesně Access-Control-Request-Headers 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 mezi zdroji.

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 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 volá tyto hlavičky jednoduchých hlaviček 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 mezi zdroji. Přihlašovací údaje zahrnují cookieschémata ověřování HTTP. Chcete-li odeslat přihlašovací údaje s žádostí mezi zdroji, musí klient nastavit XMLHttpRequest.withCredentials na truehodnotu .

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. Pokud chcete povolit přihlašovací údaje mezi zdroji, 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 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.

Předběžné 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 volá 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 předběžný požadavek odepřen, aplikace vrátí 200 OK odpověď, ale nenastaví hlavičky CORS. Prohlížeč se proto nepokouší o požadavek mezi zdroji. Příklad odepřené předběžné žádosti najdete v části Testovací 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: Blokovaný požadavek mezi zdroji: Stejné zásady původu nepovolují čtení vzdáleného prostředku na adrese https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5. (Důvod: Požadavek CORS nebyl úspěšný). Další informace
  • Chromium: Zásady CORS zablokovaly přístup k načtení nahttps://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5 "' z původu'https://cors3.azurewebsites.net: Odpověď na předběžný požadavek neprojde kontrolou řízení přístupu: U požadovaného prostředku není k dispozici žádná hlavička Access-Control-Allow-Origin. Pokud vaše potřeby obsluhují neprůspatnou odpověď, nastavte režim požadavku na no-cors, aby se načítal prostředek se zakázaný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 je volána: Zahrňte alespoň Accept, Content-Typea , a Originnavíc všechny vlastní hlavičky, které chcete podporovat.

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

Při použití zásad CORS:

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

ASP.NET Core reaguje na předběžný požadavek 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();

Povolení CORS v koncovém bodu

Jak CORS funguje

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

  • CORS není funkce zabezpečení. CORS je standard W3C, který umožňuje serveru uvolnit zásady stejného původu.
    • Například herec se zlými úmysly může na vašem webu použít skriptování mezi weby (XSS) a provést žádost mezi weby s podporou CORS k krádeži informací.
  • Rozhraní API není bezpečnější tím, že umožňuje CORS.
    • Je na klientovi (prohlížeči) a vynucuje 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 serveru umožnit prohlížečům spouštět požadavek XHR nebo Fetch API mezi zdroji, které by jinak bylo zakázáno.
    • Prohlížeče bez CORS nemůžou provádět žádosti mezi zdroji. Před CORS JSse onP použil k obcházení tohoto omezení. JSONP nepoužívá XHR, k přijetí odpovědi používá <script> značku. Skripty je možné načíst mezi zdroji.

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 pro žádosti mezi zdroji. K povolení CORS se nevyžaduje vlastní javascriptový kód.

Tlačítko TEST PUT na nasazené ukázce

Následuje příklad požadavku mezi zdroji z tlačítka Test hodnot do https://cors1.azurewebsites.net/api/values. Hlavička Origin :

  • Poskytuje doménu lokality, která požadavek provádí.
  • 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žadavku

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 OPTIONS požadavcích server nastaví hlavičku hlavičkyAccess-Control-Allow-Origin: {allowed origin} odpovědi v odpovědi. Například nasazená ukázka obsahuje požadavek na tlačítko OPTIONS Delete [EnableCors] 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žadavku

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 nastaví v odpovědi hlavičku Access-Control-Allow-Origin . Hodnota https://cors1.azurewebsites.net této hlavičky odpovídá Origin hlavičce požadavku.

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

Pokud odpověď hlavičku Access-Control-Allow-Origin neobsahuje, požadavek mezi 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í HTTP na HTTPS způsobuje ERR_INVALID_REDIRECT předběžné žádosti CORS.

Požadavky na koncový bod pomocí protokolu HTTP, které jsou přesměrované na HTTPS, selžouUseHttpsRedirection.ERR_INVALID_REDIRECT on the CORS preflight request

Projekty rozhraní API můžou odmítnout požadavky HTTP místo toho UseHttpsRedirection , aby přesměrovály požadavky 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 si stáhnout. 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();

Upozorňující

WithOrigins("https://localhost:<port>"); by se měla použít pouze k testování ukázkové aplikace podobné ukázkového kódu ke stažení.

ValuesController Následující body poskytují 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ů:

  • Použijte nasazenou ukázkovou aplikaci na adrese https://cors3.azurewebsites.net/. Ukázku není nutné stahovat.
  • Spusťte ukázku s dotnet run použitím výchozí adresy URL https://localhost:5001souboru .
  • 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 TEST PUT. 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 dokumentu, odpověď vrátí úspěch 200, ale požadavek CORS není proveden. Výběrem karty Konzola zobrazíte 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 vaše potřeby obsluhují neprůspatnou odpověď, nastavte režim požadavku na no-cors, aby se načítal prostředek se zakázaným CORS.

Koncové body s podporou CORS je možné testovat pomocí nástroje, jako je 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í mezi zdroji založený na hodnotě hlavičky Origin :

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

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 /echo koncový bod používá RequireCors k povolení požadavků mezi zdroji pomocí zadané zásady. Následující kontrolery povolují CORS pomocí atributu [EnableCors].

TodoItems1Controller Následující body poskytují 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);
}

Otestujte předchozí kód z testovací stránky 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"
 },

TodoItems2Controller Následující body poskytují podobné koncové body, ale obsahují explicitní kód pro reakci na 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);
    }

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

Otestujte předchozí kód z testovací stránky nasazené ukázky. V rozevíracím seznamu Kontroler vyberte Předlet a pak Nastavte kontroler. Všechna volání CORS do TodoItems2Controller koncových bodů jsou úspěšná.

Další materiály

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ůže být vhodné povolit jiným webům, aby vaše aplikace zpřístupňovala žádosti mezi zdroji. Další informace naleznete v článku Mozilla CORS.

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

  • Je standard W3C, který umožňuje serveru uvolnit zásady stejného původu.
  • Není to funkce zabezpečení, CORS uvolní zabezpečení. Rozhraní API není bezpečnější tím, že umožňuje 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, jako JSje ONP.

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

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

Upozorňující

UseCors musí být volána ve správném pořadí. Další informace naleznete v tématu Pořadí middlewaru. UseCors Například musí být volána před UseResponseCaching použitím 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 mezi zdroji. 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:

  • Nastaví název zásady na _myAllowSpecificOrigins. Název zásady je libovolný.
  • Volá metodu UseCors rozšíření a určuje _myAllowSpecificOrigins zásady CORS. UseCors přidá middleware CORS. Hovor UseCors musí být umístěn za UseRouting, ale před UseAuthorization. Další informace naleznete v tématu Pořadí middlewaru.
  • Volání AddCors pomocí výrazu lambda Lambda přebírá CorsPolicyBuilder objekt. Možnosti konfigurace, například WithOrigins, jsou popsány dále v tomto článku.
  • Povolí zásadu _myAllowSpecificOrigins CORS pro všechny koncové body kontroleru. Podívejte se na směrování koncových bodů, abyste použili zásadu CORS na konkrétní koncové body.
  • Při použití odpovědi Ukládání do mezipaměti Middleware zavolejte UseCors před UseResponseCaching.

Se směrováním koncového bodu musí být middleware CORS nakonfigurovaný tak, aby se prováděl mezi voláními a UseRoutingUseEndpoints.

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

Volání AddCors metody přidá služby CORS do kontejneru služby 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ězený, 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 se /adresa URL ukončí, vrátí se porovnání false a nevrátí se žádná hlavička.

Upozorňující

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čtení statických souborů mezi weby, musí před voláním UseStaticFilesvolat UseCors .

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.

Povolení Cors se směrováním koncových bodů

Povolení CORS na základě RequireCorsjednotlivých koncových bodů nepodporuje automatické předběžné požadavky. Další informace najdete v tomto problému na GitHubu a otestování 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. Vzhledem k tomu, že se nenakonfigurovala výchozí zásada, app.UseCors() samotná možnost CORS nepovoluje.
  • Koncové /echo body kontroleru umožňují požadavky mezi zdroji pomocí zadaných zásad.
  • Koncové /echo2 body stránky Razor neumožňují požadavky mezi zdroji, protože nebyly zadány žádné výchozí zásady.

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

Povolení CORS s atributy

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
  • Ovladač
  • 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. Doporučujeme kombinovat zásady. Pomocí tlačítka [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();

Nejlepší kontrolu nad omezováním požadavků CORS:

  • Používá se [EnableCors("MyPolicy")] s pojmenovanými zásadami.
  • Nedefinujte výchozí zásadu.
  • Nepoužívejte směrování koncového bodu.

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:

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ána 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 CORS požadavky ze všech původů s jakýmkoli schématem (http nebo https). AllowAnyOrigin je nezabezpečený, protože každý web může do aplikace vyhovět žádostem mezi zdroji.

Poznámka:

AllowAnyOrigin Určení a AllowCredentials je nezabezpečená konfigurace 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();

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ů

Pokud chcete povolit odesílání konkrétních hlaviček v požadavku CORS, označované jako hlavičky žádosti autora, volání WithHeaders a zadání povolených hlaviček:

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 předběžné požadavky a hlavičku Hlavičky žádostí o přístup. Další informace najdete v části Předběžné požadavky .

Zásady middlewaru CORS odpovídají konkrétním hlavičkám určeným WithHeaders pouze tehdy, když hlavičky odeslané přesně Access-Control-Request-Headers 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 mezi zdroji.

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 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 volá tyto hlavičky jednoduchých hlaviček 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 mezi zdroji. Přihlašovací údaje zahrnují cookieschémata ověřování HTTP. Chcete-li odeslat přihlašovací údaje s žádostí mezi zdroji, musí klient nastavit XMLHttpRequest.withCredentials na truehodnotu .

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. Pokud chcete povolit přihlašovací údaje mezi zdroji, 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 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.

Předběžné 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 volá 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 předběžný požadavek odepřen, aplikace vrátí 200 OK odpověď, ale nenastaví hlavičky CORS. Prohlížeč se proto nepokouší o požadavek mezi zdroji. Příklad odepřené předběžné žádosti najdete v části Testovací 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: Blokovaný požadavek mezi zdroji: Stejné zásady původu nepovolují čtení vzdáleného prostředku na adrese https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5. (Důvod: Požadavek CORS nebyl úspěšný). Další informace
  • Chromium: Zásady CORS zablokovaly přístup k načtení nahttps://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5 "' z původu'https://cors3.azurewebsites.net: Odpověď na předběžný požadavek neprojde kontrolou řízení přístupu: U požadovaného prostředku není k dispozici žádná hlavička Access-Control-Allow-Origin. Pokud vaše potřeby obsluhují neprůspatnou odpověď, nastavte režim požadavku na no-cors, aby se načítal prostředek se zakázaný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 je volána: Zahrňte alespoň Accept, Content-Typea , a Originnavíc všechny vlastní hlavičky, které chcete podporovat.

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

Při použití zásad CORS:

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

ASP.NET Core reaguje na předběžný požadavek OPTIONS.

Povolení CORS na základě jednotlivých koncových bodů v RequireCors současné době nepodporuje automatické předběžné požadavky.

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í funkce zabezpečení. CORS je standard W3C, který umožňuje serveru uvolnit zásady stejného původu.
    • Například herec se zlými úmysly může na vašem webu použít skriptování mezi weby (XSS) a provést žádost mezi weby s podporou CORS k krádeži informací.
  • Rozhraní API není bezpečnější tím, že umožňuje CORS.
    • Je na klientovi (prohlížeči) a vynucuje 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 serveru umožnit prohlížečům spouštět požadavek XHR nebo Fetch API mezi zdroji, které by jinak bylo zakázáno.
    • Prohlížeče bez CORS nemůžou provádět žádosti mezi zdroji. Před CORS JSse onP použil k obcházení tohoto omezení. JSONP nepoužívá XHR, k přijetí odpovědi používá <script> značku. Skripty je možné načíst mezi zdroji.

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 pro žádosti mezi zdroji. K povolení CORS se nevyžaduje vlastní javascriptový kód.

Tlačítko TEST PUT na nasazené ukázce

Následuje příklad požadavku mezi zdroji z tlačítka Test hodnot do https://cors1.azurewebsites.net/api/values. Hlavička Origin :

  • Poskytuje doménu lokality, která požadavek provádí.
  • 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žadavku

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 OPTIONS požadavcích server nastaví hlavičku hlavičkyAccess-Control-Allow-Origin: {allowed origin} odpovědi v odpovědi. Například nasazená ukázka obsahuje požadavek na tlačítko OPTIONS Delete [EnableCors] 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žadavku

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 nastaví v odpovědi hlavičku Access-Control-Allow-Origin . Hodnota https://cors1.azurewebsites.net této hlavičky odpovídá Origin hlavičce požadavku.

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

Pokud odpověď hlavičku Access-Control-Allow-Origin neobsahuje, požadavek mezi 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í HTTP na HTTPS způsobuje ERR_INVALID_REDIRECT předběžné žádosti CORS.

Požadavky na koncový bod pomocí protokolu HTTP, které jsou přesměrované na HTTPS, selžouUseHttpsRedirection.ERR_INVALID_REDIRECT on the CORS preflight request

Projekty rozhraní API můžou odmítnout požadavky HTTP místo toho UseHttpsRedirection , aby přesměrovály požadavky na HTTPS.

Zobrazení požadavků 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.
  • Restartujte.

Firefox zobrazuje ve výchozím nastavení žádosti 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 si stáhnout. 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();

Upozorňující

WithOrigins("https://localhost:<port>"); by se měla použít pouze k testování ukázkové aplikace podobné ukázkového kódu ke stažení.

ValuesController Následující body poskytují 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ů:

  • Použijte nasazenou ukázkovou aplikaci na adrese https://cors3.azurewebsites.net/. Ukázku není nutné stahovat.
  • Spusťte ukázku s dotnet run použitím výchozí adresy URL https://localhost:5001souboru .
  • 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 TEST PUT. 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 dokumentu, odpověď vrátí úspěch 200, ale požadavek CORS není proveden. Výběrem karty Konzola zobrazíte 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 vaše potřeby obsluhují neprůspatnou odpověď, nastavte režim požadavku na no-cors, aby se načítal prostředek se zakázaným CORS.

Koncové body s podporou CORS je možné testovat pomocí nástroje, jako je 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í mezi zdroji založený na hodnotě hlavičky Origin :

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

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 se směrováním koncových bodů a [HttpOptions]

Povolení CORS na základě jednotlivých koncových bodů v RequireCors současné době nepodporujeautomatické předběžné požadavky. 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();

TodoItems1Controller Následující body poskytují 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 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"
 },

TodoItems2Controller Následující body poskytují podobné koncové body, ale obsahují explicitní kód pro reakci na 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);
    }

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

Otestujte předchozí kód z testovací stránky nasazené ukázky. V rozevíracím seznamu Kontroler vyberte Předlet a pak Nastavte kontroler. Všechna volání CORS do TodoItems2Controller koncových bodů jsou úspěšná.

Další materiály

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ůže být vhodné povolit jiným webům, aby vaše aplikace zpřístupňovala žádosti mezi zdroji. Další informace naleznete v článku Mozilla CORS.

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

  • Je standard W3C, který umožňuje serveru uvolnit zásady stejného původu.
  • Není to funkce zabezpečení, CORS uvolní zabezpečení. Rozhraní API není bezpečnější tím, že umožňuje 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, jako JSje ONP.

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

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

Upozorňující

UseCors musí být volána ve správném pořadí. Další informace naleznete v tématu Pořadí middlewaru. UseCors Například musí být volána před UseResponseCaching použitím 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 mezi zdroji. 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:

  • Nastaví název zásady na _myAllowSpecificOrigins. Název zásady je libovolný.
  • Volá metodu UseCors rozšíření a určuje _myAllowSpecificOrigins zásady CORS. UseCors přidá middleware CORS. Hovor UseCors musí být umístěn za UseRouting, ale před UseAuthorization. Další informace naleznete v tématu Pořadí middlewaru.
  • Volání AddCors pomocí výrazu lambda Lambda přebírá CorsPolicyBuilder objekt. Možnosti konfigurace, například WithOrigins, jsou popsány dále v tomto článku.
  • Povolí zásadu _myAllowSpecificOrigins CORS pro všechny koncové body kontroleru. Podívejte se na směrování koncových bodů, abyste použili zásadu CORS na konkrétní koncové body.
  • Při použití odpovědi Ukládání do mezipaměti Middleware zavolejte UseCors před UseResponseCaching.

Se směrováním koncového bodu musí být middleware CORS nakonfigurovaný tak, aby se prováděl mezi voláními a UseRoutingUseEndpoints.

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

Volání AddCors metody přidá služby CORS do kontejneru služby 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ězený, 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 se /adresa URL ukončí, vrátí se porovnání false a nevrátí se žádná hlavička.

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.

Povolení Cors se směrováním koncových bodů

Povolení CORS na základě RequireCorsjednotlivých koncových bodů nepodporuje automatické předběžné požadavky. Další informace najdete v tomto problému na GitHubu a otestování 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. Vzhledem k tomu, že se nenakonfigurovala výchozí zásada, app.UseCors() samotná možnost CORS nepovoluje.
  • Koncové /echo body kontroleru umožňují požadavky mezi zdroji pomocí zadaných zásad.
  • Koncové /echo2 body stránky Razor neumožňují požadavky mezi zdroji, protože nebyly zadány žádné výchozí zásady.

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

Povolení CORS s atributy

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
  • Ovladač
  • 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. Doporučujeme kombinovat zásady. Pomocí tlačítka [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();
        });
    }
}

Nejlepší kontrolu nad omezováním požadavků CORS:

  • Používá se [EnableCors("MyPolicy")] s pojmenovanými zásadami.
  • Nedefinujte výchozí zásadu.
  • Nepoužívejte směrování koncového bodu.

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ána 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 CORS požadavky ze všech původů s jakýmkoli schématem (http nebo https). AllowAnyOrigin je nezabezpečený, protože každý web může do aplikace vyhovět žádostem mezi zdroji.

Poznámka:

AllowAnyOrigin Určení a AllowCredentials je nezabezpečená konfigurace 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();
    });

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ů

Pokud chcete povolit odesílání konkrétních hlaviček v požadavku CORS, označované jako hlavičky žádosti autora, volání WithHeaders a zadání povolených hlaviček:

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 předběžné požadavky a hlavičku Hlavičky žádostí o přístup. Další informace najdete v části Předběžné požadavky .

Zásady middlewaru CORS odpovídají konkrétním hlavičkám určeným WithHeaders pouze tehdy, když hlavičky odeslané přesně Access-Control-Request-Headers 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 mezi zdroji.

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 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 volá tyto hlavičky jednoduchých hlaviček 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 mezi zdroji. Přihlašovací údaje zahrnují cookieschémata ověřování HTTP. Chcete-li odeslat přihlašovací údaje s žádostí mezi zdroji, musí klient nastavit XMLHttpRequest.withCredentials na truehodnotu .

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. Pokud chcete povolit přihlašovací údaje mezi zdroji, 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 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.

Předběžné 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 volá 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 předběžný požadavek odepřen, aplikace vrátí 200 OK odpověď, ale nenastaví hlavičky CORS. Prohlížeč se proto nepokouší o požadavek mezi zdroji. Příklad odepřené předběžné žádosti najdete v části Testovací 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: Blokovaný požadavek mezi zdroji: Stejné zásady původu nepovolují čtení vzdáleného prostředku na adrese https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5. (Důvod: Požadavek CORS nebyl úspěšný). Další informace
  • Chromium: Zásady CORS zablokovaly přístup k načtení nahttps://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5 "' z původu'https://cors3.azurewebsites.net: Odpověď na předběžný požadavek neprojde kontrolou řízení přístupu: U požadovaného prostředku není k dispozici žádná hlavička Access-Control-Allow-Origin. Pokud vaše potřeby obsluhují neprůspatnou odpověď, nastavte režim požadavku na no-cors, aby se načítal prostředek se zakázaný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 je volána: Zahrňte alespoň Accept, Content-Typea , a Originnavíc všechny vlastní hlavičky, které chcete podporovat.

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

Při použití zásad CORS:

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

ASP.NET Core reaguje na předběžný požadavek OPTIONS.

Povolení CORS na základě jednotlivých koncových bodů v RequireCors současné době nepodporuje automatické předběžné požadavky.

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í funkce zabezpečení. CORS je standard W3C, který umožňuje serveru uvolnit zásady stejného původu.
    • Například herec se zlými úmysly může na vašem webu použít skriptování mezi weby (XSS) a provést žádost mezi weby s podporou CORS k krádeži informací.
  • Rozhraní API není bezpečnější tím, že umožňuje CORS.
    • Je na klientovi (prohlížeči) a vynucuje 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 serveru umožnit prohlížečům spouštět požadavek XHR nebo Fetch API mezi zdroji, které by jinak bylo zakázáno.
    • Prohlížeče bez CORS nemůžou provádět žádosti mezi zdroji. Před CORS JSse onP použil k obcházení tohoto omezení. JSONP nepoužívá XHR, k přijetí odpovědi používá <script> značku. Skripty je možné načíst mezi zdroji.

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 pro žádosti mezi zdroji. K povolení CORS se nevyžaduje vlastní javascriptový kód.

Tlačítko TEST PUT na nasazené ukázce

Následuje příklad požadavku mezi zdroji z tlačítka Test hodnot do https://cors1.azurewebsites.net/api/values. Hlavička Origin :

  • Poskytuje doménu lokality, která požadavek provádí.
  • 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žadavku

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 OPTIONS požadavcích server nastaví hlavičku hlavičkyAccess-Control-Allow-Origin: {allowed origin} odpovědi v odpovědi. Například nasazená ukázka obsahuje požadavek na tlačítko OPTIONS Delete [EnableCors] 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žadavku

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 nastaví v odpovědi hlavičku Access-Control-Allow-Origin . Hodnota https://cors1.azurewebsites.net této hlavičky odpovídá Origin hlavičce požadavku.

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

Pokud odpověď hlavičku Access-Control-Allow-Origin neobsahuje, požadavek mezi 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.

Zobrazení požadavků 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.
  • Restartujte.

Firefox zobrazuje ve výchozím nastavení žádosti 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 si stáhnout. 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();
        });
    }
}

Upozorňující

WithOrigins("https://localhost:<port>"); by se měla použít pouze k testování ukázkové aplikace podobné ukázkového kódu ke stažení.

ValuesController Následující body poskytují 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ů:

  • Použijte nasazenou ukázkovou aplikaci na adrese https://cors3.azurewebsites.net/. Ukázku není nutné stahovat.
  • Spusťte ukázku s dotnet run použitím výchozí adresy URL https://localhost:5001souboru .
  • 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 TEST PUT. 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 dokumentu, odpověď vrátí úspěch 200, ale požadavek CORS není proveden. Výběrem karty Konzola zobrazíte 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 vaše potřeby obsluhují neprůspatnou odpověď, nastavte režim požadavku na no-cors, aby se načítal prostředek se zakázaným CORS.

Koncové body s podporou CORS je možné testovat pomocí nástroje, jako je 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í mezi zdroji založený na hodnotě hlavičky Origin :

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

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 se směrováním koncových bodů a [HttpOptions]

Povolení CORS na základě jednotlivých koncových bodů v RequireCors současné době nepodporujeautomatické předběžné požadavky. 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();
        });
    }
}

TodoItems1Controller Následující body poskytují 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 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"
 },

TodoItems2Controller Následující body poskytují podobné koncové body, ale obsahují explicitní kód pro reakci na 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);
    }

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

Otestujte předchozí kód z testovací stránky nasazené ukázky. V rozevíracím seznamu Kontroler vyberte Předlet a pak Nastavte kontroler. Všechna volání CORS do TodoItems2Controller koncových bodů jsou úspěšná.

Další materiály