Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Note
Toto není nejnovější verze tohoto článku. Aktuální verzi najdete ve verzi .NET 10 tohoto článku.
Warning
Tato verze ASP.NET Core se už nepodporuje. Další informace najdete v zásadách podpory .NET a .NET Core. Aktuální verzi najdete ve verzi .NET 10 tohoto článku.
Autoři: Rick Anderson a Kirk Larkin
Tento článek ukazuje, jak v aplikaci ASP.NET Core povolit sdílení mezi různýmizdrojiprostředků (CORS).
Zabezpečení prohlížeče zabraňuje tomu, aby webová stránka odesílala požadavky do jiné domény, než je ta, která webovou stránku obsluhuje. Toto omezení se označuje jako zásada stejného zdroje. Zásada stejného zdroje brání škodlivým webům ve čtení citlivých dat z jiných webů. Někdy můžete chtít povolit jiným webům odesílat do vaší aplikace požadavky z jiného původu. Další informace naleznete v článku Mozilla CORS.
Sdílení prostředků mezi zdroji původu (CORS):
- Je to standard W3C, který umožňuje serveru zmírnit politiku stejného původu.
- Nejedná se o bezpečnostní funkci, CORS oslabuje zabezpečení. Rozhraní API není bezpečnější jen proto, že povoluje CORS. Další informace najdete v tématu Jak CORS funguje.
- Umožňuje serveru explicitně povolit některé požadavky mezi zdroji a zároveň odmítnout jiné.
- Je bezpečnější a flexibilnější než dřívější techniky, například JSONP.
Zobrazení nebo stažení ukázkového kódu (postup stažení)
Stejný původ
Dvě adresy URL mají stejný původ, pokud mají stejná schémata, hostitele a porty (RFC 6454).
Tyto dvě adresy URL mají stejný původ:
https://example.com/foo.htmlhttps://example.com/bar.html
Tyto adresy URL mají jiný původ než předchozí dvě adresy URL:
-
https://example.net: Jiná doména -
https://contoso.example.com/foo.html: Jiná subdoména -
http://example.com/foo.html: Jiné schéma -
https://example.com:9000/foo.html: Jiný port
Povolit CORS
CORS můžete povolit třemi způsoby:
- V middlewaru pomocí pojmenované zásady nebo výchozí zásady.
- Použití směrování koncových bodů.
- S atributem [EnableCors]
Použití atributu [EnableCors] s pojmenovanou zásadou poskytuje nejlepší kontrolu v omezení koncových bodů, které podporují CORS.
Warning
UseCors musí být volána ve správném pořadí. Další informace najdete v tématu Pořadí middlewaru. Například UseCors musí být volána před UseResponseCaching při použití UseResponseCaching.
Každý přístup je podrobně popsaný v následujících částech.
CORS s pojmenovanými zásadami a middlewarem
Middleware CORS zpracovává požadavky z různých zdrojů. Následující kód použije zásadu CORS pro všechny koncové body aplikace se zadanými zdroji:
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com");
});
});
// services.AddResponseCaching();
builder.Services.AddControllers();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors(MyAllowSpecificOrigins);
app.UseAuthorization();
app.MapControllers();
app.Run();
Předchozí kód:
- Nastaví název zásady na
_myAllowSpecificOrigins. Název zásady je libovolný. - Volá UseCors metodu rozšíření a zadává zásadu CORS
_myAllowSpecificOrigins.UseCorspřidá middleware CORS. HovorUseCorsmusí být umístěn zaUseRouting, ale předUseAuthorization. Další informace najdete v tématu Pořadí middlewaru. - Volá 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
_myAllowSpecificOriginsCORS pro všechny koncové body kontroleru. Informace o směrování koncových bodů najdete v části, jak použít zásadu CORS pro konkrétní koncové body. - Při použití middlewaru ukládání odpovědí do mezipaměti zavolejte UseCors před UseResponseCaching.
Při směrování koncových bodů musí být middleware CORS nakonfigurován tak, aby se spouštěl mezi volánímiUseRouting a UseEndpoints.
Volání metody AddCors přidá služby CORS do kontejneru služeb aplikace:
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com");
});
});
// services.AddResponseCaching();
builder.Services.AddControllers();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors(MyAllowSpecificOrigins);
app.UseAuthorization();
app.MapControllers();
app.Run();
Další informace najdete v tématu Možnosti zásad CORS v tomto dokumentu.
Metody CorsPolicyBuilder mohou být zřetězeny, jak je znázorněno v následujícím kódu:
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
builder.Services.AddControllers();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors(MyAllowSpecificOrigins);
app.UseAuthorization();
app.MapControllers();
app.Run();
Poznámka: Zadaná adresa URL nesmí obsahovat koncové lomítko (/). Pokud adresa URL končí na /, porovnání vrátí false a nevrátí se žádné záhlaví.
Pořadí UseCors a UseStaticFiles
Obvykle se UseStaticFiles volá před UseCors. Aplikace, které používají JavaScript k načítání statických souborů z jiného webu, musí volat UseCors před UseStaticFiles.
CORS s výchozími zásadami a middlewarem
Následující zvýrazněný kód povolí výchozí zásady CORS:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com");
});
});
builder.Services.AddControllers();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.MapControllers();
app.Run();
Předchozí kód použije výchozí zásady CORS pro všechny koncové body kontroleru.
Povolte CORS pomocí směrování koncových bodů
Pomocí směrování koncového bodu je možné CORS povolit pro jednotlivé koncové body pomocí RequireCors sady rozšiřujících metod:
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com");
});
});
builder.Services.AddControllers();
builder.Services.AddRazorPages();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/echo",
context => context.Response.WriteAsync("echo"))
.RequireCors(MyAllowSpecificOrigins);
endpoints.MapControllers()
.RequireCors(MyAllowSpecificOrigins);
endpoints.MapGet("/echo2",
context => context.Response.WriteAsync("echo2"));
endpoints.MapRazorPages();
});
app.Run();
V předchozím kódu:
-
app.UseCorspovolí middleware CORS. Protože není nakonfigurovaná výchozí politika, samotnéapp.UseCors()CORS nepovolí. - Koncové body
/echoa kontroleru umožňují požadavky z různých zdrojů podle zadaných zásad. - Koncové body stránek
/echo2a Razorneumožňují požadavky z různých zdrojů, protože nebyla zadána žádná výchozí zásada.
Atribut [DisableCors] nezakazujeCORS, které bylo povoleno směrováním koncového bodu s RequireCors.
Pokyny k testování kódu podobného předchozímu kódu najdete v části Test CORS s atributem [EnableCors] a metodou RequireCors.
Povolit CORS pomocí atributů
Povolení CORS pomocí atributu [EnableCors] a použití pojmenované zásady pouze na koncové body, které vyžadují CORS, poskytuje nejlepší kontrolu.
Atribut [EnableCors] poskytuje alternativu k použití CORS globálně. Tento [EnableCors] atribut umožňuje CORS pro vybrané koncové body, nikoli pro všechny koncové body:
-
[EnableCors]určuje výchozí zásadu. -
[EnableCors("{Policy String}")]určuje pojmenovanou zásadu.
Atribut [EnableCors] lze použít na:
-
Razor Stránka
PageModel - Controller
- Metoda akce kontroleru
U kontrolerů, modelů stránek nebo metod akcí s atributem [EnableCors] je možné použít různé zásady.
[EnableCors] Když se atribut použije u kontroleru, modelu stránky nebo metody akce a CORS je v middlewaru povolený, použijí se obě zásady. Nedoporučujeme kombinovat zásady. Použijte
[EnableCors]
atribut nebo middleware, ne oba ve stejné aplikaci.
Následující kód použije pro každou metodu jinou zásadu:
[Route("api/[controller]")]
[ApiController]
public class WidgetController : ControllerBase
{
// GET api/values
[EnableCors("AnotherPolicy")]
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
return new string[] { "green widget", "red widget" };
}
// GET api/values/5
[EnableCors("Policy1")]
[HttpGet("{id}")]
public ActionResult<string> Get(int id)
{
return id switch
{
1 => "green widget",
2 => "red widget",
_ => NotFound(),
};
}
}
Následující kód vytvoří dvě zásady CORS:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy("Policy1",
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com");
});
options.AddPolicy("AnotherPolicy",
policy =>
{
policy.WithOrigins("http://www.contoso.com")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
builder.Services.AddControllers();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.MapControllers();
app.Run();
Pro co nejpřesnější kontrolu omezení požadavků CORS:
- Použijte
[EnableCors("MyPolicy")]s pojmenovanou zásadou. - Nedefinujte výchozí zásadu.
- Nepoužívejte směrování koncových bodů.
Kód v další části odpovídá předchozímu seznamu.
Zakázání CORS
Atribut [DisableCors] nezakazujeCORS, které bylo povoleno směrováním koncového bodu.
Následující kód definuje zásadu "MyPolicy"CORS:
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: "MyPolicy",
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com")
.WithMethods("PUT", "DELETE", "GET");
});
});
builder.Services.AddControllers();
builder.Services.AddRazorPages();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.UseEndpoints(endpoints => {
endpoints.MapControllers();
endpoints.MapRazorPages();
});
app.Run();
Následující kód zakáže CORS pro GetValues2 akci:
[EnableCors("MyPolicy")]
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
// GET api/values
[HttpGet]
public IActionResult Get() =>
ControllerContext.MyDisplayRouteInfo();
// GET api/values/5
[HttpGet("{id}")]
public IActionResult Get(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
// PUT api/values/5
[HttpPut("{id}")]
public IActionResult Put(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
// GET: api/values/GetValues2
[DisableCors]
[HttpGet("{action}")]
public IActionResult GetValues2() =>
ControllerContext.MyDisplayRouteInfo();
}
Předchozí kód:
- Nepovoluje CORS pomocí směrování koncových bodů.
- Nedefinuje výchozí zásady CORS.
- Pomocí funkce [EnableCors("MyPolicy")] povolí
"MyPolicy"zásady CORS pro kontroler. - Zakáže CORS pro metodu
GetValues2.
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:
- Nastavení povolených zdrojů
- Nastavení povolených metod HTTP
- Nastavení hlaviček povolených požadavků
- Nastavení vystavených hlaviček odpovědí
- Přihlašovací údaje v požadavcích mezi různými zdroji
- Nastavení doby předběžného vypršení platnosti
AddPolicy je voláno v Program.cs. U některých možností může být užitečné nejprve přečíst část Jak CORS funguje .
Nastavení povolených zdrojů
AllowAnyOrigin: Umožňuje požadavky CORS ze všech zdrojů s jakýmkoli schématem (http nebo https).
AllowAnyOrigin není zabezpečená, protože jakýkoli web může na aplikaci odesílat cross-origin požadavky.
Warning
Zadání AllowAnyOrigin a AllowCredentials představuje nezabezpečenou konfiguraci a může vést k padělání požadavků mezi weby. Služba CORS vrátí neplatnou odpověď CORS, když je aplikace nakonfigurovaná s oběma metodami. Obejití předdefinovaných kontrol pomocí SetIsOriginAllowed(_ => true) společně s AllowCredentials je také nezabezpečená konfigurace.
AllowAnyOrigin ovlivňuje předběžné požadavky a hlavičku Access-Control-Allow-Origin . Další informace najdete v části Předběžné požadavky .
SetIsOriginAllowedToAllowWildcardSubdomains: Nastaví IsOriginAllowed vlastnost zásady na funkci, která umožňuje, aby zdroje odpovídaly nakonfigurované zástupné doméně při vyhodnocování, zda je původ povolený.
var MyAllowSpecificOrigins = "_MyAllowSubdomainPolicy";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("https://*.example.com")
.SetIsOriginAllowedToAllowWildcardSubdomains();
});
});
builder.Services.AddControllers();
var app = builder.Build();
V předchozím kódu je SetIsOriginAllowedToAllowWildcardSubdomains volána se zástupným znakem domény "https://*.example.com". Toto nastavení umožňuje CORS žádosti z jakékoli subdomény example.com, jako https://subdomain.example.com nebo https://api.example.com. Zástupný znak * musí být zahrnut v původu, aby umožnil porovnávání subdomén pomocí zástupných znaků.
Nastavení povolených metod HTTP
- Povoluje libovolnou metodu HTTP:
- Ovlivňuje předběžné požadavky a hlavičku
Access-Control-Allow-Methods. Další informace najdete v části Předběžné požadavky .
Nastavení hlaviček povolených požadavků
Chcete-li povolit odesílání konkrétních hlaviček v požadavku CORS, označovaných jako hlavičky požadavku autora, zavolejte WithHeaders a zadejte povolené hlavičky:
using Microsoft.Net.Http.Headers;
var MyAllowSpecificOrigins = "_MyAllowSubdomainPolicy";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("http://example.com")
.WithHeaders(HeaderNames.ContentType, "x-custom-header");
});
});
builder.Services.AddControllers();
var app = builder.Build();
Pokud chcete povolit všechna záhlaví žádosti autora, zavolejte AllowAnyHeader:
var MyAllowSpecificOrigins = "_MyAllowSubdomainPolicy";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("https://*.example.com")
.AllowAnyHeader();
});
});
builder.Services.AddControllers();
var app = builder.Build();
AllowAnyHeader ovlivňuje preflight požadavky a hlavičku Access-Control-Request-Headers. Další informace najdete v části Předběžné požadavky .
Shoda zásady middlewaru CORS s konkrétními hlavičkami zadanými pomocí WithHeaders je možná pouze tehdy, když hlavičky odeslané v Access-Control-Request-Headers přesně odpovídají hlavičkám uvedeným v WithHeaders.
Představte si například aplikaci nakonfigurovanou takto:
app.UseCors(policy => policy.WithHeaders(HeaderNames.CacheControl));
Middleware CORS odmítne předběžný požadavek s následující hlavičkou požadavku, protože Content-Language (HeaderNames.ContentLanguage) není uvedený v WithHeaders:
Access-Control-Request-Headers: Cache-Control, Content-Language
Aplikace vrátí 204 No Content odpověď, ale neodesílá hlavičky CORS zpět. Prohlížeč se proto nepokouší o požadavek na jiný původ.
Nastavení vystavených hlaviček odpovědí
Ve výchozím nastavení prohlížeč nezpřístupňuje do aplikace všechny hlavičky odpovědi. Další informace najdete v tématu Sdílení prostředků mezi různými zdroji W3C (terminologie): jednoduchá hlavička odpovědi.
Hlavičky odpovědi, které jsou ve výchozím nastavení k dispozici, jsou:
Cache-ControlContent-LanguageContent-TypeExpiresLast-ModifiedPragma
Specifikace CORS tyto hlavičky označuje jako jednoduché hlavičky odpovědi. Pokud chcete aplikaci zpřístupnit další hlavičky, zavolejte WithExposedHeaders:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy("MyExposeResponseHeadersPolicy",
policy =>
{
policy.WithOrigins("https://*.example.com")
.WithExposedHeaders("x-custom-header");
});
});
builder.Services.AddControllers();
var app = builder.Build();
Přihlašovací údaje v požadavcích mezi zdroji
Přihlašovací údaje vyžadují speciální zpracování v požadavku CORS. Ve výchozím nastavení prohlížeč neodesílá přihlašovací údaje s požadavkem z jiného původu. Přihlašovací údaje zahrnují soubory cookie a schémata ověřování HTTP. Chcete-li odeslat přihlašovací údaje s požadavkem mezi zdroji, musí klient nastavit XMLHttpRequest.withCredentials na hodnotu true.
Přímé použití XMLHttpRequest :
var xhr = new XMLHttpRequest();
xhr.open('get', 'https://www.example.com/api/test');
xhr.withCredentials = true;
Pomocí jQuery:
$.ajax({
type: 'get',
url: 'https://www.example.com/api/test',
xhrFields: {
withCredentials: true
}
});
Použití rozhraní Fetch API:
fetch('https://www.example.com/api/test', {
credentials: 'include'
});
Server musí přihlašovací údaje povolit. Chcete-li povolit pověření pro různé zdroje, zavolejte AllowCredentials:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy("MyMyAllowCredentialsPolicy",
policy =>
{
policy.WithOrigins("http://example.com")
.AllowCredentials();
});
});
builder.Services.AddControllers();
var app = builder.Build();
Odpověď HTTP obsahuje hlavičku Access-Control-Allow-Credentials , která prohlížeči říká, že server povoluje přihlašovací údaje pro požadavek mezi zdroji.
Pokud prohlížeč odešle přihlašovací údaje, ale odpověď neobsahuje platnou Access-Control-Allow-Credentials hlavičku, prohlížeč nezobrazí odpověď aplikaci a požadavek mezi zdroji selže.
Povolení přihlašovacích údajů mezi různými zdroji představuje bezpečnostní riziko. Web v jiné doméně může odeslat přihlašovací údaje přihlášeného uživatele do aplikace jménem uživatele bez vědomí uživatele.
Specifikace CORS také uvádí, že nastavení původu na "*" (všechny zdroje) je neplatné, pokud je hlavička Access-Control-Allow-Credentials přítomna.
Preflightové požadavky
U některých požadavků CORS prohlížeč před provedením skutečného požadavku odešle další požadavek OPTIONS . Tento požadavek se nazývá předběžný požadavek. Prohlížeč může předběžný požadavek přeskočit, pokud jsou splněny všechny následující podmínky:
- Metoda požadavku je GET, HEAD nebo POST.
- Aplikace nenastavuje jiné hlavičky požadavků než
Accept,Accept-Language,Content-Language, ,Content-TypeneboLast-Event-ID. - Hlavička
Content-Type, pokud je nastavená, má jednu z následujících hodnot:application/x-www-form-urlencodedmultipart/form-datatext/plain
Pravidlo hlavičky požadavku nastavené pro požadavek klienta se vztahuje na hlavičky, které aplikace nastaví voláním setRequestHeader objektu XMLHttpRequest . Specifikace CORS označuje tyto hlavičky jako hlavičky požadavku autora. Pravidlo se nevztahuje na hlavičky, které může prohlížeč nastavit, například User-Agent, Hostnebo Content-Length.
Note
Tento článek obsahuje adresy URL vytvořené nasazením ukázkového kódu na dva weby https://cors3.azurewebsites.net Azure a https://cors.azurewebsites.net.
Následuje příklad odpovědi podobné předběžnému požadavku vytvořenému z tlačítka [Put test] v části Test CORS tohoto dokumentu.
General:
Request URL: https://cors3.azurewebsites.net/api/values/5
Request Method: OPTIONS
Status Code: 204 No Content
Response Headers:
Access-Control-Allow-Methods: PUT,DELETE,GET
Access-Control-Allow-Origin: https://cors1.azurewebsites.net
Server: Microsoft-IIS/10.0
Set-Cookie: ARRAffinity=8f8...8;Path=/;HttpOnly;Domain=cors1.azurewebsites.net
Vary: Origin
Request Headers:
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Access-Control-Request-Method: PUT
Connection: keep-alive
Host: cors3.azurewebsites.net
Origin: https://cors1.azurewebsites.net
Referer: https://cors1.azurewebsites.net/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0
Předběžný požadavek používá metodu HTTP OPTIONS . Může obsahovat následující hlavičky:
- Access-Control-Request-Method: Metoda HTTP, která se použije pro skutečný požadavek.
-
Access-Control-Request-Headers: Seznam hlaviček žádosti, které aplikace nastaví ve skutečném požadavku. Jak jsme uvedli dříve, nezahrnuje hlavičky, které prohlížeče nastaví, například
User-Agent.
Pokud je preflight požadavek zamítnut, aplikace vrátí odpověď 204 No Content, ale nenastaví hlavičky CORS. Prohlížeč se proto nepokouší o požadavek na jiný původ. Příklad zamítnutého preflightového požadavku najdete v části Test CORS tohoto dokumentu.
Pomocí nástrojů F12 konzolová aplikace zobrazí v závislosti na prohlížeči chybu podobnou jedné z následujících možností:
- Firefox: Požadavek mezi různými zdroji byl zablokován: Zásada stejného původu nepovoluje přístup ke vzdálenému prostředku na adrese
https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5. (Důvod: Požadavek CORS nebyl úspěšný). Zjistit více - Založeno na Chromiu: Přístup k načtení na adrese 'https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5' z původu 'https://cors3.azurewebsites.net' byl zablokován zásadami CORS: Odpověď na předběžný požadavek neprošla kontrolou řízení přístupu: v požadovaném prostředku není přítomna žádná hlavička 'Access-Control-Allow-Origin'. Pokud vám vyhovuje neprůhledná odpověď, nastavte režim požadavku na 'no-cors' pro načtení prostředku s vypnutým CORS.
Pokud chcete povolit konkrétní záhlaví, zavolejte WithHeaders:
using Microsoft.Net.Http.Headers;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy("MyAllowHeadersPolicy",
policy =>
{
policy.WithOrigins("http://example.com")
.WithHeaders(HeaderNames.ContentType, "x-custom-header");
});
});
builder.Services.AddControllers();
var app = builder.Build();
Pokud chcete povolit všechna záhlaví žádosti autora, zavolejte AllowAnyHeader:
using Microsoft.Net.Http.Headers;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy("MyAllowAllHeadersPolicy",
policy =>
{
policy.WithOrigins("https://*.example.com")
.AllowAnyHeader();
});
});
builder.Services.AddControllers();
var app = builder.Build();
Prohlížeče nejsou konzistentní ve způsobu jejich nastavení Access-Control-Request-Headers. Pokud máte některou z těchto:
- Záhlaví jsou nastavená na cokoli jiného než
"*" -
AllowAnyHeader se nazývá: Zahrňte alespoň
Accept,Content-TypeaOrigina všechny vlastní hlavičky, které chcete podporovat.
Automatický předletový kód požadavku
Pokud se použije zásada CORS:
- Globálně voláním
app.UseCorsvProgram.cs. - Použití atributu
[EnableCors]
ASP.NET Core odpovídá na předběžný dotaz OPTIONS.
Toto chování ukazuje část Test CORS tohoto dokumentu.
Atribut [HttpOptions] pro předběžné požadavky
Když je CORS povolená s příslušnými zásadami, ASP.NET Core obvykle automaticky reaguje na předběžné požadavky CORS.
Následující kód používá atribut [HttpOptions] k vytvoření koncových bodů pro požadavky OPTIONS:
[Route("api/[controller]")]
[ApiController]
public class TodoItems2Controller : ControllerBase
{
// OPTIONS: api/TodoItems2/5
[HttpOptions("{id}")]
public IActionResult PreflightRoute(int id)
{
return NoContent();
}
// OPTIONS: api/TodoItems2
[HttpOptions]
public IActionResult PreflightRoute()
{
return NoContent();
}
[HttpPut("{id}")]
public IActionResult PutTodoItem(int id)
{
if (id < 1)
{
return BadRequest();
}
return ControllerContext.MyDisplayRouteInfo(id);
}
Pokyny k testování předchozího kódu najdete v části Test CORS s atributem [EnableCors] a metodou RequireCors.
Nastavení doby předběžného vypršení platnosti
Hlavička Access-Control-Max-Age určuje, jak dlouho může být odpověď na předběžný požadavek uložena do mezipaměti. Chcete-li nastavit toto záhlaví, zavolejte SetPreflightMaxAge:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy("MySetPreflightExpirationPolicy",
policy =>
{
policy.WithOrigins("http://example.com")
.SetPreflightMaxAge(TimeSpan.FromSeconds(2520));
});
});
builder.Services.AddControllers();
var app = builder.Build();
Povolte CORS na koncovém bodu
Jak CORS funguje
Tato část popisuje, co se stane v požadavku CORS na úrovni zpráv HTTP.
- CORS není bezpečnostní funkce. CORS je standard W3C, který umožňuje serveru uvolnit zásady stejného původu.
- Například by škodlivý útočník mohl proti vašemu webu použít Cross-Site Scripting (XSS) a odeslat požadavek mezi weby na svůj web s povoleným CORS, aby odcizil informace.
- API není bezpečnější tím, že umožňuje CORS.
- Je na klientovi (prohlížeči), aby vynucoval CORS. Server spustí požadavek a vrátí odpověď. Je to klient, který vrací chybu a blokuje odpověď. Například některý z následujících nástrojů zobrazí odpověď serveru:
- Fiddler
- .NET HttpClient
- Ve webovém prohlížeči zadáním adresy URL do adresního řádku.
- Je na klientovi (prohlížeči), aby vynucoval CORS. Server spustí požadavek a vrátí odpověď. Je to klient, který vrací chybu a blokuje odpověď. Například některý z následujících nástrojů zobrazí odpověď serveru:
- Je to způsob, jak server umožňuje prohlížečům provést požadavek XHR nebo Fetch API z jiné domény, který by jinak byl zakázán.
- Prohlížeče bez CORS nemůžou provádět žádosti mezi zdroji. Před CORS se k obejití tohoto omezení použil JSONP . JSONP nepoužívá XHR, k přijetí odpovědi používá
<script>značku. Skripty je povoleno načítat z jiného původu.
- Prohlížeče bez CORS nemůžou provádět žádosti mezi zdroji. Před CORS se k obejití tohoto omezení použil JSONP . JSONP nepoužívá XHR, k přijetí odpovědi používá
Specifikace CORS zavedla několik nových hlaviček HTTP, které umožňují požadavky mezi zdroji. Pokud prohlížeč podporuje CORS, nastaví tato záhlaví automaticky u požadavků z jiného původu. K povolení CORS se nevyžaduje vlastní javascriptový kód.
Následuje příklad požadavku mezi různými zdroji z testovacího tlačítka Values do https://cors1.azurewebsites.net/api/values. Hlavička Origin :
- Poskytuje doménu webu, který odesílá požadavek.
- Vyžaduje se a musí se lišit od hostitele.
Obecné hlavičky
Request URL: https://cors1.azurewebsites.net/api/values
Request Method: GET
Status Code: 200 OK
Hlavičky odpovědi
Content-Encoding: gzip
Content-Type: text/plain; charset=utf-8
Server: Microsoft-IIS/10.0
Set-Cookie: ARRAffinity=8f...;Path=/;HttpOnly;Domain=cors1.azurewebsites.net
Transfer-Encoding: chunked
Vary: Accept-Encoding
X-Powered-By: ASP.NET
Hlavičky požadavků
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Connection: keep-alive
Host: cors1.azurewebsites.net
Origin: https://cors3.azurewebsites.net
Referer: https://cors3.azurewebsites.net/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0 ...
V požadavcích OPTIONS server v odpovědi nastaví hlavičku Response headersAccess-Control-Allow-Origin: {allowed origin}. Například v ukázkovém kódu Delete [EnableCors] obsahuje požadavek na tlačítko OPTIONS následující hlavičky:
Obecné hlavičky
Request URL: https://cors3.azurewebsites.net/api/TodoItems2/MyDelete2/5
Request Method: OPTIONS
Status Code: 204 No Content
Hlavičky odpovědi
Access-Control-Allow-Headers: Content-Type,x-custom-header
Access-Control-Allow-Methods: PUT,DELETE,GET,OPTIONS
Access-Control-Allow-Origin: https://cors1.azurewebsites.net
Server: Microsoft-IIS/10.0
Set-Cookie: ARRAffinity=8f...;Path=/;HttpOnly;Domain=cors3.azurewebsites.net
Vary: Origin
X-Powered-By: ASP.NET
Hlavičky požadavků
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Access-Control-Request-Headers: content-type
Access-Control-Request-Method: DELETE
Connection: keep-alive
Host: cors3.azurewebsites.net
Origin: https://cors1.azurewebsites.net
Referer: https://cors1.azurewebsites.net/test?number=2
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0
V předchozích hlavičkách odpovědi server v odpovědi nastaví hlavičku Access-Control-Allow-Origin. Hodnota https://cors1.azurewebsites.net této hlavičky odpovídá Origin hlavičce požadavku.
Pokud je zavoláno AllowAnyOrigin, vrátí se Access-Control-Allow-Origin: *, zástupná hodnota.
AllowAnyOrigin umožňuje jakýkoli původ.
Pokud odpověď neobsahuje hlavičku Access-Control-Allow-Origin, požadavek mezi různými zdroji selže. Konkrétně prohlížeč požadavek zakáže. I když server vrátí úspěšnou odpověď, prohlížeč nepřístupní odpověď klientské aplikaci.
Přesměrování z HTTP na HTTPS způsobuje chybu ERR_INVALID_REDIRECT u předběžného požadavku CORS.
Požadavky na koncový bod používající HTTP, které UseHttpsRedirection přesměruje na HTTPS, selžou s chybou ERR_INVALID_REDIRECT on the CORS preflight request.
Projekty API mohou odmítat požadavky HTTP namísto použití UseHttpsRedirection k přesměrování požadavků na HTTPS.
CORS ve službě IIS
Při nasazování do služby IIS musí CORS běžet před ověřováním systému Windows, pokud server není nakonfigurovaný tak, aby povoloval anonymní přístup. Pro podporu tohoto scénáře je potřeba nainstalovat a nakonfigurovat modul CORS služby IIS pro aplikaci.
Testování CORS
Ukázkový soubor ke stažení obsahuje kód pro testování CORS. Podívejte se, jak stahovat. Ukázka je projekt rozhraní API s přidanými stránkami Razor :
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: "MyPolicy",
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com",
"https://cors1.azurewebsites.net",
"https://cors3.azurewebsites.net",
"https://localhost:44398",
"https://localhost:5001")
.WithMethods("PUT", "DELETE", "GET");
});
});
builder.Services.AddControllers();
builder.Services.AddRazorPages();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.MapControllers();
app.MapRazorPages();
app.Run();
Warning
WithOrigins("https://localhost:<port>"); lze použít pouze k testování ukázkové aplikace podobné jako ukázkový kód ke stažení.
Note
Pokud používáte launchSettings.json v sadě Visual Studio nebo konfigurujete nastavení ladění jazyka C# ve VS Code a k místnímu ladění používáte službu IIS Express, ujistěte se, že jste nakonfigurovali službu IIS Express pro "anonymousAuthentication": true. Pokud je "anonymousAuthentication" nastaveno na false, hostitel webového prostředí ASP.NET Core neuvidí žádné předběžné dotazy. Konkrétně pokud používáte ověřování NTLM ("windowsAuthentication": true), prvním krokem výzvy NTLM je odeslání webového prohlížeče a výzvy 401, což může usnadnit ověření správné konfigurace předletové trasy.
ValuesController Následující text uvádí koncové body pro testování:
[EnableCors("MyPolicy")]
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
// GET api/values
[HttpGet]
public IActionResult Get() =>
ControllerContext.MyDisplayRouteInfo();
// GET api/values/5
[HttpGet("{id}")]
public IActionResult Get(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
// PUT api/values/5
[HttpPut("{id}")]
public IActionResult Put(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
// GET: api/values/GetValues2
[DisableCors]
[HttpGet("{action}")]
public IActionResult GetValues2() =>
ControllerContext.MyDisplayRouteInfo();
}
MyDisplayRouteInfo poskytuje balíček NuGet Rick.Docs.Samples.RouteInfo a zobrazí informace o trase.
Otestujte předchozí vzorový kód pomocí jednoho z následujících přístupů:
- Spusťte ukázku pomocí
dotnet runs výchozí adresou URLhttps://localhost:5001. - Spusťte ukázku ze sady Visual Studio s portem nastaveným na 44398 pro adresu URL souboru
https://localhost:44398.
Použití prohlížeče s nástroji F12:
Vyberte tlačítko Hodnoty a zkontrolujte záhlaví na kartě Síť.
Vyberte tlačítko PUT test. Pokyny k zobrazení požadavku OPTIONS najdete v části Zobrazení MOŽNOSTÍ . Test PUT vytvoří dva požadavky, předběžný požadavek OPTIONS a požadavek PUT.
GetValues2 [DisableCors]Výběrem tlačítka aktivujte neúspěšný požadavek CORS. Jak je uvedeno v dokumentaci, odpověď vrátí stavový kód 200 (OK), ale požadavek CORS se neodešle. Vyberte kartu Konzola a zobrazte chybu CORS. V závislosti na prohlížeči se zobrazí chyba podobná této:Zásady CORS blokovaly přístup k načtení
'https://cors1.azurewebsites.net/api/values/GetValues2'z zdroje'https://cors3.azurewebsites.net': U požadovaného prostředku není k dispozici žádná hlavička Access-Control-Allow-Origin. Pokud vám vyhovuje neprůhledná odpověď, nastavte režim požadavku na 'no-cors' pro načtení prostředku s vypnutým CORS.
Koncové body s povoleným CORS lze testovat pomocí nástrojů, jako jsou curl nebo Fiddler. Při použití nástroje se původ požadavku určeného Origin hlavičkou musí lišit od hostitele, který požadavek přijímá. Pokud požadavek není na základě hodnoty hlavičky považován za Origin:
- Není nutné, aby middleware CORS zpracovával požadavek.
- Hlavičky CORS nejsou v odpovědi vráceny.
Následující příkaz používá curl k vydání požadavku OPTIONS s informacemi:
curl -X OPTIONS https://cors3.azurewebsites.net/api/TodoItems2/5 -i
Testování CORS s atributem [EnableCors] a metodou RequireCors
Zvažte následující kód, který používá směrování koncových bodů k povolení CORS na základě jednotlivých koncových bodů pomocí RequireCors:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: "MyPolicy",
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com",
"https://cors1.azurewebsites.net",
"https://cors3.azurewebsites.net",
"https://localhost:44398",
"https://localhost:5001")
.WithMethods("PUT", "DELETE", "GET");
});
});
builder.Services.AddControllers();
builder.Services.AddRazorPages();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/echo",
context => context.Response.WriteAsync("echo"))
.RequireCors("MyPolicy");
endpoints.MapControllers();
endpoints.MapRazorPages();
});
app.Run();
Všimněte si, že pouze koncový bod /echo používá RequireCors k povolení požadavků z různých zdrojů pomocí zadané zásady. Následující kontrolery povolují CORS pomocí atributu [EnableCors].
Následující TodoItems1Controller poskytuje koncové body pro testování:
[Route("api/[controller]")]
[ApiController]
public class TodoItems1Controller : ControllerBase
{
// PUT: api/TodoItems1/5
[HttpPut("{id}")]
public IActionResult PutTodoItem(int id) {
if (id < 1) {
return Content($"ID = {id}");
}
return ControllerContext.MyDisplayRouteInfo(id);
}
// Delete: api/TodoItems1/5
[HttpDelete("{id}")]
public IActionResult MyDelete(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
// GET: api/TodoItems1
[HttpGet]
public IActionResult GetTodoItems() =>
ControllerContext.MyDisplayRouteInfo();
[EnableCors("MyPolicy")]
[HttpGet("{action}")]
public IActionResult GetTodoItems2() =>
ControllerContext.MyDisplayRouteInfo();
// Delete: api/TodoItems1/MyDelete2/5
[EnableCors("MyPolicy")]
[HttpDelete("{action}/{id}")]
public IActionResult MyDelete2(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
}
Tlačítka Delete [EnableCors] a GET [EnableCors] jsou úspěšná, protože koncové body mají [EnableCors] a reagují na předběžné požadavky. Ostatní koncové body selžou. Tlačítko GET selže, protože JavaScript odesílá:
headers: {
"Content-Type": "x-custom-header"
},
Následující TodoItems2Controller poskytuje podobné endpointy, ale obsahuje explicitní kód pro zpracování požadavků OPTIONS:
[Route("api/[controller]")]
[ApiController]
public class TodoItems2Controller : ControllerBase
{
// OPTIONS: api/TodoItems2/5
[HttpOptions("{id}")]
public IActionResult PreflightRoute(int id)
{
return NoContent();
}
// OPTIONS: api/TodoItems2
[HttpOptions]
public IActionResult PreflightRoute()
{
return NoContent();
}
[HttpPut("{id}")]
public IActionResult PutTodoItem(int id)
{
if (id < 1)
{
return BadRequest();
}
return ControllerContext.MyDisplayRouteInfo(id);
}
// [EnableCors] // Not needed as OPTIONS path provided.
[HttpDelete("{id}")]
public IActionResult MyDelete(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
// [EnableCors] // Warning ASP0023 Route '{id}' conflicts with another action route.
// An HTTP request that matches multiple routes results in an ambiguous
// match error.
[EnableCors("MyPolicy")] // Required for this path.
[HttpGet]
public IActionResult GetTodoItems() =>
ControllerContext.MyDisplayRouteInfo();
[HttpGet("{action}")]
public IActionResult GetTodoItems2() =>
ControllerContext.MyDisplayRouteInfo();
[EnableCors("MyPolicy")] // Required for this path.
[HttpDelete("{action}/{id}")]
public IActionResult MyDelete2(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
}
Předchozí kód je možné otestovat nasazením ukázky do Azure. V rozevíracím seznamu Kontroler vyberte Preflight a potom Nastavit kontroler. Všechna volání CORS do TodoItems2Controller koncových bodů jsou úspěšná.
Dodatečné zdroje
Autoři: Rick Anderson a Kirk Larkin
Tento článek ukazuje, jak povolit CORS v aplikaci ASP.NET Core.
Zabezpečení prohlížeče zabraňuje tomu, aby webová stránka odesílala požadavky do jiné domény, než je ta, která webovou stránku obsluhuje. Toto omezení se označuje jako zásada stejného zdroje. Zásada stejného zdroje brání škodlivým webům ve čtení citlivých dat z jiných webů. Někdy můžete chtít povolit jiným webům odesílat do vaší aplikace požadavky z jiného původu. Další informace naleznete v článku Mozilla CORS.
Sdílení prostředků mezi zdroji původu (CORS):
- Je to standard W3C, který umožňuje serveru zmírnit politiku stejného původu.
- Nejedná se o bezpečnostní funkci, CORS oslabuje zabezpečení. Rozhraní API není bezpečnější jen proto, že povoluje CORS. Další informace najdete v tématu Jak CORS funguje.
- Umožňuje serveru explicitně povolit některé požadavky mezi zdroji a zároveň odmítnout jiné.
- Je bezpečnější a flexibilnější než dřívější techniky, například JSONP.
Zobrazení nebo stažení ukázkového kódu (postup stažení)
Stejný původ
Dvě adresy URL mají stejný původ, pokud mají stejná schémata, hostitele a porty (RFC 6454).
Tyto dvě adresy URL mají stejný původ:
https://example.com/foo.htmlhttps://example.com/bar.html
Tyto adresy URL mají jiný původ než předchozí dvě adresy URL:
-
https://example.net: Jiná doména -
https://www.example.com/foo.html: Jiná subdoména -
http://example.com/foo.html: Jiné schéma -
https://example.com:9000/foo.html: Jiný port
Povolit CORS
CORS můžete povolit třemi způsoby:
- V middlewaru pomocí pojmenované zásady nebo výchozí zásady.
- Použití směrování koncových bodů.
- S atributem [EnableCors]
Použití atributu [EnableCors] s pojmenovanou zásadou poskytuje nejlepší kontrolu v omezení koncových bodů, které podporují CORS.
Warning
UseCors musí být volána ve správném pořadí. Další informace najdete v tématu Pořadí middlewaru. Například UseCors musí být volána před UseResponseCaching při použití UseResponseCaching.
Každý přístup je podrobně popsaný v následujících částech.
CORS s pojmenovanými zásadami a middlewarem
Middleware CORS zpracovává požadavky z různých zdrojů. Následující kód použije zásadu CORS pro všechny koncové body aplikace se zadanými zdroji:
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com");
});
});
// services.AddResponseCaching();
builder.Services.AddControllers();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors(MyAllowSpecificOrigins);
app.UseAuthorization();
app.MapControllers();
app.Run();
Předchozí kód:
- Nastaví název zásady na
_myAllowSpecificOrigins. Název zásady je libovolný. - Volá UseCors metodu rozšíření a zadává zásadu CORS
_myAllowSpecificOrigins.UseCorspřidá middleware CORS. HovorUseCorsmusí být umístěn zaUseRouting, ale předUseAuthorization. Další informace najdete v tématu Pořadí middlewaru. - Volá 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
_myAllowSpecificOriginsCORS pro všechny koncové body kontroleru. Informace o směrování koncových bodů najdete v části, jak použít zásadu CORS pro konkrétní koncové body. - Při použití middlewaru ukládání odpovědí do mezipaměti zavolejte UseCors před UseResponseCaching.
Při směrování koncových bodů musí být middleware CORS nakonfigurován tak, aby se spouštěl mezi volánímiUseRouting a UseEndpoints.
Volání metody AddCors přidá služby CORS do kontejneru služeb aplikace:
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com");
});
});
// services.AddResponseCaching();
builder.Services.AddControllers();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors(MyAllowSpecificOrigins);
app.UseAuthorization();
app.MapControllers();
app.Run();
Další informace najdete v tématu Možnosti zásad CORS v tomto dokumentu.
Metody CorsPolicyBuilder mohou být zřetězeny, jak je znázorněno v následujícím kódu:
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
builder.Services.AddControllers();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors(MyAllowSpecificOrigins);
app.UseAuthorization();
app.MapControllers();
app.Run();
Poznámka: Zadaná adresa URL nesmí obsahovat koncové lomítko (/). Pokud adresa URL končí na /, porovnání vrátí false a nevrátí se žádné záhlaví.
Warning
UseCors musí být umístěn za UseRouting a před UseAuthorization. To zajistí, aby hlavičky CORS byly zahrnuty do odpovědi pro autorizovaná i neautorizovaná volání.
Pořadí UseCors a UseStaticFiles
Obvykle se UseStaticFiles volá před UseCors. Aplikace, které používají JavaScript k načítání statických souborů z jiného webu, musí volat UseCors před UseStaticFiles.
CORS s výchozími zásadami a middlewarem
Následující zvýrazněný kód povolí výchozí zásady CORS:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com");
});
});
builder.Services.AddControllers();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.MapControllers();
app.Run();
Předchozí kód použije výchozí zásady CORS pro všechny koncové body kontroleru.
Povolte CORS pomocí směrování koncových bodů
Pomocí směrování koncového bodu je možné CORS povolit pro jednotlivé koncové body pomocí RequireCors sady rozšiřujících metod:
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com");
});
});
builder.Services.AddControllers();
builder.Services.AddRazorPages();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/echo",
context => context.Response.WriteAsync("echo"))
.RequireCors(MyAllowSpecificOrigins);
endpoints.MapControllers()
.RequireCors(MyAllowSpecificOrigins);
endpoints.MapGet("/echo2",
context => context.Response.WriteAsync("echo2"));
endpoints.MapRazorPages();
});
app.Run();
V předchozím kódu:
-
app.UseCorspovolí middleware CORS. Protože není nakonfigurovaná výchozí politika, samotnéapp.UseCors()CORS nepovolí. - Koncové body
/echoa kontroleru umožňují požadavky z různých zdrojů podle zadaných zásad. - Koncové body stránek
/echo2a Razorneumožňují požadavky z různých zdrojů, protože nebyla zadána žádná výchozí zásada.
Atribut [DisableCors] nezakazujeCORS, které bylo povoleno směrováním koncového bodu s RequireCors.
V .NET 7 musí být atributu [EnableCors] předán parametr, jinak se kvůli nejednoznačné shodě trasy vygeneruje upozornění ASP0023. .NET 8 nebo novější negeneruje ASP0023 upozornění.
[Route("api/[controller]")]
[ApiController]
public class TodoItems2Controller : ControllerBase
{
// OPTIONS: api/TodoItems2/5
[HttpOptions("{id}")]
public IActionResult PreflightRoute(int id)
{
return NoContent();
}
// OPTIONS: api/TodoItems2
[HttpOptions]
public IActionResult PreflightRoute()
{
return NoContent();
}
[HttpPut("{id}")]
public IActionResult PutTodoItem(int id)
{
if (id < 1)
{
return BadRequest();
}
return ControllerContext.MyDisplayRouteInfo(id);
}
// [EnableCors] // Not needed as OPTIONS path provided.
[HttpDelete("{id}")]
public IActionResult MyDelete(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
// [EnableCors] // Warning ASP0023 Route '{id}' conflicts with another action route.
// An HTTP request that matches multiple routes results in an ambiguous
// match error.
[EnableCors("MyPolicy")] // Required for this path.
[HttpGet]
public IActionResult GetTodoItems() =>
ControllerContext.MyDisplayRouteInfo();
[HttpGet("{action}")]
public IActionResult GetTodoItems2() =>
ControllerContext.MyDisplayRouteInfo();
[EnableCors("MyPolicy")] // Required for this path.
[HttpDelete("{action}/{id}")]
public IActionResult MyDelete2(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
}
Pokyny k testování kódu podobného předchozímu kódu najdete v části Test CORS s atributem [EnableCors] a metodou RequireCors.
Povolit CORS pomocí atributů
Povolení CORS pomocí atributu [EnableCors] a použití pojmenované zásady pouze na koncové body, které vyžadují CORS, poskytuje nejlepší kontrolu.
Atribut [EnableCors] poskytuje alternativu k použití CORS globálně. Tento [EnableCors] atribut umožňuje CORS pro vybrané koncové body, nikoli pro všechny koncové body:
-
[EnableCors]určuje výchozí zásadu. -
[EnableCors("{Policy String}")]určuje pojmenovanou zásadu.
Atribut [EnableCors] lze použít na:
-
Razor Stránka
PageModel - Controller
- Metoda akce kontroleru
U kontrolerů, modelů stránek nebo metod akcí s atributem [EnableCors] je možné použít různé zásady.
[EnableCors] Když se atribut použije u kontroleru, modelu stránky nebo metody akce a CORS je v middlewaru povolený, použijí se obě zásady. Nedoporučujeme kombinovat zásady. Použijte
[EnableCors]
atribut nebo middleware, ne oba ve stejné aplikaci.
Následující kód použije pro každou metodu jinou zásadu:
[Route("api/[controller]")]
[ApiController]
public class WidgetController : ControllerBase
{
// GET api/values
[EnableCors("AnotherPolicy")]
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
return new string[] { "green widget", "red widget" };
}
// GET api/values/5
[EnableCors("Policy1")]
[HttpGet("{id}")]
public ActionResult<string> Get(int id)
{
return id switch
{
1 => "green widget",
2 => "red widget",
_ => NotFound(),
};
}
}
Následující kód vytvoří dvě zásady CORS:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy("Policy1",
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com");
});
options.AddPolicy("AnotherPolicy",
policy =>
{
policy.WithOrigins("http://www.contoso.com")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
builder.Services.AddControllers();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.MapControllers();
app.Run();
Pro co nejpřesnější kontrolu omezení požadavků CORS:
- Použijte
[EnableCors("MyPolicy")]s pojmenovanou zásadou. - Nedefinujte výchozí zásadu.
- Nepoužívejte směrování koncových bodů.
Kód v další části odpovídá předchozímu seznamu.
Zakázání CORS
Atribut [DisableCors] nezakazujeCORS, které bylo povoleno směrováním koncového bodu.
Následující kód definuje zásadu "MyPolicy"CORS:
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: "MyPolicy",
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com")
.WithMethods("PUT", "DELETE", "GET");
});
});
builder.Services.AddControllers();
builder.Services.AddRazorPages();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.UseEndpoints(endpoints => {
endpoints.MapControllers();
endpoints.MapRazorPages();
});
app.Run();
Následující kód zakáže CORS pro GetValues2 akci:
[EnableCors("MyPolicy")]
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
// GET api/values
[HttpGet]
public IActionResult Get() =>
ControllerContext.MyDisplayRouteInfo();
// GET api/values/5
[HttpGet("{id}")]
public IActionResult Get(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
// PUT api/values/5
[HttpPut("{id}")]
public IActionResult Put(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
// GET: api/values/GetValues2
[DisableCors]
[HttpGet("{action}")]
public IActionResult GetValues2() =>
ControllerContext.MyDisplayRouteInfo();
}
Předchozí kód:
- Nepovoluje CORS pomocí směrování koncových bodů.
- Nedefinuje výchozí zásady CORS.
- Pomocí funkce [EnableCors("MyPolicy")] povolí
"MyPolicy"zásady CORS pro kontroler. - Zakáže CORS pro metodu
GetValues2.
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:
- Nastavení povolených zdrojů
- Nastavení povolených metod HTTP
- Nastavení hlaviček povolených požadavků
- Nastavení vystavených hlaviček odpovědí
- Přihlašovací údaje v požadavcích mezi různými zdroji
- Nastavení doby předběžného vypršení platnosti
AddPolicy je voláno v Program.cs. U některých možností může být užitečné nejprve přečíst část Jak CORS funguje .
Nastavení povolených zdrojů
AllowAnyOrigin: Umožňuje požadavky CORS ze všech zdrojů s jakýmkoli schématem (http nebo https).
AllowAnyOrigin není zabezpečená, protože jakýkoli web může na aplikaci odesílat cross-origin požadavky.
Note
Zadání AllowAnyOrigin a AllowCredentials představuje nezabezpečenou konfiguraci a může vést k padělání požadavků mezi weby. Služba CORS vrátí neplatnou odpověď CORS, když je aplikace nakonfigurovaná s oběma metodami.
AllowAnyOrigin ovlivňuje předběžné požadavky a hlavičku Access-Control-Allow-Origin . Další informace najdete v části Předběžné požadavky .
SetIsOriginAllowedToAllowWildcardSubdomains: Nastaví IsOriginAllowed vlastnost zásady na funkci, která umožňuje, aby zdroje odpovídaly nakonfigurované zástupné doméně při vyhodnocování, zda je původ povolený.
var MyAllowSpecificOrigins = "_MyAllowSubdomainPolicy";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("https://*.example.com")
.SetIsOriginAllowedToAllowWildcardSubdomains();
});
});
builder.Services.AddControllers();
var app = builder.Build();
V předchozím kódu je SetIsOriginAllowedToAllowWildcardSubdomains volána se zástupným znakem domény "https://*.example.com". Toto nastavení umožňuje CORS žádosti z jakékoli subdomény example.com, jako https://subdomain.example.com nebo https://api.example.com. Zástupný znak * musí být zahrnut v původu, aby umožnil porovnávání subdomén pomocí zástupných znaků.
Nastavení povolených metod HTTP
- Povoluje libovolnou metodu HTTP:
- Ovlivňuje předběžné požadavky a hlavičku
Access-Control-Allow-Methods. Další informace najdete v části Předběžné požadavky .
Nastavení hlaviček povolených požadavků
Chcete-li povolit odesílání konkrétních hlaviček v požadavku CORS, označovaných jako hlavičky požadavku autora, zavolejte WithHeaders a zadejte povolené hlavičky:
using Microsoft.Net.Http.Headers;
var MyAllowSpecificOrigins = "_MyAllowSubdomainPolicy";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("http://example.com")
.WithHeaders(HeaderNames.ContentType, "x-custom-header");
});
});
builder.Services.AddControllers();
var app = builder.Build();
Pokud chcete povolit všechna záhlaví žádosti autora, zavolejte AllowAnyHeader:
var MyAllowSpecificOrigins = "_MyAllowSubdomainPolicy";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("https://*.example.com")
.AllowAnyHeader();
});
});
builder.Services.AddControllers();
var app = builder.Build();
AllowAnyHeader ovlivňuje preflight požadavky a hlavičku Access-Control-Request-Headers. Další informace najdete v části Předběžné požadavky .
Shoda zásady middlewaru CORS s konkrétními hlavičkami zadanými pomocí WithHeaders je možná pouze tehdy, když hlavičky odeslané v Access-Control-Request-Headers přesně odpovídají hlavičkám uvedeným v WithHeaders.
Představte si například aplikaci nakonfigurovanou takto:
app.UseCors(policy => policy.WithHeaders(HeaderNames.CacheControl));
Middleware CORS odmítne předběžný požadavek s následující hlavičkou požadavku, protože Content-Language (HeaderNames.ContentLanguage) není uvedený v WithHeaders:
Access-Control-Request-Headers: Cache-Control, Content-Language
Aplikace vrátí odpověď 200 OK , ale neodesílá hlavičky CORS zpět. Prohlížeč se proto nepokouší o požadavek na jiný původ.
Nastavení vystavených hlaviček odpovědí
Ve výchozím nastavení prohlížeč nezpřístupňuje do aplikace všechny hlavičky odpovědi. Další informace najdete v tématu Sdílení prostředků mezi různými zdroji W3C (terminologie): jednoduchá hlavička odpovědi.
Hlavičky odpovědi, které jsou ve výchozím nastavení k dispozici, jsou:
Cache-ControlContent-LanguageContent-TypeExpiresLast-ModifiedPragma
Specifikace CORS tyto hlavičky označuje jako jednoduché hlavičky odpovědi. Pokud chcete aplikaci zpřístupnit další hlavičky, zavolejte WithExposedHeaders:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy("MyExposeResponseHeadersPolicy",
policy =>
{
policy.WithOrigins("https://*.example.com")
.WithExposedHeaders("x-custom-header");
});
});
builder.Services.AddControllers();
var app = builder.Build();
Přihlašovací údaje v požadavcích mezi zdroji
Přihlašovací údaje vyžadují speciální zpracování v požadavku CORS. Ve výchozím nastavení prohlížeč neodesílá přihlašovací údaje s požadavkem z jiného původu. Přihlašovací údaje zahrnují soubory cookie a schémata ověřování HTTP. Chcete-li odeslat přihlašovací údaje s požadavkem mezi zdroji, musí klient nastavit XMLHttpRequest.withCredentials na hodnotu true.
Přímé použití XMLHttpRequest :
var xhr = new XMLHttpRequest();
xhr.open('get', 'https://www.example.com/api/test');
xhr.withCredentials = true;
Pomocí jQuery:
$.ajax({
type: 'get',
url: 'https://www.example.com/api/test',
xhrFields: {
withCredentials: true
}
});
Použití rozhraní Fetch API:
fetch('https://www.example.com/api/test', {
credentials: 'include'
});
Server musí přihlašovací údaje povolit. Chcete-li povolit pověření pro různé zdroje, zavolejte AllowCredentials:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy("MyMyAllowCredentialsPolicy",
policy =>
{
policy.WithOrigins("http://example.com")
.AllowCredentials();
});
});
builder.Services.AddControllers();
var app = builder.Build();
Odpověď HTTP obsahuje hlavičku Access-Control-Allow-Credentials , která prohlížeči říká, že server povoluje přihlašovací údaje pro požadavek mezi zdroji.
Pokud prohlížeč odešle přihlašovací údaje, ale odpověď neobsahuje platnou Access-Control-Allow-Credentials hlavičku, prohlížeč nezobrazí odpověď aplikaci a požadavek mezi zdroji selže.
Povolení přihlašovacích údajů mezi různými zdroji představuje bezpečnostní riziko. Web v jiné doméně může odeslat přihlašovací údaje přihlášeného uživatele do aplikace jménem uživatele bez vědomí uživatele.
Specifikace CORS také uvádí, že nastavení původu na "*" (všechny zdroje) je neplatné, pokud je hlavička Access-Control-Allow-Credentials přítomna.
Preflightové požadavky
U některých požadavků CORS prohlížeč před provedením skutečného požadavku odešle další požadavek OPTIONS . Tento požadavek se nazývá předběžný požadavek. Prohlížeč může předběžný požadavek přeskočit, pokud jsou splněny všechny následující podmínky:
- Metoda požadavku je GET, HEAD nebo POST.
- Aplikace nenastavuje jiné hlavičky požadavků než
Accept,Accept-Language,Content-Language, ,Content-TypeneboLast-Event-ID. - Hlavička
Content-Type, pokud je nastavená, má jednu z následujících hodnot:application/x-www-form-urlencodedmultipart/form-datatext/plain
Pravidlo hlavičky požadavku nastavené pro požadavek klienta se vztahuje na hlavičky, které aplikace nastaví voláním setRequestHeader objektu XMLHttpRequest . Specifikace CORS označuje tyto hlavičky jako hlavičky požadavku autora. Pravidlo se nevztahuje na hlavičky, které může prohlížeč nastavit, například User-Agent, Hostnebo Content-Length.
Následuje příklad odpovědi podobné předběžnému požadavku vytvořenému z tlačítka [Put test] v části Test CORS tohoto dokumentu.
General:
Request URL: https://cors3.azurewebsites.net/api/values/5
Request Method: OPTIONS
Status Code: 204 No Content
Response Headers:
Access-Control-Allow-Methods: PUT,DELETE,GET
Access-Control-Allow-Origin: https://cors1.azurewebsites.net
Server: Microsoft-IIS/10.0
Set-Cookie: ARRAffinity=8f8...8;Path=/;HttpOnly;Domain=cors1.azurewebsites.net
Vary: Origin
Request Headers:
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Access-Control-Request-Method: PUT
Connection: keep-alive
Host: cors3.azurewebsites.net
Origin: https://cors1.azurewebsites.net
Referer: https://cors1.azurewebsites.net/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0
Předběžný požadavek používá metodu HTTP OPTIONS . Může obsahovat následující hlavičky:
- Access-Control-Request-Method: Metoda HTTP, která se použije pro skutečný požadavek.
-
Access-Control-Request-Headers: Seznam hlaviček žádosti, které aplikace nastaví ve skutečném požadavku. Jak jsme uvedli dříve, nezahrnuje hlavičky, které prohlížeče nastaví, například
User-Agent. - Access-Control-Allow-Methods
Pokud je preflight požadavek zamítnut, aplikace vrátí odpověď 200 OK, ale nenastaví hlavičky CORS. Prohlížeč se proto nepokouší o požadavek na jiný původ. Příklad zamítnutého preflightového požadavku najdete v části Test CORS tohoto dokumentu.
Pomocí nástrojů F12 konzolová aplikace zobrazí v závislosti na prohlížeči chybu podobnou jedné z následujících možností:
- Firefox: Požadavek mezi různými zdroji byl zablokován: Zásada stejného původu nepovoluje přístup ke vzdálenému prostředku na adrese
https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5. (Důvod: Požadavek CORS nebyl úspěšný). Zjistit více - Založeno na Chromiu: Přístup k načtení na adrese 'https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5' z původu 'https://cors3.azurewebsites.net' byl zablokován zásadami CORS: Odpověď na předběžný požadavek neprošla kontrolou řízení přístupu: v požadovaném prostředku není přítomna žádná hlavička 'Access-Control-Allow-Origin'. Pokud vám vyhovuje neprůhledná odpověď, nastavte režim požadavku na 'no-cors' pro načtení prostředku s vypnutým CORS.
Pokud chcete povolit konkrétní záhlaví, zavolejte WithHeaders:
using Microsoft.Net.Http.Headers;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy("MyAllowHeadersPolicy",
policy =>
{
policy.WithOrigins("http://example.com")
.WithHeaders(HeaderNames.ContentType, "x-custom-header");
});
});
builder.Services.AddControllers();
var app = builder.Build();
Pokud chcete povolit všechna záhlaví žádosti autora, zavolejte AllowAnyHeader:
using Microsoft.Net.Http.Headers;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy("MyAllowAllHeadersPolicy",
policy =>
{
policy.WithOrigins("https://*.example.com")
.AllowAnyHeader();
});
});
builder.Services.AddControllers();
var app = builder.Build();
Prohlížeče nejsou konzistentní ve způsobu jejich nastavení Access-Control-Request-Headers. Pokud máte některou z těchto:
- Záhlaví jsou nastavená na cokoli jiného než
"*" -
AllowAnyHeader se nazývá: Zahrňte alespoň
Accept,Content-TypeaOrigina všechny vlastní hlavičky, které chcete podporovat.
Automatický předletový kód požadavku
Pokud se použije zásada CORS:
- Globálně voláním
app.UseCorsvProgram.cs. - Použití atributu
[EnableCors]
ASP.NET Core odpovídá na předběžný dotaz OPTIONS.
Toto chování ukazuje část Test CORS tohoto dokumentu.
Atribut [HttpOptions] pro předběžné požadavky
Když je CORS povolená s příslušnými zásadami, ASP.NET Core obvykle automaticky reaguje na předběžné požadavky CORS.
Následující kód používá atribut [HttpOptions] k vytvoření koncových bodů pro požadavky OPTIONS:
[Route("api/[controller]")]
[ApiController]
public class TodoItems2Controller : ControllerBase
{
// OPTIONS: api/TodoItems2/5
[HttpOptions("{id}")]
public IActionResult PreflightRoute(int id)
{
return NoContent();
}
// OPTIONS: api/TodoItems2
[HttpOptions]
public IActionResult PreflightRoute()
{
return NoContent();
}
[HttpPut("{id}")]
public IActionResult PutTodoItem(int id)
{
if (id < 1)
{
return BadRequest();
}
return ControllerContext.MyDisplayRouteInfo(id);
}
Pokyny k testování předchozího kódu najdete v části Test CORS s atributem [EnableCors] a metodou RequireCors.
Nastavení doby předběžného vypršení platnosti
Hlavička Access-Control-Max-Age určuje, jak dlouho může být odpověď na předběžný požadavek uložena do mezipaměti. Chcete-li nastavit toto záhlaví, zavolejte SetPreflightMaxAge:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy("MySetPreflightExpirationPolicy",
policy =>
{
policy.WithOrigins("http://example.com")
.SetPreflightMaxAge(TimeSpan.FromSeconds(2520));
});
});
builder.Services.AddControllers();
var app = builder.Build();
Povolte CORS na koncovém bodu
Jak CORS funguje
Tato část popisuje, co se stane v požadavku CORS na úrovni zpráv HTTP.
- CORS není bezpečnostní funkce. CORS je standard W3C, který umožňuje serveru uvolnit zásady stejného původu.
- Například by škodlivý útočník mohl proti vašemu webu použít Cross-Site Scripting (XSS) a odeslat požadavek mezi weby na svůj web s povoleným CORS, aby odcizil informace.
- API není bezpečnější tím, že umožňuje CORS.
- Je na klientovi (prohlížeči), aby vynucoval CORS. Server spustí požadavek a vrátí odpověď. Je to klient, který vrací chybu a blokuje odpověď. Například některý z následujících nástrojů zobrazí odpověď serveru:
- Fiddler
- .NET HttpClient
- Ve webovém prohlížeči zadáním adresy URL do adresního řádku.
- Je na klientovi (prohlížeči), aby vynucoval CORS. Server spustí požadavek a vrátí odpověď. Je to klient, který vrací chybu a blokuje odpověď. Například některý z následujících nástrojů zobrazí odpověď serveru:
- Je to způsob, jak server umožňuje prohlížečům provést požadavek XHR nebo Fetch API z jiné domény, který by jinak byl zakázán.
- Prohlížeče bez CORS nemůžou provádět žádosti mezi zdroji. Před CORS se k obejití tohoto omezení použil JSONP . JSONP nepoužívá XHR, k přijetí odpovědi používá
<script>značku. Skripty je povoleno načítat z jiného původu.
- Prohlížeče bez CORS nemůžou provádět žádosti mezi zdroji. Před CORS se k obejití tohoto omezení použil JSONP . JSONP nepoužívá XHR, k přijetí odpovědi používá
Specifikace CORS zavedla několik nových hlaviček HTTP, které umožňují požadavky mezi zdroji. Pokud prohlížeč podporuje CORS, nastaví tato záhlaví automaticky u požadavků z jiného původu. K povolení CORS se nevyžaduje vlastní javascriptový kód.
V nasazené ukázce vyberte testovací tlačítko PUT.
Hlavička Origin :
- Poskytuje doménu webu, který odesílá požadavek.
- Vyžaduje se a musí se lišit od hostitele.
Obecné hlavičky
Request URL: https://cors1.azurewebsites.net/api/values
Request Method: GET
Status Code: 200 OK
Hlavičky odpovědi
Content-Encoding: gzip
Content-Type: text/plain; charset=utf-8
Server: Microsoft-IIS/10.0
Set-Cookie: ARRAffinity=8f...;Path=/;HttpOnly;Domain=cors1.azurewebsites.net
Transfer-Encoding: chunked
Vary: Accept-Encoding
X-Powered-By: ASP.NET
Hlavičky požadavků
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Connection: keep-alive
Host: cors1.azurewebsites.net
Origin: https://cors3.azurewebsites.net
Referer: https://cors3.azurewebsites.net/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0 ...
V požadavcích OPTIONS server v odpovědi nastaví hlavičku Response headersAccess-Control-Allow-Origin: {allowed origin}. Například v ukázkovém kódu Delete [EnableCors] obsahuje požadavek na tlačítko OPTIONS následující hlavičky:
Obecné hlavičky
Request URL: https://cors3.azurewebsites.net/api/TodoItems2/MyDelete2/5
Request Method: OPTIONS
Status Code: 204 No Content
Hlavičky odpovědi
Access-Control-Allow-Headers: Content-Type,x-custom-header
Access-Control-Allow-Methods: PUT,DELETE,GET,OPTIONS
Access-Control-Allow-Origin: https://cors1.azurewebsites.net
Server: Microsoft-IIS/10.0
Set-Cookie: ARRAffinity=8f...;Path=/;HttpOnly;Domain=cors3.azurewebsites.net
Vary: Origin
X-Powered-By: ASP.NET
Hlavičky požadavků
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Access-Control-Request-Headers: content-type
Access-Control-Request-Method: DELETE
Connection: keep-alive
Host: cors3.azurewebsites.net
Origin: https://cors1.azurewebsites.net
Referer: https://cors1.azurewebsites.net/test?number=2
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0
V předchozích hlavičkách odpovědi server v odpovědi nastaví hlavičku Access-Control-Allow-Origin. Hodnota https://cors1.azurewebsites.net této hlavičky odpovídá Origin hlavičce požadavku.
Pokud je zavoláno AllowAnyOrigin, vrátí se Access-Control-Allow-Origin: *, zástupná hodnota.
AllowAnyOrigin umožňuje jakýkoli původ.
Pokud odpověď neobsahuje hlavičku Access-Control-Allow-Origin, požadavek mezi různými zdroji selže. Konkrétně prohlížeč požadavek zakáže. I když server vrátí úspěšnou odpověď, prohlížeč nepřístupní odpověď klientské aplikaci.
Přesměrování z HTTP na HTTPS způsobuje chybu ERR_INVALID_REDIRECT u předběžného požadavku CORS.
Požadavky na koncový bod používající HTTP, které UseHttpsRedirection přesměruje na HTTPS, selžou s chybou ERR_INVALID_REDIRECT on the CORS preflight request.
Projekty API mohou odmítat požadavky HTTP namísto použití UseHttpsRedirection k přesměrování požadavků na HTTPS.
CORS ve službě IIS
Při nasazování do služby IIS musí CORS běžet před ověřováním systému Windows, pokud server není nakonfigurovaný tak, aby povoloval anonymní přístup. Pro podporu tohoto scénáře je potřeba nainstalovat a nakonfigurovat modul CORS služby IIS pro aplikaci.
Testování CORS
Ukázkový soubor ke stažení obsahuje kód pro testování CORS. Podívejte se, jak stahovat. Ukázka je projekt rozhraní API s přidanými stránkami Razor :
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: "MyPolicy",
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com",
"https://cors1.azurewebsites.net",
"https://cors3.azurewebsites.net",
"https://localhost:44398",
"https://localhost:5001")
.WithMethods("PUT", "DELETE", "GET");
});
});
builder.Services.AddControllers();
builder.Services.AddRazorPages();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.MapControllers();
app.MapRazorPages();
app.Run();
Warning
WithOrigins("https://localhost:<port>"); lze použít pouze k testování ukázkové aplikace podobné jako ukázkový kód ke stažení.
ValuesController Následující text uvádí koncové body pro testování:
[EnableCors("MyPolicy")]
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
// GET api/values
[HttpGet]
public IActionResult Get() =>
ControllerContext.MyDisplayRouteInfo();
// GET api/values/5
[HttpGet("{id}")]
public IActionResult Get(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
// PUT api/values/5
[HttpPut("{id}")]
public IActionResult Put(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
// GET: api/values/GetValues2
[DisableCors]
[HttpGet("{action}")]
public IActionResult GetValues2() =>
ControllerContext.MyDisplayRouteInfo();
}
MyDisplayRouteInfo poskytuje balíček NuGet Rick.Docs.Samples.RouteInfo a zobrazí informace o trase.
Otestujte předchozí vzorový kód pomocí jednoho z následujících přístupů:
- Spusťte ukázku pomocí
dotnet runs výchozí adresou URLhttps://localhost:5001. - Spusťte ukázku ze sady Visual Studio s portem nastaveným na 44398 pro adresu URL souboru
https://localhost:44398.
Použití prohlížeče s nástroji F12:
Vyberte tlačítko Hodnoty a zkontrolujte záhlaví na kartě Síť.
Vyberte tlačítko PUT test. Pokyny k zobrazení požadavku OPTIONS najdete v části Zobrazení MOŽNOSTÍ . Test PUT vytvoří dva požadavky, předběžný požadavek OPTIONS a požadavek PUT.
GetValues2 [DisableCors]Výběrem tlačítka aktivujte neúspěšný požadavek CORS. Jak je uvedeno v dokumentaci, odpověď vrátí stavový kód 200 (OK), ale požadavek CORS se neodešle. Vyberte kartu Konzola a zobrazte chybu CORS. V závislosti na prohlížeči se zobrazí chyba podobná této:Zásady CORS blokovaly přístup k načtení
'https://cors1.azurewebsites.net/api/values/GetValues2'z zdroje'https://cors3.azurewebsites.net': U požadovaného prostředku není k dispozici žádná hlavička Access-Control-Allow-Origin. Pokud vám vyhovuje neprůhledná odpověď, nastavte režim požadavku na 'no-cors' pro načtení prostředku s vypnutým CORS.
Koncové body s povoleným CORS lze testovat pomocí nástrojů, jako jsou curl nebo Fiddler. Při použití nástroje se původ požadavku určeného Origin hlavičkou musí lišit od hostitele, který požadavek přijímá. Pokud požadavek není na základě hodnoty hlavičky považován za Origin:
- Není nutné, aby middleware CORS zpracovával požadavek.
- Hlavičky CORS nejsou v odpovědi vráceny.
Následující příkaz používá curl k vydání požadavku OPTIONS s informacemi:
curl -X OPTIONS https://cors3.azurewebsites.net/api/TodoItems2/5 -i
Testování CORS s atributem [EnableCors] a metodou RequireCors
Zvažte následující kód, který používá směrování koncových bodů k povolení CORS na základě jednotlivých koncových bodů pomocí RequireCors:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: "MyPolicy",
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com",
"https://cors1.azurewebsites.net",
"https://cors3.azurewebsites.net",
"https://localhost:44398",
"https://localhost:5001")
.WithMethods("PUT", "DELETE", "GET");
});
});
builder.Services.AddControllers();
builder.Services.AddRazorPages();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/echo",
context => context.Response.WriteAsync("echo"))
.RequireCors("MyPolicy");
endpoints.MapControllers();
endpoints.MapRazorPages();
});
app.Run();
Všimněte si, že pouze koncový bod /echo používá RequireCors k povolení požadavků z různých zdrojů pomocí zadané zásady. Následující kontrolery povolují CORS pomocí atributu [EnableCors].
Následující TodoItems1Controller poskytuje koncové body pro testování:
[Route("api/[controller]")]
[ApiController]
public class TodoItems1Controller : ControllerBase
{
// PUT: api/TodoItems1/5
[HttpPut("{id}")]
public IActionResult PutTodoItem(int id) {
if (id < 1) {
return Content($"ID = {id}");
}
return ControllerContext.MyDisplayRouteInfo(id);
}
// Delete: api/TodoItems1/5
[HttpDelete("{id}")]
public IActionResult MyDelete(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
// GET: api/TodoItems1
[HttpGet]
public IActionResult GetTodoItems() =>
ControllerContext.MyDisplayRouteInfo();
[EnableCors("MyPolicy")]
[HttpGet("{action}")]
public IActionResult GetTodoItems2() =>
ControllerContext.MyDisplayRouteInfo();
// Delete: api/TodoItems1/MyDelete2/5
[EnableCors("MyPolicy")]
[HttpDelete("{action}/{id}")]
public IActionResult MyDelete2(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
}
Tlačítka Delete [EnableCors] a GET [EnableCors] jsou úspěšná, protože koncové body mají [EnableCors] a reagují na předběžné požadavky. Ostatní koncové body selžou. Tlačítko GET selže, protože JavaScript odesílá:
headers: {
"Content-Type": "x-custom-header"
},
Následující TodoItems2Controller poskytuje podobné endpointy, ale obsahuje explicitní kód pro zpracování požadavků OPTIONS:
[Route("api/[controller]")]
[ApiController]
public class TodoItems2Controller : ControllerBase
{
// OPTIONS: api/TodoItems2/5
[HttpOptions("{id}")]
public IActionResult PreflightRoute(int id)
{
return NoContent();
}
// OPTIONS: api/TodoItems2
[HttpOptions]
public IActionResult PreflightRoute()
{
return NoContent();
}
[HttpPut("{id}")]
public IActionResult PutTodoItem(int id)
{
if (id < 1)
{
return BadRequest();
}
return ControllerContext.MyDisplayRouteInfo(id);
}
// [EnableCors] // Not needed as OPTIONS path provided.
[HttpDelete("{id}")]
public IActionResult MyDelete(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
// [EnableCors] // Warning ASP0023 Route '{id}' conflicts with another action route.
// An HTTP request that matches multiple routes results in an ambiguous
// match error.
[EnableCors("MyPolicy")] // Required for this path.
[HttpGet]
public IActionResult GetTodoItems() =>
ControllerContext.MyDisplayRouteInfo();
[HttpGet("{action}")]
public IActionResult GetTodoItems2() =>
ControllerContext.MyDisplayRouteInfo();
[EnableCors("MyPolicy")] // Required for this path.
[HttpDelete("{action}/{id}")]
public IActionResult MyDelete2(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
}
Předchozí kód lze otestovat nasazením ukázky do Azure. V rozevíracím seznamu Controller vyberte Preflight a potom Set Controller. Všechna volání CORS do TodoItems2Controller koncových bodů jsou úspěšná.
Dodatečné zdroje
Autoři: Rick Anderson a Kirk Larkin
Tento článek ukazuje, jak povolit CORS v aplikaci ASP.NET Core.
Zabezpečení prohlížeče zabraňuje tomu, aby webová stránka odesílala požadavky do jiné domény, než je ta, která webovou stránku obsluhuje. Toto omezení se označuje jako zásada stejného zdroje. Zásada stejného zdroje brání škodlivým webům ve čtení citlivých dat z jiných webů. Někdy můžete chtít povolit jiným webům odesílat do vaší aplikace požadavky z jiného původu. Další informace naleznete v článku Mozilla CORS.
Sdílení prostředků mezi zdroji původu (CORS):
- Je to standard W3C, který umožňuje serveru zmírnit politiku stejného původu.
- Nejedná se o bezpečnostní funkci, CORS oslabuje zabezpečení. Rozhraní API není bezpečnější jen proto, že povoluje CORS. Další informace najdete v tématu Jak CORS funguje.
- Umožňuje serveru explicitně povolit některé požadavky mezi zdroji a zároveň odmítnout jiné.
- Je bezpečnější a flexibilnější než dřívější techniky, například JSONP.
Zobrazení nebo stažení ukázkového kódu (postup stažení)
Stejný původ
Dvě adresy URL mají stejný původ, pokud mají stejná schémata, hostitele a porty (RFC 6454).
Tyto dvě adresy URL mají stejný původ:
https://example.com/foo.htmlhttps://example.com/bar.html
Tyto adresy URL mají jiný původ než předchozí dvě adresy URL:
-
https://example.net: Jiná doména -
https://www.example.com/foo.html: Jiná subdoména -
http://example.com/foo.html: Jiné schéma -
https://example.com:9000/foo.html: Jiný port
Povolit CORS
CORS můžete povolit třemi způsoby:
- V middlewaru pomocí pojmenované zásady nebo výchozí zásady.
- Použití směrování koncových bodů.
- S atributem [EnableCors]
Použití atributu [EnableCors] s pojmenovanou zásadou poskytuje nejlepší kontrolu v omezení koncových bodů, které podporují CORS.
Warning
UseCors musí být volána ve správném pořadí. Další informace najdete v tématu Pořadí middlewaru. Například UseCors musí být volána před UseResponseCaching při použití UseResponseCaching.
Každý přístup je podrobně popsaný v následujících částech.
CORS s pojmenovanými zásadami a middlewarem
Middleware CORS zpracovává požadavky z různých zdrojů. Následující kód použije zásadu CORS pro všechny koncové body aplikace se zadanými zdroji:
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com");
});
});
// services.AddResponseCaching();
builder.Services.AddControllers();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors(MyAllowSpecificOrigins);
app.UseAuthorization();
app.MapControllers();
app.Run();
Předchozí kód:
- Nastaví název zásady na
_myAllowSpecificOrigins. Název zásady je libovolný. - Volá UseCors metodu rozšíření a zadává zásadu CORS
_myAllowSpecificOrigins.UseCorspřidá middleware CORS. HovorUseCorsmusí být umístěn zaUseRouting, ale předUseAuthorization. Další informace najdete v tématu Pořadí middlewaru. - Volá 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
_myAllowSpecificOriginsCORS pro všechny koncové body kontroleru. Informace o směrování koncových bodů najdete v části, jak použít zásadu CORS pro konkrétní koncové body. - Při použití middlewaru ukládání odpovědí do mezipaměti zavolejte UseCors před UseResponseCaching.
Při směrování koncových bodů musí být middleware CORS nakonfigurován tak, aby se spouštěl mezi volánímiUseRouting a UseEndpoints.
Volání metody AddCors přidá služby CORS do kontejneru služeb aplikace:
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com");
});
});
// services.AddResponseCaching();
builder.Services.AddControllers();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors(MyAllowSpecificOrigins);
app.UseAuthorization();
app.MapControllers();
app.Run();
Další informace najdete v tématu Možnosti zásad CORS v tomto dokumentu.
Metody CorsPolicyBuilder mohou být zřetězeny, jak je znázorněno v následujícím kódu:
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
builder.Services.AddControllers();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors(MyAllowSpecificOrigins);
app.UseAuthorization();
app.MapControllers();
app.Run();
Poznámka: Zadaná adresa URL nesmí obsahovat koncové lomítko (/). Pokud adresa URL končí na /, porovnání vrátí false a nevrátí se žádné záhlaví.
Warning
UseCors musí být umístěn za UseRouting a před UseAuthorization. To zajistí, aby hlavičky CORS byly zahrnuty do odpovědi pro autorizovaná i neautorizovaná volání.
Pořadí UseCors a UseStaticFiles
Obvykle se UseStaticFiles volá před UseCors. Aplikace, které používají JavaScript k načítání statických souborů z jiného webu, musí volat UseCors před UseStaticFiles.
CORS s výchozími zásadami a middlewarem
Následující zvýrazněný kód povolí výchozí zásady CORS:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com");
});
});
builder.Services.AddControllers();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.MapControllers();
app.Run();
Předchozí kód použije výchozí zásady CORS pro všechny koncové body kontroleru.
Povolte CORS pomocí směrování koncových bodů
Povolení CORS pro jednotlivé koncové body pomocí RequireCorsnepodporuje automatické požadavky preflight. Další informace najdete v tomto problému na GitHubu a Test CORS se směrováním koncových bodů a [HttpOptions].
Pomocí směrování koncového bodu je možné CORS povolit pro jednotlivé koncové body pomocí RequireCors sady rozšiřujících metod:
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com");
});
});
builder.Services.AddControllers();
builder.Services.AddRazorPages();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/echo",
context => context.Response.WriteAsync("echo"))
.RequireCors(MyAllowSpecificOrigins);
endpoints.MapControllers()
.RequireCors(MyAllowSpecificOrigins);
endpoints.MapGet("/echo2",
context => context.Response.WriteAsync("echo2"));
endpoints.MapRazorPages();
});
app.Run();
V předchozím kódu:
-
app.UseCorspovolí middleware CORS. Protože není nakonfigurovaná výchozí politika, samotnéapp.UseCors()CORS nepovolí. - Koncové body
/echoa kontroleru umožňují požadavky z různých zdrojů podle zadaných zásad. - Koncové body stránek
/echo2a Razorneumožňují požadavky z různých zdrojů, protože nebyla zadána žádná výchozí zásada.
Atribut [DisableCors] nezakazujeCORS, které bylo povoleno směrováním koncového bodu s RequireCors.
Povolit CORS pomocí atributů
Povolení CORS pomocí atributu [EnableCors] a použití pojmenované zásady pouze na koncové body, které vyžadují CORS, poskytuje nejlepší kontrolu.
Atribut [EnableCors] poskytuje alternativu k použití CORS globálně. Tento [EnableCors] atribut umožňuje CORS pro vybrané koncové body, nikoli pro všechny koncové body:
-
[EnableCors]určuje výchozí zásadu. -
[EnableCors("{Policy String}")]určuje pojmenovanou zásadu.
Atribut [EnableCors] lze použít na:
-
Razor Stránka
PageModel - Controller
- Metoda akce kontroleru
U kontrolerů, modelů stránek nebo metod akcí s atributem [EnableCors] je možné použít různé zásady.
[EnableCors] Když se atribut použije u kontroleru, modelu stránky nebo metody akce a CORS je v middlewaru povolený, použijí se obě zásady. Nedoporučujeme kombinovat zásady. Použijte
[EnableCors]
atribut nebo middleware, ne oba ve stejné aplikaci.
Následující kód použije pro každou metodu jinou zásadu:
[Route("api/[controller]")]
[ApiController]
public class WidgetController : ControllerBase
{
// GET api/values
[EnableCors("AnotherPolicy")]
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
return new string[] { "green widget", "red widget" };
}
// GET api/values/5
[EnableCors("Policy1")]
[HttpGet("{id}")]
public ActionResult<string> Get(int id)
{
return id switch
{
1 => "green widget",
2 => "red widget",
_ => NotFound(),
};
}
}
Následující kód vytvoří dvě zásady CORS:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy("Policy1",
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com");
});
options.AddPolicy("AnotherPolicy",
policy =>
{
policy.WithOrigins("http://www.contoso.com")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
builder.Services.AddControllers();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.MapControllers();
app.Run();
Pro co nejpřesnější kontrolu omezení požadavků CORS:
- Použijte
[EnableCors("MyPolicy")]s pojmenovanou zásadou. - Nedefinujte výchozí zásadu.
- Nepoužívejte směrování koncových bodů.
Kód v další části odpovídá předchozímu seznamu.
Zakázání CORS
Atribut [DisableCors] nezakazujeCORS, které bylo povoleno směrováním koncového bodu.
Následující kód definuje zásadu "MyPolicy"CORS:
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: "MyPolicy",
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com")
.WithMethods("PUT", "DELETE", "GET");
});
});
builder.Services.AddControllers();
builder.Services.AddRazorPages();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.MapControllers();
app.MapRazorPages();
app.Run();
Následující kód zakáže CORS pro GetValues2 akci:
[EnableCors("MyPolicy")]
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
// GET api/values
[HttpGet]
public IActionResult Get() =>
ControllerContext.MyDisplayRouteInfo();
// GET api/values/5
[HttpGet("{id}")]
public IActionResult Get(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
// PUT api/values/5
[HttpPut("{id}")]
public IActionResult Put(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
// GET: api/values/GetValues2
[DisableCors]
[HttpGet("{action}")]
public IActionResult GetValues2() =>
ControllerContext.MyDisplayRouteInfo();
}
Předchozí kód:
- Nepovoluje CORS pomocí směrování koncových bodů.
- Nedefinuje výchozí zásady CORS.
- Pomocí funkce [EnableCors("MyPolicy")] povolí
"MyPolicy"zásady CORS pro kontroler. - Zakáže CORS pro metodu
GetValues2.
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:
- Nastavení povolených zdrojů
- Nastavení povolených metod HTTP
- Nastavení hlaviček povolených požadavků
- Nastavení vystavených hlaviček odpovědí
- Přihlašovací údaje v požadavcích mezi různými zdroji
- Nastavení doby předběžného vypršení platnosti
AddPolicy je voláno v Program.cs. U některých možností může být užitečné nejprve přečíst část Jak CORS funguje .
Nastavení povolených zdrojů
AllowAnyOrigin: Umožňuje požadavky CORS ze všech zdrojů s jakýmkoli schématem (http nebo https).
AllowAnyOrigin není zabezpečená, protože jakýkoli web může na aplikaci odesílat cross-origin požadavky.
Note
Zadání AllowAnyOrigin a AllowCredentials představuje nezabezpečenou konfiguraci a může vést k padělání požadavků mezi weby. Služba CORS vrátí neplatnou odpověď CORS, když je aplikace nakonfigurovaná s oběma metodami.
AllowAnyOrigin ovlivňuje předběžné požadavky a hlavičku Access-Control-Allow-Origin . Další informace najdete v části Předběžné požadavky .
SetIsOriginAllowedToAllowWildcardSubdomains: Nastaví IsOriginAllowed vlastnost zásady na funkci, která umožňuje, aby zdroje odpovídaly nakonfigurované zástupné doméně při vyhodnocování, zda je původ povolený.
var MyAllowSpecificOrigins = "_MyAllowSubdomainPolicy";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("https://*.example.com")
.SetIsOriginAllowedToAllowWildcardSubdomains();
});
});
builder.Services.AddControllers();
var app = builder.Build();
V předchozím kódu je SetIsOriginAllowedToAllowWildcardSubdomains volána se zástupným znakem domény "https://*.example.com". Toto nastavení umožňuje CORS žádosti z jakékoli subdomény example.com, jako https://subdomain.example.com nebo https://api.example.com. Zástupný znak * musí být zahrnut v původu, aby umožnil porovnávání subdomén pomocí zástupných znaků.
Nastavení povolených metod HTTP
- Povoluje libovolnou metodu HTTP:
- Ovlivňuje předběžné požadavky a hlavičku
Access-Control-Allow-Methods. Další informace najdete v části Předběžné požadavky .
Nastavení hlaviček povolených požadavků
Chcete-li povolit odesílání konkrétních hlaviček v požadavku CORS, označovaných jako hlavičky požadavku autora, zavolejte WithHeaders a zadejte povolené hlavičky:
using Microsoft.Net.Http.Headers;
var MyAllowSpecificOrigins = "_MyAllowSubdomainPolicy";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("http://example.com")
.WithHeaders(HeaderNames.ContentType, "x-custom-header");
});
});
builder.Services.AddControllers();
var app = builder.Build();
Pokud chcete povolit všechna záhlaví žádosti autora, zavolejte AllowAnyHeader:
var MyAllowSpecificOrigins = "_MyAllowSubdomainPolicy";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("https://*.example.com")
.AllowAnyHeader();
});
});
builder.Services.AddControllers();
var app = builder.Build();
AllowAnyHeader ovlivňuje preflight požadavky a hlavičku Access-Control-Request-Headers. Další informace najdete v části Předběžné požadavky .
Shoda zásady middlewaru CORS s konkrétními hlavičkami zadanými pomocí WithHeaders je možná pouze tehdy, když hlavičky odeslané v Access-Control-Request-Headers přesně odpovídají hlavičkám uvedeným v WithHeaders.
Představte si například aplikaci nakonfigurovanou takto:
app.UseCors(policy => policy.WithHeaders(HeaderNames.CacheControl));
Middleware CORS odmítne předběžný požadavek s následující hlavičkou požadavku, protože Content-Language (HeaderNames.ContentLanguage) není uvedený v WithHeaders:
Access-Control-Request-Headers: Cache-Control, Content-Language
Aplikace vrátí odpověď 200 OK , ale neodesílá hlavičky CORS zpět. Prohlížeč se proto nepokouší o požadavek na jiný původ.
Nastavení vystavených hlaviček odpovědí
Ve výchozím nastavení prohlížeč nezpřístupňuje do aplikace všechny hlavičky odpovědi. Další informace najdete v tématu Sdílení prostředků mezi různými zdroji W3C (terminologie): jednoduchá hlavička odpovědi.
Hlavičky odpovědi, které jsou ve výchozím nastavení k dispozici, jsou:
Cache-ControlContent-LanguageContent-TypeExpiresLast-ModifiedPragma
Specifikace CORS tyto hlavičky označuje jako jednoduché hlavičky odpovědi. Pokud chcete aplikaci zpřístupnit další hlavičky, zavolejte WithExposedHeaders:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy("MyExposeResponseHeadersPolicy",
policy =>
{
policy.WithOrigins("https://*.example.com")
.WithExposedHeaders("x-custom-header");
});
});
builder.Services.AddControllers();
var app = builder.Build();
Přihlašovací údaje v požadavcích mezi zdroji
Přihlašovací údaje vyžadují speciální zpracování v požadavku CORS. Ve výchozím nastavení prohlížeč neodesílá přihlašovací údaje s požadavkem z jiného původu. Přihlašovací údaje zahrnují soubory cookie a schémata ověřování HTTP. Chcete-li odeslat přihlašovací údaje s požadavkem mezi zdroji, musí klient nastavit XMLHttpRequest.withCredentials na hodnotu true.
Přímé použití XMLHttpRequest :
var xhr = new XMLHttpRequest();
xhr.open('get', 'https://www.example.com/api/test');
xhr.withCredentials = true;
Pomocí jQuery:
$.ajax({
type: 'get',
url: 'https://www.example.com/api/test',
xhrFields: {
withCredentials: true
}
});
Použití rozhraní Fetch API:
fetch('https://www.example.com/api/test', {
credentials: 'include'
});
Server musí přihlašovací údaje povolit. Chcete-li povolit pověření pro různé zdroje, zavolejte AllowCredentials:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy("MyMyAllowCredentialsPolicy",
policy =>
{
policy.WithOrigins("http://example.com")
.AllowCredentials();
});
});
builder.Services.AddControllers();
var app = builder.Build();
Odpověď HTTP obsahuje hlavičku Access-Control-Allow-Credentials , která prohlížeči říká, že server povoluje přihlašovací údaje pro požadavek mezi zdroji.
Pokud prohlížeč odešle přihlašovací údaje, ale odpověď neobsahuje platnou Access-Control-Allow-Credentials hlavičku, prohlížeč nezobrazí odpověď aplikaci a požadavek mezi zdroji selže.
Povolení přihlašovacích údajů mezi různými zdroji představuje bezpečnostní riziko. Web v jiné doméně může odeslat přihlašovací údaje přihlášeného uživatele do aplikace jménem uživatele bez vědomí uživatele.
Specifikace CORS také uvádí, že nastavení původu na "*" (všechny zdroje) je neplatné, pokud je hlavička Access-Control-Allow-Credentials přítomna.
Preflightové požadavky
U některých požadavků CORS prohlížeč před provedením skutečného požadavku odešle další požadavek OPTIONS . Tento požadavek se nazývá předběžný požadavek. Prohlížeč může předběžný požadavek přeskočit, pokud jsou splněny všechny následující podmínky:
- Metoda požadavku je GET, HEAD nebo POST.
- Aplikace nenastavuje jiné hlavičky požadavků než
Accept,Accept-Language,Content-Language, ,Content-TypeneboLast-Event-ID. - Hlavička
Content-Type, pokud je nastavená, má jednu z následujících hodnot:application/x-www-form-urlencodedmultipart/form-datatext/plain
Pravidlo hlavičky požadavku nastavené pro požadavek klienta se vztahuje na hlavičky, které aplikace nastaví voláním setRequestHeader objektu XMLHttpRequest . Specifikace CORS označuje tyto hlavičky jako hlavičky požadavku autora. Pravidlo se nevztahuje na hlavičky, které může prohlížeč nastavit, například User-Agent, Hostnebo Content-Length.
Následuje příklad odpovědi podobné předběžnému požadavku vytvořenému z tlačítka [Put test] v části Test CORS tohoto dokumentu.
General:
Request URL: https://cors3.azurewebsites.net/api/values/5
Request Method: OPTIONS
Status Code: 204 No Content
Response Headers:
Access-Control-Allow-Methods: PUT,DELETE,GET
Access-Control-Allow-Origin: https://cors1.azurewebsites.net
Server: Microsoft-IIS/10.0
Set-Cookie: ARRAffinity=8f8...8;Path=/;HttpOnly;Domain=cors1.azurewebsites.net
Vary: Origin
Request Headers:
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Access-Control-Request-Method: PUT
Connection: keep-alive
Host: cors3.azurewebsites.net
Origin: https://cors1.azurewebsites.net
Referer: https://cors1.azurewebsites.net/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0
Předběžný požadavek používá metodu HTTP OPTIONS . Může obsahovat následující hlavičky:
- Access-Control-Request-Method: Metoda HTTP, která se použije pro skutečný požadavek.
-
Access-Control-Request-Headers: Seznam hlaviček žádosti, které aplikace nastaví ve skutečném požadavku. Jak jsme uvedli dříve, nezahrnuje hlavičky, které prohlížeče nastaví, například
User-Agent. - Access-Control-Allow-Methods
Pokud je preflight požadavek zamítnut, aplikace vrátí odpověď 200 OK, ale nenastaví hlavičky CORS. Prohlížeč se proto nepokouší o požadavek na jiný původ. Příklad zamítnutého preflightového požadavku najdete v části Test CORS tohoto dokumentu.
Pomocí nástrojů F12 konzolová aplikace zobrazí v závislosti na prohlížeči chybu podobnou jedné z následujících možností:
- Firefox: Požadavek mezi různými zdroji byl zablokován: Zásada stejného původu nepovoluje přístup ke vzdálenému prostředku na adrese
https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5. (Důvod: Požadavek CORS nebyl úspěšný). Zjistit více - Založeno na Chromiu: Přístup k načtení na adrese 'https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5' z původu 'https://cors3.azurewebsites.net' byl zablokován zásadami CORS: Odpověď na předběžný požadavek neprošla kontrolou řízení přístupu: v požadovaném prostředku není přítomna žádná hlavička 'Access-Control-Allow-Origin'. Pokud vám vyhovuje neprůhledná odpověď, nastavte režim požadavku na 'no-cors' pro načtení prostředku s vypnutým CORS.
Pokud chcete povolit konkrétní záhlaví, zavolejte WithHeaders:
using Microsoft.Net.Http.Headers;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy("MyAllowHeadersPolicy",
policy =>
{
policy.WithOrigins("http://example.com")
.WithHeaders(HeaderNames.ContentType, "x-custom-header");
});
});
builder.Services.AddControllers();
var app = builder.Build();
Pokud chcete povolit všechna záhlaví žádosti autora, zavolejte AllowAnyHeader:
using Microsoft.Net.Http.Headers;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy("MyAllowAllHeadersPolicy",
policy =>
{
policy.WithOrigins("https://*.example.com")
.AllowAnyHeader();
});
});
builder.Services.AddControllers();
var app = builder.Build();
Prohlížeče nejsou konzistentní ve způsobu jejich nastavení Access-Control-Request-Headers. Pokud máte některou z těchto:
- Záhlaví jsou nastavená na cokoli jiného než
"*" -
AllowAnyHeader se nazývá: Zahrňte alespoň
Accept,Content-TypeaOrigina všechny vlastní hlavičky, které chcete podporovat.
Automatický předletový kód požadavku
Pokud se použije zásada CORS:
- Globálně voláním
app.UseCorsvProgram.cs. - Použití atributu
[EnableCors]
ASP.NET Core odpovídá na předběžný dotaz OPTIONS.
Povolení CORS pro jednotlivé endpointy pomocí RequireCors aktuálně nepodporuje automatické požadavky preflight.
Toto chování ukazuje část Test CORS tohoto dokumentu.
Atribut [HttpOptions] pro předběžné požadavky
Když je CORS povolená s příslušnými zásadami, ASP.NET Core obvykle automaticky reaguje na předběžné požadavky CORS. V některých scénářích to nemusí být tento případ. Například použití CORS se směrováním koncových bodů.
Následující kód používá atribut [HttpOptions] k vytvoření koncových bodů pro požadavky OPTIONS:
[Route("api/[controller]")]
[ApiController]
public class TodoItems2Controller : ControllerBase
{
// OPTIONS: api/TodoItems2/5
[HttpOptions("{id}")]
public IActionResult PreflightRoute(int id)
{
return NoContent();
}
// OPTIONS: api/TodoItems2
[HttpOptions]
public IActionResult PreflightRoute()
{
return NoContent();
}
[HttpPut("{id}")]
public IActionResult PutTodoItem(int id)
{
if (id < 1)
{
return BadRequest();
}
return ControllerContext.MyDisplayRouteInfo(id);
}
Nastavení doby předběžného vypršení platnosti
Hlavička Access-Control-Max-Age určuje, jak dlouho může být odpověď na předběžný požadavek uložena do mezipaměti. Chcete-li nastavit toto záhlaví, zavolejte SetPreflightMaxAge:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy("MySetPreflightExpirationPolicy",
policy =>
{
policy.WithOrigins("http://example.com")
.SetPreflightMaxAge(TimeSpan.FromSeconds(2520));
});
});
builder.Services.AddControllers();
var app = builder.Build();
Jak CORS funguje
Tato část popisuje, co se stane v požadavku CORS na úrovni zpráv HTTP.
- CORS není bezpečnostní funkce. CORS je standard W3C, který umožňuje serveru uvolnit zásady stejného původu.
- Například by škodlivý útočník mohl proti vašemu webu použít Cross-Site Scripting (XSS) a odeslat požadavek mezi weby na svůj web s povoleným CORS, aby odcizil informace.
- API není bezpečnější tím, že umožňuje CORS.
- Je na klientovi (prohlížeči), aby vynucoval CORS. Server spustí požadavek a vrátí odpověď. Je to klient, který vrací chybu a blokuje odpověď. Například některý z následujících nástrojů zobrazí odpověď serveru:
- Fiddler
- .NET HttpClient
- Ve webovém prohlížeči zadáním adresy URL do adresního řádku.
- Je na klientovi (prohlížeči), aby vynucoval CORS. Server spustí požadavek a vrátí odpověď. Je to klient, který vrací chybu a blokuje odpověď. Například některý z následujících nástrojů zobrazí odpověď serveru:
- Je to způsob, jak server umožňuje prohlížečům provést požadavek XHR nebo Fetch API z jiné domény, který by jinak byl zakázán.
- Prohlížeče bez CORS nemůžou provádět žádosti mezi zdroji. Před CORS se k obejití tohoto omezení použil JSONP . JSONP nepoužívá XHR, k přijetí odpovědi používá
<script>značku. Skripty je povoleno načítat z jiného původu.
- Prohlížeče bez CORS nemůžou provádět žádosti mezi zdroji. Před CORS se k obejití tohoto omezení použil JSONP . JSONP nepoužívá XHR, k přijetí odpovědi používá
Specifikace CORS zavedla několik nových hlaviček HTTP, které umožňují požadavky mezi zdroji. Pokud prohlížeč podporuje CORS, nastaví tato záhlaví automaticky u požadavků z jiného původu. K povolení CORS se nevyžaduje vlastní javascriptový kód.
Následuje příklad požadavku mezi různými zdroji z testovacího tlačítka Values do https://cors1.azurewebsites.net/api/values. Hlavička Origin :
- Poskytuje doménu webu, který odesílá požadavek.
- Vyžaduje se a musí se lišit od hostitele.
Obecné hlavičky
Request URL: https://cors1.azurewebsites.net/api/values
Request Method: GET
Status Code: 200 OK
Hlavičky odpovědi
Content-Encoding: gzip
Content-Type: text/plain; charset=utf-8
Server: Microsoft-IIS/10.0
Set-Cookie: ARRAffinity=8f...;Path=/;HttpOnly;Domain=cors1.azurewebsites.net
Transfer-Encoding: chunked
Vary: Accept-Encoding
X-Powered-By: ASP.NET
Hlavičky požadavků
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Connection: keep-alive
Host: cors1.azurewebsites.net
Origin: https://cors3.azurewebsites.net
Referer: https://cors3.azurewebsites.net/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0 ...
V požadavcích OPTIONS server v odpovědi nastaví hlavičku Response headersAccess-Control-Allow-Origin: {allowed origin}. Například požadavek pro tlačítko Odstranit v nasazeném OPTIONS obsahuje následující hlavičky:
Obecné hlavičky
Request URL: https://cors3.azurewebsites.net/api/TodoItems2/MyDelete2/5
Request Method: OPTIONS
Status Code: 204 No Content
Hlavičky odpovědi
Access-Control-Allow-Headers: Content-Type,x-custom-header
Access-Control-Allow-Methods: PUT,DELETE,GET,OPTIONS
Access-Control-Allow-Origin: https://cors1.azurewebsites.net
Server: Microsoft-IIS/10.0
Set-Cookie: ARRAffinity=8f...;Path=/;HttpOnly;Domain=cors3.azurewebsites.net
Vary: Origin
X-Powered-By: ASP.NET
Hlavičky požadavků
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Access-Control-Request-Headers: content-type
Access-Control-Request-Method: DELETE
Connection: keep-alive
Host: cors3.azurewebsites.net
Origin: https://cors1.azurewebsites.net
Referer: https://cors1.azurewebsites.net/test?number=2
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0
V předchozích hlavičkách odpovědi server v odpovědi nastaví hlavičku Access-Control-Allow-Origin. Hodnota https://cors1.azurewebsites.net této hlavičky odpovídá Origin hlavičce požadavku.
Pokud je zavoláno AllowAnyOrigin, vrátí se Access-Control-Allow-Origin: *, zástupná hodnota.
AllowAnyOrigin umožňuje jakýkoli původ.
Pokud odpověď neobsahuje hlavičku Access-Control-Allow-Origin, požadavek mezi různými zdroji selže. Konkrétně prohlížeč požadavek zakáže. I když server vrátí úspěšnou odpověď, prohlížeč nepřístupní odpověď klientské aplikaci.
Přesměrování z HTTP na HTTPS způsobuje chybu ERR_INVALID_REDIRECT u předběžného požadavku CORS.
Požadavky na koncový bod používající HTTP, které UseHttpsRedirection přesměruje na HTTPS, selžou s chybou ERR_INVALID_REDIRECT on the CORS preflight request.
Projekty API mohou odmítat požadavky HTTP namísto použití UseHttpsRedirection k přesměrování požadavků na HTTPS.
Zobrazit požadavky OPTIONS
Ve výchozím nastavení prohlížeče Chrome a Edge nezobrazují požadavky OPTIONS na kartě sítě nástrojů F12. Zobrazení požadavků OPTIONS v těchto prohlížečích:
-
chrome://flags/#out-of-blink-corsneboedge://flags/#out-of-blink-cors - zakažte příznak.
- restart.
Firefox ve výchozím nastavení zobrazuje požadavky OPTIONS.
CORS ve službě IIS
Při nasazování do služby IIS musí CORS běžet před ověřováním systému Windows, pokud server není nakonfigurovaný tak, aby povoloval anonymní přístup. Pro podporu tohoto scénáře je potřeba nainstalovat a nakonfigurovat modul CORS služby IIS pro aplikaci.
Testování CORS
Ukázkový soubor ke stažení obsahuje kód pro testování CORS. Podívejte se, jak stahovat. Ukázka je projekt rozhraní API s přidanými stránkami Razor :
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: "MyPolicy",
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com",
"https://cors1.azurewebsites.net",
"https://cors3.azurewebsites.net",
"https://localhost:44398",
"https://localhost:5001")
.WithMethods("PUT", "DELETE", "GET");
});
});
builder.Services.AddControllers();
builder.Services.AddRazorPages();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.MapControllers();
app.MapRazorPages();
app.Run();
Warning
WithOrigins("https://localhost:<port>"); lze použít pouze k testování ukázkové aplikace podobné jako ukázkový kód ke stažení.
ValuesController Následující text uvádí koncové body pro testování:
[EnableCors("MyPolicy")]
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
// GET api/values
[HttpGet]
public IActionResult Get() =>
ControllerContext.MyDisplayRouteInfo();
// GET api/values/5
[HttpGet("{id}")]
public IActionResult Get(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
// PUT api/values/5
[HttpPut("{id}")]
public IActionResult Put(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
// GET: api/values/GetValues2
[DisableCors]
[HttpGet("{action}")]
public IActionResult GetValues2() =>
ControllerContext.MyDisplayRouteInfo();
}
MyDisplayRouteInfo poskytuje balíček NuGet Rick.Docs.Samples.RouteInfo a zobrazí informace o trase.
Otestujte předchozí vzorový kód pomocí jednoho z následujících přístupů:
- Spusťte ukázku pomocí
dotnet runs výchozí adresou URLhttps://localhost:5001. - Spusťte ukázku ze sady Visual Studio s portem nastaveným na 44398 pro adresu URL souboru
https://localhost:44398.
Použití prohlížeče s nástroji F12:
Vyberte tlačítko Hodnoty a zkontrolujte záhlaví na kartě Síť.
Vyberte tlačítko PUT test. Pokyny k zobrazení požadavku OPTIONS najdete v části Zobrazení MOŽNOSTÍ . Test PUT vytvoří dva požadavky, předběžný požadavek OPTIONS a požadavek PUT.
GetValues2 [DisableCors]Výběrem tlačítka aktivujte neúspěšný požadavek CORS. Jak je uvedeno v dokumentaci, odpověď vrátí stavový kód 200 (OK), ale požadavek CORS se neodešle. Vyberte kartu Konzola a zobrazte chybu CORS. V závislosti na prohlížeči se zobrazí chyba podobná této:Zásady CORS blokovaly přístup k načtení
'https://cors1.azurewebsites.net/api/values/GetValues2'z zdroje'https://cors3.azurewebsites.net': U požadovaného prostředku není k dispozici žádná hlavička Access-Control-Allow-Origin. Pokud vám vyhovuje neprůhledná odpověď, nastavte režim požadavku na 'no-cors' pro načtení prostředku s vypnutým CORS.
Koncové body s povoleným CORS lze testovat pomocí nástrojů, jako jsou curl nebo Fiddler. Při použití nástroje se původ požadavku určeného Origin hlavičkou musí lišit od hostitele, který požadavek přijímá. Pokud požadavek není na základě hodnoty hlavičky považován za Origin:
- Není nutné, aby middleware CORS zpracovával požadavek.
- Hlavičky CORS nejsou v odpovědi vráceny.
Následující příkaz používá curl k vydání požadavku OPTIONS s informacemi:
curl -X OPTIONS https://cors3.azurewebsites.net/api/TodoItems2/5 -i
Testování CORS pomocí směrování koncových bodů a [HttpOptions]
Povolení CORS pro jednotlivé endpointy pomocí RequireCors v současnosti nepodporujeautomatické požadavky preflight. Zvažte následující kód, který používá směrování koncových bodů k povolení CORS:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: "MyPolicy",
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com",
"https://cors1.azurewebsites.net",
"https://cors3.azurewebsites.net",
"https://localhost:44398",
"https://localhost:5001")
.WithMethods("PUT", "DELETE", "GET");
});
});
builder.Services.AddControllers();
builder.Services.AddRazorPages();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.MapControllers();
app.MapRazorPages();
app.Run();
Následující TodoItems1Controller poskytuje koncové body pro testování:
[Route("api/[controller]")]
[ApiController]
public class TodoItems1Controller : ControllerBase
{
// PUT: api/TodoItems1/5
[HttpPut("{id}")]
public IActionResult PutTodoItem(int id)
{
if (id < 1)
{
return Content($"ID = {id}");
}
return ControllerContext.MyDisplayRouteInfo(id);
}
// Delete: api/TodoItems1/5
[HttpDelete("{id}")]
public IActionResult MyDelete(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
// GET: api/TodoItems1
[HttpGet]
public IActionResult GetTodoItems() =>
ControllerContext.MyDisplayRouteInfo();
[EnableCors]
[HttpGet("{action}")]
public IActionResult GetTodoItems2() =>
ControllerContext.MyDisplayRouteInfo();
// Delete: api/TodoItems1/MyDelete2/5
[EnableCors]
[HttpDelete("{action}/{id}")]
public IActionResult MyDelete2(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
}
Otestujte předchozí kód z testovací stránky (https://cors1.azurewebsites.net/test?number=1) nasazené ukázky.
Tlačítka Delete [EnableCors] a GET [EnableCors] jsou úspěšná, protože koncové body mají [EnableCors] a reagují na předběžné požadavky. Ostatní koncové body selžou. Tlačítko GET selže, protože JavaScript odesílá:
headers: {
"Content-Type": "x-custom-header"
},
Následující TodoItems2Controller poskytuje podobné endpointy, ale obsahuje explicitní kód pro zpracování požadavků OPTIONS:
[Route("api/[controller]")]
[ApiController]
public class TodoItems2Controller : ControllerBase
{
// OPTIONS: api/TodoItems2/5
[HttpOptions("{id}")]
public IActionResult PreflightRoute(int id)
{
return NoContent();
}
// OPTIONS: api/TodoItems2
[HttpOptions]
public IActionResult PreflightRoute()
{
return NoContent();
}
[HttpPut("{id}")]
public IActionResult PutTodoItem(int id)
{
if (id < 1)
{
return BadRequest();
}
return ControllerContext.MyDisplayRouteInfo(id);
}
// [EnableCors] // Not needed as OPTIONS path provided
[HttpDelete("{id}")]
public IActionResult MyDelete(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
[EnableCors] // Rquired for this path
[HttpGet]
public IActionResult GetTodoItems() =>
ControllerContext.MyDisplayRouteInfo();
[HttpGet("{action}")]
public IActionResult GetTodoItems2() =>
ControllerContext.MyDisplayRouteInfo();
[EnableCors] // Rquired for this path
[HttpDelete("{action}/{id}")]
public IActionResult MyDelete2(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
}
Předchozí kód lze otestovat nasazením ukázky do Azure. V rozevíracím seznamu Controller vyberte Preflight a potom Set Controller. Všechna volání CORS do TodoItems2Controller koncových bodů jsou úspěšná.
Dodatečné zdroje
Autoři: Rick Anderson a Kirk Larkin
Tento článek ukazuje, jak povolit CORS v aplikaci ASP.NET Core.
Zabezpečení prohlížeče zabraňuje tomu, aby webová stránka odesílala požadavky do jiné domény, než je ta, která webovou stránku obsluhuje. Toto omezení se označuje jako zásada stejného zdroje. Zásada stejného zdroje brání škodlivým webům ve čtení citlivých dat z jiných webů. Někdy můžete chtít povolit jiným webům odesílat do vaší aplikace požadavky z jiného původu. Další informace naleznete v článku Mozilla CORS.
Sdílení prostředků mezi zdroji původu (CORS):
- Je to standard W3C, který umožňuje serveru zmírnit politiku stejného původu.
- Nejedná se o bezpečnostní funkci, CORS oslabuje zabezpečení. Rozhraní API není bezpečnější jen proto, že povoluje CORS. Další informace najdete v tématu Jak CORS funguje.
- Umožňuje serveru explicitně povolit některé požadavky mezi zdroji a zároveň odmítnout jiné.
- Je bezpečnější a flexibilnější než dřívější techniky, například JSONP.
Zobrazení nebo stažení ukázkového kódu (postup stažení)
Stejný původ
Dvě adresy URL mají stejný původ, pokud mají stejná schémata, hostitele a porty (RFC 6454).
Tyto dvě adresy URL mají stejný původ:
https://example.com/foo.htmlhttps://example.com/bar.html
Tyto adresy URL mají jiný původ než předchozí dvě adresy URL:
-
https://example.net: Jiná doména -
https://www.example.com/foo.html: Jiná subdoména -
http://example.com/foo.html: Jiné schéma -
https://example.com:9000/foo.html: Jiný port
Povolit CORS
CORS můžete povolit třemi způsoby:
- V middlewaru pomocí pojmenované zásady nebo výchozí zásady.
- Použití směrování koncových bodů.
- S atributem [EnableCors]
Použití atributu [EnableCors] s pojmenovanou zásadou poskytuje nejlepší kontrolu v omezení koncových bodů, které podporují CORS.
Warning
UseCors musí být volána ve správném pořadí. Další informace najdete v tématu Pořadí middlewaru. Například UseCors musí být volána před UseResponseCaching při použití UseResponseCaching.
Každý přístup je podrobně popsaný v následujících částech.
CORS s pojmenovanými zásadami a middlewarem
Middleware CORS zpracovává požadavky z různých zdrojů. Následující kód použije zásadu CORS pro všechny koncové body aplikace se zadanými zdroji:
public class Startup
{
readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com");
});
});
// services.AddResponseCaching();
services.AddControllers();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors(MyAllowSpecificOrigins);
// app.UseResponseCaching();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
Předchozí kód:
- Nastaví název zásady na
_myAllowSpecificOrigins. Název zásady je libovolný. - Volá UseCors metodu rozšíření a zadává zásadu CORS
_myAllowSpecificOrigins.UseCorspřidá middleware CORS. HovorUseCorsmusí být umístěn zaUseRouting, ale předUseAuthorization. Další informace najdete v tématu Pořadí middlewaru. - Volá 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
_myAllowSpecificOriginsCORS pro všechny koncové body kontroleru. Informace o směrování koncových bodů najdete v části, jak použít zásadu CORS pro konkrétní koncové body. - Při použití middlewaru ukládání odpovědí do mezipaměti zavolejte UseCors před UseResponseCaching.
Při směrování koncových bodů musí být middleware CORS nakonfigurován tak, aby se spouštěl mezi volánímiUseRouting a UseEndpoints.
Pokyny k testování kódu podobného předchozímu kódu najdete v části Test CORS .
Volání metody AddCors přidá služby CORS do kontejneru služeb aplikace:
public class Startup
{
readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com");
});
});
// services.AddResponseCaching();
services.AddControllers();
}
Další informace najdete v tématu Možnosti zásad CORS v tomto dokumentu.
Metody CorsPolicyBuilder mohou být zřetězeny, jak je znázorněno v následujícím kódu:
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy(MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
services.AddControllers();
}
Poznámka: Zadaná adresa URL nesmí obsahovat koncové lomítko (/). Pokud adresa URL končí na /, porovnání vrátí false a nevrátí se žádné záhlaví.
CORS s výchozími zásadami a middlewarem
Následující zvýrazněný kód povolí výchozí zásady CORS:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddDefaultPolicy(
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com");
});
});
services.AddControllers();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
Předchozí kód použije výchozí zásady CORS pro všechny koncové body kontroleru.
Povolte CORS pomocí směrování koncových bodů
Povolení CORS pro jednotlivé koncové body pomocí RequireCorsnepodporuje automatické požadavky preflight. Další informace najdete v tomto problému na GitHubu a Test CORS se směrováním koncových bodů a [HttpOptions].
Pomocí směrování koncového bodu je možné CORS povolit pro jednotlivé koncové body pomocí RequireCors sady rozšiřujících metod:
public class Startup
{
readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com");
});
});
services.AddControllers();
services.AddRazorPages();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/echo",
context => context.Response.WriteAsync("echo"))
.RequireCors(MyAllowSpecificOrigins);
endpoints.MapControllers()
.RequireCors(MyAllowSpecificOrigins);
endpoints.MapGet("/echo2",
context => context.Response.WriteAsync("echo2"));
endpoints.MapRazorPages();
});
}
}
V předchozím kódu:
-
app.UseCorspovolí middleware CORS. Protože není nakonfigurovaná výchozí politika, samotnéapp.UseCors()CORS nepovolí. - Koncové body
/echoa kontroleru umožňují požadavky z různých zdrojů podle zadaných zásad. - Koncové body stránek
/echo2a Razorneumožňují požadavky z různých zdrojů, protože nebyla zadána žádná výchozí zásada.
Atribut [DisableCors] nezakazujeCORS, které bylo povoleno směrováním koncového bodu s RequireCors.
Povolit CORS pomocí atributů
Povolení CORS pomocí atributu [EnableCors] a použití pojmenované zásady pouze na koncové body, které vyžadují CORS, poskytuje nejlepší kontrolu.
Atribut [EnableCors] poskytuje alternativu k použití CORS globálně. Tento [EnableCors] atribut umožňuje CORS pro vybrané koncové body, nikoli pro všechny koncové body:
-
[EnableCors]určuje výchozí zásadu. -
[EnableCors("{Policy String}")]určuje pojmenovanou zásadu.
Atribut [EnableCors] lze použít na:
-
Razor Stránka
PageModel - Controller
- Metoda akce kontroleru
U kontrolerů, modelů stránek nebo metod akcí s atributem [EnableCors] je možné použít různé zásady.
[EnableCors] Když se atribut použije u kontroleru, modelu stránky nebo metody akce a CORS je v middlewaru povolený, použijí se obě zásady. Nedoporučujeme kombinovat zásady. Použijte
[EnableCors]
atribut nebo middleware, ne oba ve stejné aplikaci.
Následující kód použije pro každou metodu jinou zásadu:
[Route("api/[controller]")]
[ApiController]
public class WidgetController : ControllerBase
{
// GET api/values
[EnableCors("AnotherPolicy")]
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
return new string[] { "green widget", "red widget" };
}
// GET api/values/5
[EnableCors("Policy1")]
[HttpGet("{id}")]
public ActionResult<string> Get(int id)
{
return id switch
{
1 => "green widget",
2 => "red widget",
_ => NotFound(),
};
}
}
Následující kód vytvoří dvě zásady CORS:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy("Policy1",
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com");
});
options.AddPolicy("AnotherPolicy",
policy =>
{
policy.WithOrigins("http://www.contoso.com")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
services.AddControllers();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
Pro co nejpřesnější kontrolu omezení požadavků CORS:
- Použijte
[EnableCors("MyPolicy")]s pojmenovanou zásadou. - Nedefinujte výchozí zásadu.
- Nepoužívejte směrování koncových bodů.
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:
- Nepovoluje CORS pomocí směrování koncových bodů.
- Nedefinuje výchozí zásady CORS.
- Pomocí funkce [EnableCors("MyPolicy")] povolí
"MyPolicy"zásady CORS pro kontroler. - Zakáže CORS pro metodu
GetValues2.
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:
- Nastavení povolených zdrojů
- Nastavení povolených metod HTTP
- Nastavení hlaviček povolených požadavků
- Nastavení vystavených hlaviček odpovědí
- Přihlašovací údaje v požadavcích mezi různými zdroji
- Nastavení doby předběžného vypršení platnosti
AddPolicy je voláno v Startup.ConfigureServices. U některých možností může být užitečné nejprve přečíst část Jak CORS funguje .
Nastavení povolených zdrojů
AllowAnyOrigin: Umožňuje požadavky CORS ze všech zdrojů s jakýmkoli schématem (http nebo https).
AllowAnyOrigin není zabezpečená, protože jakýkoli web může na aplikaci odesílat cross-origin požadavky.
Note
Zadání AllowAnyOrigin a AllowCredentials představuje nezabezpečenou konfiguraci a může vést k padělání požadavků mezi weby. Služba CORS vrátí neplatnou odpověď CORS, když je aplikace nakonfigurovaná s oběma metodami.
AllowAnyOrigin ovlivňuje předběžné požadavky a hlavičku Access-Control-Allow-Origin . Další informace najdete v části Předběžné požadavky .
SetIsOriginAllowedToAllowWildcardSubdomains: Nastaví IsOriginAllowed vlastnost zásady na funkci, která umožňuje, aby zdroje odpovídaly nakonfigurované zástupné doméně při vyhodnocování, zda je původ povolený.
options.AddPolicy("MyAllowSubdomainPolicy",
policy =>
{
policy.WithOrigins("https://*.example.com")
.SetIsOriginAllowedToAllowWildcardSubdomains();
});
V předchozím kódu je SetIsOriginAllowedToAllowWildcardSubdomains volána se zástupným znakem domény "https://*.example.com". Toto nastavení umožňuje CORS žádosti z jakékoli subdomény example.com, jako https://subdomain.example.com nebo https://api.example.com. Zástupný znak * musí být zahrnut v původu, aby umožnil porovnávání subdomén pomocí zástupných znaků.
Nastavení povolených metod HTTP
- Povoluje libovolnou metodu HTTP:
- Ovlivňuje předběžné požadavky a hlavičku
Access-Control-Allow-Methods. Další informace najdete v části Předběžné požadavky .
Nastavení hlaviček povolených požadavků
Chcete-li povolit odesílání konkrétních hlaviček v požadavku CORS, označovaných jako hlavičky požadavku autora, zavolejte WithHeaders a zadejte povolené hlavičky:
options.AddPolicy("MyAllowHeadersPolicy",
policy =>
{
// requires using Microsoft.Net.Http.Headers;
policy.WithOrigins("http://example.com")
.WithHeaders(HeaderNames.ContentType, "x-custom-header");
});
Pokud chcete povolit všechna záhlaví žádosti autora, zavolejte AllowAnyHeader:
options.AddPolicy("MyAllowAllHeadersPolicy",
policy =>
{
policy.WithOrigins("https://*.example.com")
.AllowAnyHeader();
});
AllowAnyHeader ovlivňuje preflight požadavky a hlavičku Access-Control-Request-Headers. Další informace najdete v části Předběžné požadavky .
Shoda zásady middlewaru CORS s konkrétními hlavičkami zadanými pomocí WithHeaders je možná pouze tehdy, když hlavičky odeslané v Access-Control-Request-Headers přesně odpovídají hlavičkám uvedeným v WithHeaders.
Představte si například aplikaci nakonfigurovanou takto:
app.UseCors(policy => policy.WithHeaders(HeaderNames.CacheControl));
Middleware CORS odmítne předběžný požadavek s následující hlavičkou požadavku, protože Content-Language (HeaderNames.ContentLanguage) není uvedený v WithHeaders:
Access-Control-Request-Headers: Cache-Control, Content-Language
Aplikace vrátí odpověď 200 OK , ale neodesílá hlavičky CORS zpět. Prohlížeč se proto nepokouší o požadavek na jiný původ.
Nastavení vystavených hlaviček odpovědí
Ve výchozím nastavení prohlížeč nezpřístupňuje do aplikace všechny hlavičky odpovědi. Další informace najdete v tématu Sdílení prostředků mezi různými zdroji W3C (terminologie): jednoduchá hlavička odpovědi.
Hlavičky odpovědi, které jsou ve výchozím nastavení k dispozici, jsou:
Cache-ControlContent-LanguageContent-TypeExpiresLast-ModifiedPragma
Specifikace CORS tyto hlavičky označuje jako jednoduché hlavičky odpovědi. Pokud chcete aplikaci zpřístupnit další hlavičky, zavolejte WithExposedHeaders:
options.AddPolicy("MyExposeResponseHeadersPolicy",
policy =>
{
policy.WithOrigins("https://*.example.com")
.WithExposedHeaders("x-custom-header");
});
Přihlašovací údaje v požadavcích mezi zdroji
Přihlašovací údaje vyžadují speciální zpracování v požadavku CORS. Ve výchozím nastavení prohlížeč neodesílá přihlašovací údaje s požadavkem z jiného původu. Přihlašovací údaje zahrnují soubory cookie a schémata ověřování HTTP. Chcete-li odeslat přihlašovací údaje s požadavkem mezi zdroji, musí klient nastavit XMLHttpRequest.withCredentials na hodnotu true.
Přímé použití XMLHttpRequest :
var xhr = new XMLHttpRequest();
xhr.open('get', 'https://www.example.com/api/test');
xhr.withCredentials = true;
Pomocí jQuery:
$.ajax({
type: 'get',
url: 'https://www.example.com/api/test',
xhrFields: {
withCredentials: true
}
});
Použití rozhraní Fetch API:
fetch('https://www.example.com/api/test', {
credentials: 'include'
});
Server musí přihlašovací údaje povolit. Chcete-li povolit pověření pro různé zdroje, zavolejte AllowCredentials:
options.AddPolicy("MyMyAllowCredentialsPolicy",
policy =>
{
policy.WithOrigins("http://example.com")
.AllowCredentials();
});
Odpověď HTTP obsahuje hlavičku Access-Control-Allow-Credentials , která prohlížeči říká, že server povoluje přihlašovací údaje pro požadavek mezi zdroji.
Pokud prohlížeč odešle přihlašovací údaje, ale odpověď neobsahuje platnou Access-Control-Allow-Credentials hlavičku, prohlížeč nezobrazí odpověď aplikaci a požadavek mezi zdroji selže.
Povolení přihlašovacích údajů mezi různými zdroji představuje bezpečnostní riziko. Web v jiné doméně může odeslat přihlašovací údaje přihlášeného uživatele do aplikace jménem uživatele bez vědomí uživatele.
Specifikace CORS také uvádí, že nastavení původu na "*" (všechny zdroje) je neplatné, pokud je hlavička Access-Control-Allow-Credentials přítomna.
Preflightové požadavky
U některých požadavků CORS prohlížeč před provedením skutečného požadavku odešle další požadavek OPTIONS . Tento požadavek se nazývá předběžný požadavek. Prohlížeč může předběžný požadavek přeskočit, pokud jsou splněny všechny následující podmínky:
- Metoda požadavku je GET, HEAD nebo POST.
- Aplikace nenastavuje jiné hlavičky požadavků než
Accept,Accept-Language,Content-Language, ,Content-TypeneboLast-Event-ID. - Hlavička
Content-Type, pokud je nastavená, má jednu z následujících hodnot:application/x-www-form-urlencodedmultipart/form-datatext/plain
Pravidlo hlavičky požadavku nastavené pro požadavek klienta se vztahuje na hlavičky, které aplikace nastaví voláním setRequestHeader objektu XMLHttpRequest . Specifikace CORS označuje tyto hlavičky jako hlavičky požadavku autora. Pravidlo se nevztahuje na hlavičky, které může prohlížeč nastavit, například User-Agent, Hostnebo Content-Length.
Následuje příklad odpovědi podobné předběžnému požadavku vytvořenému z tlačítka [Put test] v části Test CORS tohoto dokumentu.
General:
Request URL: https://cors3.azurewebsites.net/api/values/5
Request Method: OPTIONS
Status Code: 204 No Content
Response Headers:
Access-Control-Allow-Methods: PUT,DELETE,GET
Access-Control-Allow-Origin: https://cors1.azurewebsites.net
Server: Microsoft-IIS/10.0
Set-Cookie: ARRAffinity=8f8...8;Path=/;HttpOnly;Domain=cors1.azurewebsites.net
Vary: Origin
Request Headers:
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Access-Control-Request-Method: PUT
Connection: keep-alive
Host: cors3.azurewebsites.net
Origin: https://cors1.azurewebsites.net
Referer: https://cors1.azurewebsites.net/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0
Předběžný požadavek používá metodu HTTP OPTIONS . Může obsahovat následující hlavičky:
- Access-Control-Request-Method: Metoda HTTP, která se použije pro skutečný požadavek.
-
Access-Control-Request-Headers: Seznam hlaviček žádosti, které aplikace nastaví ve skutečném požadavku. Jak jsme uvedli dříve, nezahrnuje hlavičky, které prohlížeče nastaví, například
User-Agent. - Access-Control-Allow-Methods
Pokud je preflight požadavek zamítnut, aplikace vrátí odpověď 200 OK, ale nenastaví hlavičky CORS. Prohlížeč se proto nepokouší o požadavek na jiný původ. Příklad zamítnutého preflightového požadavku najdete v části Test CORS tohoto dokumentu.
Pomocí nástrojů F12 konzolová aplikace zobrazí v závislosti na prohlížeči chybu podobnou jedné z následujících možností:
- Firefox: Požadavek mezi různými zdroji byl zablokován: Zásada stejného původu nepovoluje přístup ke vzdálenému prostředku na adrese
https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5. (Důvod: Požadavek CORS nebyl úspěšný). Zjistit více - Založeno na Chromiu: Přístup k načtení na adrese 'https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5' z původu 'https://cors3.azurewebsites.net' byl zablokován zásadami CORS: Odpověď na předběžný požadavek neprošla kontrolou řízení přístupu: v požadovaném prostředku není přítomna žádná hlavička 'Access-Control-Allow-Origin'. Pokud vám vyhovuje neprůhledná odpověď, nastavte režim požadavku na 'no-cors' pro načtení prostředku s vypnutým CORS.
Pokud chcete povolit konkrétní záhlaví, zavolejte WithHeaders:
options.AddPolicy("MyAllowHeadersPolicy",
policy =>
{
// requires using Microsoft.Net.Http.Headers;
policy.WithOrigins("http://example.com")
.WithHeaders(HeaderNames.ContentType, "x-custom-header");
});
Pokud chcete povolit všechna záhlaví žádosti autora, zavolejte AllowAnyHeader:
options.AddPolicy("MyAllowAllHeadersPolicy",
policy =>
{
policy.WithOrigins("https://*.example.com")
.AllowAnyHeader();
});
Prohlížeče nejsou konzistentní ve způsobu jejich nastavení Access-Control-Request-Headers. Pokud máte některou z těchto:
- Záhlaví jsou nastavená na cokoli jiného než
"*" -
AllowAnyHeader se nazývá: Zahrňte alespoň
Accept,Content-TypeaOrigina všechny vlastní hlavičky, které chcete podporovat.
Automatický předletový kód požadavku
Pokud se použije zásada CORS:
- Globálně voláním
app.UseCorsvStartup.Configure. - Použití atributu
[EnableCors]
ASP.NET Core odpovídá na předběžný dotaz OPTIONS.
Povolení CORS pro jednotlivé endpointy pomocí RequireCors aktuálně nepodporuje automatické požadavky preflight.
Toto chování ukazuje část Test CORS tohoto dokumentu.
Atribut [HttpOptions] pro předběžné požadavky
Když je CORS povolená s příslušnými zásadami, ASP.NET Core obvykle automaticky reaguje na předběžné požadavky CORS. V některých scénářích to nemusí být tento případ. Například použití CORS se směrováním koncových bodů.
Následující kód používá atribut [HttpOptions] k vytvoření koncových bodů pro požadavky OPTIONS:
[Route("api/[controller]")]
[ApiController]
public class TodoItems2Controller : ControllerBase
{
// OPTIONS: api/TodoItems2/5
[HttpOptions("{id}")]
public IActionResult PreflightRoute(int id)
{
return NoContent();
}
// OPTIONS: api/TodoItems2
[HttpOptions]
public IActionResult PreflightRoute()
{
return NoContent();
}
[HttpPut("{id}")]
public IActionResult PutTodoItem(int id)
{
if (id < 1)
{
return BadRequest();
}
return ControllerContext.MyDisplayRouteInfo(id);
}
Nastavení doby předběžného vypršení platnosti
Hlavička Access-Control-Max-Age určuje, jak dlouho může být odpověď na předběžný požadavek uložena do mezipaměti. Chcete-li nastavit toto záhlaví, zavolejte SetPreflightMaxAge:
options.AddPolicy("MySetPreflightExpirationPolicy",
policy =>
{
policy.WithOrigins("http://example.com")
.SetPreflightMaxAge(TimeSpan.FromSeconds(2520));
});
Jak CORS funguje
Tato část popisuje, co se stane v požadavku CORS na úrovni zpráv HTTP.
- CORS není bezpečnostní funkce. CORS je standard W3C, který umožňuje serveru uvolnit zásady stejného původu.
- Například by škodlivý útočník mohl proti vašemu webu použít Cross-Site Scripting (XSS) a odeslat požadavek mezi weby na svůj web s povoleným CORS, aby odcizil informace.
- API není bezpečnější tím, že umožňuje CORS.
- Je na klientovi (prohlížeči), aby vynucoval CORS. Server spustí požadavek a vrátí odpověď. Je to klient, který vrací chybu a blokuje odpověď. Například některý z následujících nástrojů zobrazí odpověď serveru:
- Fiddler
- .NET HttpClient
- Ve webovém prohlížeči zadáním adresy URL do adresního řádku.
- Je na klientovi (prohlížeči), aby vynucoval CORS. Server spustí požadavek a vrátí odpověď. Je to klient, který vrací chybu a blokuje odpověď. Například některý z následujících nástrojů zobrazí odpověď serveru:
- Je to způsob, jak server umožňuje prohlížečům provést požadavek XHR nebo Fetch API z jiné domény, který by jinak byl zakázán.
- Prohlížeče bez CORS nemůžou provádět žádosti mezi zdroji. Před CORS se k obejití tohoto omezení použil JSONP . JSONP nepoužívá XHR, k přijetí odpovědi používá
<script>značku. Skripty je povoleno načítat z jiného původu.
- Prohlížeče bez CORS nemůžou provádět žádosti mezi zdroji. Před CORS se k obejití tohoto omezení použil JSONP . JSONP nepoužívá XHR, k přijetí odpovědi používá
Specifikace CORS zavedla několik nových hlaviček HTTP, které umožňují požadavky mezi zdroji. Pokud prohlížeč podporuje CORS, nastaví tato záhlaví automaticky u požadavků z jiného původu. K povolení CORS se nevyžaduje vlastní javascriptový kód.
Následuje příklad požadavku mezi různými zdroji z testovacího tlačítka Values do https://cors1.azurewebsites.net/api/values. Hlavička Origin :
- Poskytuje doménu webu, který odesílá požadavek.
- Vyžaduje se a musí se lišit od hostitele.
Obecné hlavičky
Request URL: https://cors1.azurewebsites.net/api/values
Request Method: GET
Status Code: 200 OK
Hlavičky odpovědi
Content-Encoding: gzip
Content-Type: text/plain; charset=utf-8
Server: Microsoft-IIS/10.0
Set-Cookie: ARRAffinity=8f...;Path=/;HttpOnly;Domain=cors1.azurewebsites.net
Transfer-Encoding: chunked
Vary: Accept-Encoding
X-Powered-By: ASP.NET
Hlavičky požadavků
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Connection: keep-alive
Host: cors1.azurewebsites.net
Origin: https://cors3.azurewebsites.net
Referer: https://cors3.azurewebsites.net/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0 ...
V požadavcích OPTIONS server v odpovědi nastaví hlavičku Response headersAccess-Control-Allow-Origin: {allowed origin}. Například požadavek pro tlačítko Odstranit v nasazeném OPTIONS obsahuje následující hlavičky:
Obecné hlavičky
Request URL: https://cors3.azurewebsites.net/api/TodoItems2/MyDelete2/5
Request Method: OPTIONS
Status Code: 204 No Content
Hlavičky odpovědi
Access-Control-Allow-Headers: Content-Type,x-custom-header
Access-Control-Allow-Methods: PUT,DELETE,GET,OPTIONS
Access-Control-Allow-Origin: https://cors1.azurewebsites.net
Server: Microsoft-IIS/10.0
Set-Cookie: ARRAffinity=8f...;Path=/;HttpOnly;Domain=cors3.azurewebsites.net
Vary: Origin
X-Powered-By: ASP.NET
Hlavičky požadavků
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Access-Control-Request-Headers: content-type
Access-Control-Request-Method: DELETE
Connection: keep-alive
Host: cors3.azurewebsites.net
Origin: https://cors1.azurewebsites.net
Referer: https://cors1.azurewebsites.net/test?number=2
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0
V předchozích hlavičkách odpovědi server v odpovědi nastaví hlavičku Access-Control-Allow-Origin. Hodnota https://cors1.azurewebsites.net této hlavičky odpovídá Origin hlavičce požadavku.
Pokud je zavoláno AllowAnyOrigin, vrátí se Access-Control-Allow-Origin: *, zástupná hodnota.
AllowAnyOrigin umožňuje jakýkoli původ.
Pokud odpověď neobsahuje hlavičku Access-Control-Allow-Origin, požadavek mezi různými zdroji selže. Konkrétně prohlížeč požadavek zakáže. I když server vrátí úspěšnou odpověď, prohlížeč nepřístupní odpověď klientské aplikaci.
Zobrazit požadavky OPTIONS
Ve výchozím nastavení prohlížeče Chrome a Edge nezobrazují požadavky OPTIONS na kartě sítě nástrojů F12. Zobrazení požadavků OPTIONS v těchto prohlížečích:
-
chrome://flags/#out-of-blink-corsneboedge://flags/#out-of-blink-cors - zakažte příznak.
- restart.
Firefox ve výchozím nastavení zobrazuje požadavky OPTIONS.
CORS ve službě IIS
Při nasazování do služby IIS musí CORS běžet před ověřováním systému Windows, pokud server není nakonfigurovaný tak, aby povoloval anonymní přístup. Pro podporu tohoto scénáře je potřeba nainstalovat a nakonfigurovat modul CORS služby IIS pro aplikaci.
Testování CORS
Ukázkový soubor ke stažení obsahuje kód pro testování CORS. Podívejte se, jak stahovat. Ukázka je projekt rozhraní API s přidanými stránkami Razor :
public class StartupTest2
{
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy(name: "MyPolicy",
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com",
"https://cors1.azurewebsites.net",
"https://cors3.azurewebsites.net",
"https://localhost:44398",
"https://localhost:5001")
.WithMethods("PUT", "DELETE", "GET");
});
});
services.AddControllers();
services.AddRazorPages();
}
public void Configure(IApplicationBuilder app)
{
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapRazorPages();
});
}
}
Warning
WithOrigins("https://localhost:<port>"); lze použít pouze k testování ukázkové aplikace podobné jako ukázkový kód ke stažení.
ValuesController Následující text uvádí koncové body pro testování:
[EnableCors("MyPolicy")]
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
// GET api/values
[HttpGet]
public IActionResult Get() =>
ControllerContext.MyDisplayRouteInfo();
// GET api/values/5
[HttpGet("{id}")]
public IActionResult Get(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
// PUT api/values/5
[HttpPut("{id}")]
public IActionResult Put(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
// GET: api/values/GetValues2
[DisableCors]
[HttpGet("{action}")]
public IActionResult GetValues2() =>
ControllerContext.MyDisplayRouteInfo();
}
MyDisplayRouteInfo poskytuje balíček NuGet Rick.Docs.Samples.RouteInfo a zobrazí informace o trase.
Otestujte předchozí vzorový kód pomocí jednoho z následujících přístupů:
- Spusťte ukázku pomocí
dotnet runs výchozí adresou URLhttps://localhost:5001. - Spusťte ukázku ze sady Visual Studio s portem nastaveným na 44398 pro adresu URL souboru
https://localhost:44398.
Použití prohlížeče s nástroji F12:
Vyberte tlačítko Hodnoty a zkontrolujte záhlaví na kartě Síť.
Vyberte tlačítko PUT test. Pokyny k zobrazení požadavku OPTIONS najdete v části Zobrazení MOŽNOSTÍ . Test PUT vytvoří dva požadavky, předběžný požadavek OPTIONS a požadavek PUT.
GetValues2 [DisableCors]Výběrem tlačítka aktivujte neúspěšný požadavek CORS. Jak je uvedeno v dokumentaci, odpověď vrátí stavový kód 200 (OK), ale požadavek CORS se neodešle. Vyberte kartu Konzola a zobrazte chybu CORS. V závislosti na prohlížeči se zobrazí chyba podobná této:Zásady CORS blokovaly přístup k načtení
'https://cors1.azurewebsites.net/api/values/GetValues2'z zdroje'https://cors3.azurewebsites.net': U požadovaného prostředku není k dispozici žádná hlavička Access-Control-Allow-Origin. Pokud vám vyhovuje neprůhledná odpověď, nastavte režim požadavku na 'no-cors' pro načtení prostředku s vypnutým CORS.
Koncové body s povoleným CORS lze testovat pomocí nástrojů, jako jsou curl nebo Fiddler. Při použití nástroje se původ požadavku určeného Origin hlavičkou musí lišit od hostitele, který požadavek přijímá. Pokud požadavek není na základě hodnoty hlavičky považován za Origin:
- Není nutné, aby middleware CORS zpracovával požadavek.
- Hlavičky CORS nejsou v odpovědi vráceny.
Následující příkaz používá curl k vydání požadavku OPTIONS s informacemi:
curl -X OPTIONS https://cors3.azurewebsites.net/api/TodoItems2/5 -i
Testování CORS pomocí směrování koncových bodů a [HttpOptions]
Povolení CORS pro jednotlivé endpointy pomocí RequireCors v současnosti nepodporujeautomatické požadavky preflight. Zvažte následující kód, který používá směrování koncových bodů k povolení CORS:
public class StartupEndPointBugTest
{
readonly string MyPolicy = "_myPolicy";
// .WithHeaders(HeaderNames.ContentType, "x-custom-header")
// forces browsers to require a preflight request with GET
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy(name: MyPolicy,
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com",
"https://cors1.azurewebsites.net",
"https://cors3.azurewebsites.net",
"https://localhost:44398",
"https://localhost:5001")
.WithHeaders(HeaderNames.ContentType, "x-custom-header")
.WithMethods("PUT", "DELETE", "GET", "OPTIONS");
});
});
services.AddControllers();
services.AddRazorPages();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers().RequireCors(MyPolicy);
endpoints.MapRazorPages();
});
}
}
Následující TodoItems1Controller poskytuje koncové body pro testování:
[Route("api/[controller]")]
[ApiController]
public class TodoItems1Controller : ControllerBase
{
// PUT: api/TodoItems1/5
[HttpPut("{id}")]
public IActionResult PutTodoItem(int id)
{
if (id < 1)
{
return Content($"ID = {id}");
}
return ControllerContext.MyDisplayRouteInfo(id);
}
// Delete: api/TodoItems1/5
[HttpDelete("{id}")]
public IActionResult MyDelete(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
// GET: api/TodoItems1
[HttpGet]
public IActionResult GetTodoItems() =>
ControllerContext.MyDisplayRouteInfo();
[EnableCors]
[HttpGet("{action}")]
public IActionResult GetTodoItems2() =>
ControllerContext.MyDisplayRouteInfo();
// Delete: api/TodoItems1/MyDelete2/5
[EnableCors]
[HttpDelete("{action}/{id}")]
public IActionResult MyDelete2(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
}
Otestujte předchozí kód z testovací stránky (https://cors1.azurewebsites.net/test?number=1) nasazené ukázky.
Tlačítka Delete [EnableCors] a GET [EnableCors] jsou úspěšná, protože koncové body mají [EnableCors] a reagují na předběžné požadavky. Ostatní koncové body selžou. Tlačítko GET selže, protože JavaScript odesílá:
headers: {
"Content-Type": "x-custom-header"
},
Následující TodoItems2Controller poskytuje podobné endpointy, ale obsahuje explicitní kód pro zpracování požadavků OPTIONS:
[Route("api/[controller]")]
[ApiController]
public class TodoItems2Controller : ControllerBase
{
// OPTIONS: api/TodoItems2/5
[HttpOptions("{id}")]
public IActionResult PreflightRoute(int id)
{
return NoContent();
}
// OPTIONS: api/TodoItems2
[HttpOptions]
public IActionResult PreflightRoute()
{
return NoContent();
}
[HttpPut("{id}")]
public IActionResult PutTodoItem(int id)
{
if (id < 1)
{
return BadRequest();
}
return ControllerContext.MyDisplayRouteInfo(id);
}
// [EnableCors] // Not needed as OPTIONS path provided
[HttpDelete("{id}")]
public IActionResult MyDelete(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
[EnableCors] // Rquired for this path
[HttpGet]
public IActionResult GetTodoItems() =>
ControllerContext.MyDisplayRouteInfo();
[HttpGet("{action}")]
public IActionResult GetTodoItems2() =>
ControllerContext.MyDisplayRouteInfo();
[EnableCors] // Rquired for this path
[HttpDelete("{action}/{id}")]
public IActionResult MyDelete2(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
}
Předchozí kód lze otestovat nasazením ukázky do Azure. V rozevíracím seznamu Controller vyberte Preflight a potom Set Controller. Všechna volání CORS do TodoItems2Controller koncových bodů jsou úspěšná.