Habilitar o CORS (solicitações entre origens) no ASP.NET Core
Observação
Esta não é a versão mais recente deste artigo. Para a versão atual, consulte a versão .NET 9 deste artigo.
Aviso
Esta versão do ASP.NET Core não tem mais suporte. Para obter mais informações, confira .NET e a Política de Suporte do .NET Core. Para informações sobre a versão vigente, confira a Versão do .NET 8 deste artigo.
Importante
Essas informações relacionam-se ao produto de pré-lançamento, que poderá ser substancialmente modificado antes do lançamento comercial. A Microsoft não oferece nenhuma garantia, explícita ou implícita, quanto às informações fornecidas aqui.
Para a versão atual, consulte a versão .NET 9 deste artigo.
Por Rick Anderson e Kirk Larkin
Este artigo mostra como o Compartilhamento de Recursos Entre Origens (CORS) é habilitado em um aplicativo ASP.NET Core.
A segurança do navegador impede que uma página da Web faça solicitações para um domínio diferente daquele que ofereceu a página da Web. Essa restrição é chamada de política de mesma origem. Essa restrição se chama política da mesma origem e impede que um site mal-intencional leia dados confidenciais de outro site. Às vezes, talvez você queira permitir que outros sites façam solicitações entre origens para seu aplicativo. Para obter mais informações, consulte o artigo do Mozilla CORS.
CORS (compartilhamento de recursos entre origens):
- É um padrão W3C que permite que um servidor relaxe a política de mesma origem.
- Não é um recurso de segurança, o CORS relaxa a segurança. Uma API não é mais segura permitindo CORS. Para saber mais, veja Como funciona CORS.
- Permite que um servidor autorize explicitamente algumas solicitações de origem cruzada e rejeite outras.
- É mais seguro e flexível do que técnicas anteriores, como JSONP.
Exibir ou baixar código de exemplo (como baixar)
Mesma origem
Duas URLs têm a mesma origem se tiverem esquemas, hosts e portas idênticos (RFC 6454).
Essas duas URLs têm a mesma origem:
https://example.com/foo.html
https://example.com/bar.html
Essas URLs têm origens diferentes das duas URLs anteriores:
https://example.net
: Domínio diferentehttps://contoso.example.com/foo.html
: Subdomínio diferentehttp://example.com/foo.html
: Esquema diferentehttps://example.com:9000/foo.html
: Porta diferente
Habilitar CORS
Há três maneiras de habilitar CORS:
- No middleware usando uma política nomeada ou uma política padrão.
- Usando o roteamento de ponto de extremidade.
- Com o atributo [EnableCors] .
O uso do atributo [EnableCors] com uma política nomeada fornece o melhor controle na limitação de pontos de extremidade que dão suporte ao CORS.
Aviso
UseCors deve ser chamado na ordem correta. Para obter mais informações, veja ordem do Middleware. Por exemplo, UseCors
deve ser chamado antes de UseResponseCaching usando UseResponseCaching
.
Cada abordagem é detalhada nas seções a seguir.
CORS com política nomeada e middleware
O Middleware CORS lida com solicitações entre origens. O código a seguir aplica uma política CORS a todos os pontos de extremidade do aplicativo com as origens especificadas:
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();
O código anterior:
- Define o nome da política como
_myAllowSpecificOrigins
. O nome da política é arbitrário. - Chama o UseCors método de extensão e especifica a
_myAllowSpecificOrigins
política CORS.UseCors
adiciona o middleware CORS. A chamada paraUseCors
deve ser colocada apósUseRouting
, mas antes deUseAuthorization
. Para obter mais informações, veja ordem do Middleware. - Chama AddCors com uma expressão lambda. O lambda recebe um objeto CorsPolicyBuilder. As opções de configuração, como
WithOrigins
, são descritas posteriormente neste artigo. - Habilita a política CORS
_myAllowSpecificOrigins
para todos os pontos de extremidade do controlador. Confira Roteamento de ponto de extremidade para aplicar uma política CORS a pontos de extremidade específicos. - Ao usar o Middleware de Cache de Resposta, chame UseCors antes de UseResponseCaching.
Com o roteamento de ponto de extremidade, o middleware CORS deve ser configurado para ser executado entre as chamadas para UseRouting
e UseEndpoints
.
A chamada do método AddCors adiciona serviços CORS ao contêiner de serviços do aplicativo:
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();
Para obter mais informações, consulte Opções de política CORS neste documento.
Os métodos CorsPolicyBuilder podem ser encadeados, conforme mostrado no código a seguir:
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();
Observação: a URL especificada não deve conter uma barra à direita (/
). Se a URL terminar com /
, a comparação retornará false
e nenhum cabeçalho será retornado.
Ordem de UseCors e UseStaticFiles
Normalmente, UseStaticFiles
é chamado antes de UseCors
. Os aplicativos que usam JavaScript para recuperar arquivos estáticos entre sites devem chamar UseCors
antes de UseStaticFiles
.
CORS com política padrão e middleware
O código realçado a seguir habilita a política padrão do 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();
O código anterior aplica a política CORS padrão a todos os pontos de extremidade do controlador.
Habilitar Cors com roteamento de ponto de extremidade
Com o roteamento de ponto de extremidade, o CORS pode ser habilitado por ponto de extremidade usando o RequireCors conjunto de métodos de extensão:
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();
No código anterior:
app.UseCors
adiciona o middleware CORS. Como uma política padrão não foi configurada,app.UseCors()
por si só não habilita o CORS.- Os pontos de extremidade do controlador e
/echo
permitem solicitações entre origens usando a política especificada. - Os pontos de extremidade
/echo2
e Razor páginas não permitem solicitações entre origens porque nenhuma política padrão foi especificada.
O atributo [DisableCors]não desabilita o CORS que foi habilitado pelo roteamento de ponto de extremidade com RequireCors
.
Consulte Testar CORS com o atributo [EnableCors] e o método RequireCors para obter instruções sobre como testar código semelhante ao anterior.
Habilitar CORS com atributos
Habilitar o CORS com o atributo [EnableCors] e aplicar uma política nomeada somente aos pontos de extremidade que exigem CORS fornece o melhor controle.
O atributo [EnableCors] fornece uma alternativa para aplicar o CORS globalmente. O atributo [EnableCors]
habilita o CORS para pontos de extremidade selecionados, em vez de todos os pontos de extremidade:
[EnableCors]
especifica a política padrão.[EnableCors("{Policy String}")]
especifica uma política nomeada.
O atributo [EnableCors]
pode ser aplicado a:
- Razor Página
PageModel
- Controller
- Método de ação do controlador
Políticas diferentes podem ser aplicadas a controladores, modelos de página ou métodos de ação com o atributo [EnableCors]
. Quando o atributo [EnableCors]
é aplicado a um controlador, modelo de página ou método de ação e o CORS está habilitado no middleware, ambas as políticas são aplicadas. É recomendável não combinar políticas. Use o [EnableCors]
atributo ou middleware, não ambos no mesmo aplicativo.
O código a seguir aplica uma política diferente a cada método:
[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(),
};
}
}
O código a seguir cria duas políticas 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();
Para obter o melhor controle de limitação de solicitações CORS:
- Use
[EnableCors("MyPolicy")]
com uma política nomeada. - Não defina uma política padrão.
- Não use o roteamento de ponto de extremidade.
O código na próxima seção atende à lista anterior.
Desabilitar CORS
O atributo [DisableCors]não desabilita o CORS que foi habilitado pelo roteamento de ponto de extremidade.
O código a seguir define a política CORS "MyPolicy"
:
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();
O código a seguir desabilita o CORS para a ação GetValues2
:
[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();
}
O código anterior:
- Não habilita o CORS com roteamento de ponto de extremidade.
- Não define uma política de CORS padrão.
- Usa [EnableCors("MyPolicy")] para habilitar a
"MyPolicy"
política CORS para o controlador. - Desabilita o CORS para o método
GetValues2
.
Consulte Testar CORS para obter instruções sobre como testar código semelhante ao código anterior.
Opções de política CORS
Esta seção descreve as várias opções que podem ser definidas em uma política CORS:
- Definir as origens permitidas
- Definir os métodos HTTP permitidos
- Definir os cabeçalhos de solicitação permitidos
- Definir os cabeçalhos de resposta expostos
- Credenciais em solicitações entre origens
- Definir o tempo de expiração do pré-vôo
AddPolicy é chamado em Program.cs
. Para algumas opções, pode ser útil ler primeiro a seção Como funciona o CORS.
Definir as origens permitidas
AllowAnyOrigin: permite solicitações CORS de todas as origens com qualquer esquema (http
ou https
). AllowAnyOrigin
não é seguro porque qualquer site pode fazer solicitações entre origens para o aplicativo.
Observação
A especificação de AllowAnyOrigin
e AllowCredentials
não é uma configuração segura e pode resultar em uma solicitação intersite forjada. O serviço CORS retorna uma resposta CORS inválida quando um aplicativo é configurado com os dois métodos.
AllowAnyOrigin
afeta as solicitações de pré-vôo e o Access-Control-Allow-Origin
cabeçalho. Para obter mais informações, consulte a seção Solicitações de pré-vôo.
SetIsOriginAllowedToAllowWildcardSubdomains: define a IsOriginAllowed propriedade da política como uma função que permite que as origens correspondam a um domínio curinga configurado ao avaliar se a origem é permitida.
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();
Definir os métodos HTTP permitidos
- Permite qualquer método HTTP:
- Afeta as solicitações de pré-vôo e o cabeçalho
Access-Control-Allow-Methods
. Para obter mais informações, consulte a seção Solicitações de pré-vôo.
Definir os cabeçalhos de solicitação permitidos
Para permitir que cabeçalhos específicos sejam enviados em uma solicitação CORS, chamado cabeçalhos de solicitação de autor, chame WithHeaders e especifique os cabeçalhos permitidos:
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();
Para permitir todos os cabeçalhos de solicitação de autor, chame 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
afeta as solicitações de pré-vôo e o cabeçalho Access-Control-Request-Headers. Para obter mais informações, consulte a seção Solicitações de pré-vôo.
Uma correspondência da política do CORS Middleware com cabeçalhos específicos especificados por WithHeaders
só é possível quando os cabeçalhos enviados em Access-Control-Request-Headers
correspondem exatamente aos cabeçalhos declarados em WithHeaders
.
Por exemplo, considere um aplicativo configurado da seguinte maneira:
app.UseCors(policy => policy.WithHeaders(HeaderNames.CacheControl));
O MIDDLEware cors recusa uma solicitação de pré-vôo com o cabeçalho de solicitação a seguir porque Content-Language
(HeaderNames.ContentLanguage) não está listado em WithHeaders
:
Access-Control-Request-Headers: Cache-Control, Content-Language
O aplicativo retorna uma resposta 200 OK, mas não envia os cabeçalhos CORS de volta. Portanto, o navegador não tenta a solicitação entre origens.
Definir os cabeçalhos de resposta expostos
Por padrão, o navegador não expõe todos os cabeçalhos de resposta ao aplicativo. Para obter mais informações, consulte Compartilhamento de recursos entre origens do W3C (Terminologia): cabeçalho de resposta simples.
Os cabeçalhos de resposta disponíveis por padrão são:
Cache-Control
Content-Language
Content-Type
Expires
Last-Modified
Pragma
A especificação CORS chama esses cabeçalhos de cabeçalhos de resposta simples. Para disponibilizar outros cabeçalhos para o aplicativo, chame 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();
Credenciais em solicitações entre origens
As credenciais exigem tratamento especial em uma solicitação CORS. Por padrão, o navegador não envia credenciais com uma solicitação de origem cruzada. As credenciais incluem cookies e esquemas de autenticação HTTP. Para enviar credenciais com uma solicitação entre origens, o cliente deve definir XMLHttpRequest.withCredentials
como true
.
Usando XMLHttpRequest
diretamente:
var xhr = new XMLHttpRequest();
xhr.open('get', 'https://www.example.com/api/test');
xhr.withCredentials = true;
Usando jQuery:
$.ajax({
type: 'get',
url: 'https://www.example.com/api/test',
xhrFields: {
withCredentials: true
}
});
Usando a API Fetch:
fetch('https://www.example.com/api/test', {
credentials: 'include'
});
O servidor deve permitir as credenciais. Para permitir credenciais entre origens, chame 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();
A resposta HTTP inclui um Access-Control-Allow-Credentials
cabeçalho, que informa ao navegador que o servidor permite credenciais para uma solicitação entre origens.
Se o navegador enviar credenciais, mas a resposta não incluir um cabeçalho válido Access-Control-Allow-Credentials
, o navegador não exporá a resposta ao aplicativo e a solicitação entre origens falhará.
Permitir credenciais entre origens é um risco de segurança. Um site em outro domínio pode enviar as credenciais de um usuário conectado para o aplicativo em nome do usuário sem o conhecimento do usuário.
A especificação CORS também afirma que definir origens como "*"
(todas as origens) é inválida se o Access-Control-Allow-Credentials
cabeçalho estiver presente.
Solicitações de pré-voo
Para algumas solicitações CORS, o navegador envia uma solicitação OPTIONS adicional antes de fazer a solicitação real. Essa solicitação é chamada de solicitação de pré-voo. O navegador poderá ignorar a solicitação de pré-vôo se todas as seguintes condições forem verdadeiras:
- O método de solicitação é GET, HEAD ou POST.
- O aplicativo não define cabeçalhos de solicitação diferentes de
Accept
,Accept-Language
,Content-Language
,Content-Type
ouLast-Event-ID
. - O cabeçalho
Content-Type
, se definido, tem um dos seguintes valores:application/x-www-form-urlencoded
multipart/form-data
text/plain
A regra nos cabeçalhos de solicitação definida para a solicitação do cliente se aplica aos cabeçalhos que o aplicativo define chamando setRequestHeader
no objeto XMLHttpRequest
. A especificação CORS chama esses cabeçalhos de cabeçalhos de solicitação de autor. A regra não se aplica a cabeçalhos que o navegador pode definir, como User-Agent
, Host
ou Content-Length
.
Observação
Este artigo contém URLs criadas com a implantação do código de exemplo em dois sites do Azure, https://cors3.azurewebsites.net
e https://cors.azurewebsites.net
.
Veja a seguir um exemplo de resposta semelhante à solicitação de pré-voo feita no botão [Colocar teste] na seção Testar CORS deste documento.
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
A solicitação de pré-vôo usa o método HTTP OPTIONS. Ele pode incluir os seguintes cabeçalhos:
- Access-Control-Request-Method: o método HTTP que será usado para a solicitação real.
- Access-Control-Request-Headers: uma lista de cabeçalhos de solicitação que o aplicativo define na solicitação real. Conforme indicado anteriormente, isso não inclui cabeçalhos que o navegador define, como
User-Agent
.
Se a solicitação de pré-voo for negada, o aplicativo retornará uma resposta 200 OK
, mas não definirá os cabeçalhos CORS. Portanto, o navegador não tenta a solicitação entre origens. Para obter um exemplo de uma solicitação de pré-voo negada, consulte a seção Testar CORS deste documento.
Usando as ferramentas F12, o aplicativo de console mostra um erro semelhante a um dos seguintes, dependendo do navegador:
- Firefox: solicitação entre origens bloqueada: a mesma política de origem não permite a leitura do recurso remoto em
https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5
. (Motivo: a solicitação CORS não foi bem-sucedida). Saiba mais - Chromium baseado: o acesso para buscar em 'https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5' da origem 'https://cors3.azurewebsites.net' foi bloqueado pela política cors: a resposta à solicitação de pré-vôo não passa o controle de acesso marcar: nenhum cabeçalho 'Access-Control-Allow-Origin' está presente no recurso solicitado. Se uma resposta opaca atender às suas necessidades, defina o modo da solicitação como 'no-cors' para buscar o recurso com o CORS desabilitado.
Para permitir cabeçalhos específicos, chame 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();
Para permitir todos os cabeçalhos de solicitação de autor, chame 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();
Os navegadores não são consistentes em como eles definem Access-Control-Request-Headers
. Se um dos dois:
- Cabeçalhos são definidos como qualquer outra coisa que não seja
"*"
- AllowAnyHeader é chamado: inclua pelo menos
Accept
,Content-Type
eOrigin
, além de todos os cabeçalhos personalizados que você deseja dar suporte.
Código de solicitação de pré-vôo automático
Quando a política CORS é aplicada:
- Globalmente chamando
app.UseCors
emProgram.cs
. - Usando o atributo
[EnableCors]
.
ASP.NET Core responde à solicitação OPTIONS de pré-vôo.
A seção Testar CORS deste documento demonstra esse comportamento.
Atributo [HttpOptions] para solicitações de pré-voo
Quando o CORS está habilitado com a política apropriada, ASP.NET Core geralmente responde às solicitações de pré-vôo CORS automaticamente.
O código a seguir usa o atributo [HttpOptions] para criar pontos de extremidade para solicitações 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);
}
Consulte Testar CORS com o atributo [EnableCors] e o método RequireCors para obter instruções sobre como testar o código anterior.
Definir o tempo de expiração do pré-vôo
O cabeçalho Access-Control-Max-Age
especifica por quanto tempo a resposta à solicitação de pré-voo pode ser armazenada em cache. Para definir esse cabeçalho, chame 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();
Habilitar o CORS em um ponto de extremidade
Como funciona o CORS
Esta seção descreve o que acontece em uma solicitação CORS no nível das mensagens HTTP.
- O CORS não é um recurso de segurança. O CORS é um padrão W3C que permite ao servidor flexibilizar a política de same-origin.
- Por exemplo, um ator mal-intencionado pode usar o XSS (Script entre Sites) em seu site e executar uma solicitação entre sites no site habilitado para CORS para roubar informações.
- Uma API não é mais segura permitindo o CORS.
- Cabe ao cliente (navegador) impor o CORS. O servidor executa a solicitação e retorna a resposta, é o cliente que retorna um erro e bloqueia a resposta. Por exemplo, qualquer uma das seguintes ferramentas exibirá a resposta do servidor:
- Fiddler
- .NET HttpClient
- Um navegador da Web inserindo a URL na barra de endereços.
- Cabe ao cliente (navegador) impor o CORS. O servidor executa a solicitação e retorna a resposta, é o cliente que retorna um erro e bloqueia a resposta. Por exemplo, qualquer uma das seguintes ferramentas exibirá a resposta do servidor:
- É uma maneira de um servidor permitir que os navegadores executem uma solicitação de API XHR ou Fetch de origem cruzada que, de outra forma, seria proibida.
- Navegadores sem CORS não podem fazer solicitações entre origens. Antes do CORS, JSONP era usado para contornar essa restrição. O JSONP não usa XHR, ele usa a marca
<script>
para receber a resposta. Os scripts têm permissão para serem carregados entre origens.
- Navegadores sem CORS não podem fazer solicitações entre origens. Antes do CORS, JSONP era usado para contornar essa restrição. O JSONP não usa XHR, ele usa a marca
A especificação CORS introduziu vários novos cabeçalhos HTTP que habilitam solicitações entre origens. Se um navegador der suporte ao CORS, ele definirá esses cabeçalhos automaticamente para solicitações entre origens. O código JavaScript personalizado não é necessário para habilitar o CORS.
Veja a seguir um exemplo de uma solicitação entre origens do botão de teste Valores para https://cors1.azurewebsites.net/api/values
. O cabeçalho Origin
:
- Fornece o domínio do site que está fazendo a solicitação.
- É necessário e deve ser diferente do host.
Cabeçalhos gerais
Request URL: https://cors1.azurewebsites.net/api/values
Request Method: GET
Status Code: 200 OK
Cabeçalhos de resposta
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
Cabeçalhos de solicitação
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 ...
Em solicitações OPTIONS
, o servidor define o cabeçalho Cabeçalhos de resposta Access-Control-Allow-Origin: {allowed origin}
na resposta. Por exemplo, no código de exemplo, a solicitação OPTIONS
de botão Delete [EnableCors]
contém os seguintes cabeçalhos:
Cabeçalhos gerais
Request URL: https://cors3.azurewebsites.net/api/TodoItems2/MyDelete2/5
Request Method: OPTIONS
Status Code: 204 No Content
Cabeçalhos de resposta
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
Cabeçalhos de solicitação
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
Nos cabeçalhos de resposta anteriores, o servidor define o cabeçalho Access-Control-Allow-Origin na resposta. O valor https://cors1.azurewebsites.net
desse cabeçalho corresponde ao cabeçalho Origin
da solicitação.
Se AllowAnyOrigin for chamado, o Access-Control-Allow-Origin: *
, o valor curinga, será retornado. AllowAnyOrigin
permite qualquer origem.
Se a resposta não incluir o cabeçalho Access-Control-Allow-Origin
, a solicitação entre origens falhará. Especificamente, o navegador não permite a solicitação. Mesmo que o servidor retorne uma resposta bem-sucedida, o navegador não disponibiliza a resposta para o aplicativo cliente.
O redirecionamento HTTP para HTTPS causa ERR_INVALID_REDIRECT na solicitação de simulação do CORS
Solicitações para um ponto de extremidade usando HTTP que são redirecionadas para HTTPS por falha de UseHttpsRedirection com ERR_INVALID_REDIRECT on the CORS preflight request
.
Os projetos de API podem rejeitar solicitações HTTP em vez de usar UseHttpsRedirection
para redirecionar solicitações para HTTPS.
CORS no IIS
Ao implantar no IIS, o CORS precisará ser executado antes da Autenticação do Windows se o servidor não estiver configurado para permitir o acesso anônimo. Para dar suporte a esse cenário, o módulo CORS do IIS precisa ser instalado e configurado para o aplicativo.
Testar o CORS
O download de exemplo tem código para testar o CORS. Consulte como baixar. O exemplo é um projeto de API com Razor Pages (Páginas) adicionado:
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();
Aviso
WithOrigins("https://localhost:<port>");
só deve ser usado para testar um aplicativo de exemplo semelhante ao código de exemplo de download.
O seguinte ValuesController
fornece os pontos de extremidade para teste:
[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 é fornecido pelo pacote NuGet Rick.Docs.Samples.RouteInfo e exibe as informações de rota.
Teste o código de exemplo anterior usando uma das seguintes abordagens:
- Execute o exemplo com
dotnet run
usando a URL padrão dehttps://localhost:5001
. - Execute o exemplo do Visual Studio com a porta definida como 44398 para uma URL de
https://localhost:44398
.
Usando um navegador com as ferramentas F12:
Selecione o botão Valores e examine os cabeçalhos na guia Rede.
Selecione o botão de teste PUT. Consulte Exibir solicitações OPTIONS para obter instruções sobre como exibir a solicitação OPTIONS. O teste PUT cria duas solicitações, uma solicitação de pré-vôo OPTIONS e a solicitação PUT.
Selecione o botão
GetValues2 [DisableCors]
para disparar uma solicitação CORS com falha. Conforme mencionado no documento, a resposta retorna 200 êxitos, mas a solicitação CORS não é feita. Selecione a guia Console para ver o erro CORS. Dependendo do navegador, um erro semelhante ao seguinte é exibido:O acesso para buscar na
'https://cors1.azurewebsites.net/api/values/GetValues2'
origem'https://cors3.azurewebsites.net'
foi bloqueado pela política do CORS: nenhum cabeçalho 'Access-Control-Allow-Origin' está presente no recurso solicitado. Se uma resposta opaca atender às suas necessidades, defina o modo da solicitação como 'no-cors' para buscar o recurso com o CORS desabilitado.
Os pontos de extremidade habilitados para CORS podem ser testados com uma ferramenta, como curl ou Fiddler. Ao usar uma ferramenta, a origem da solicitação especificada pelo cabeçalho Origin
deve ser diferente do host que recebe a solicitação. Se a solicitação não for entre origens com base no valor do cabeçalho Origin
:
- Não é necessário que o Middleware CORS processe a solicitação.
- Os cabeçalhos CORS não são retornados na resposta.
O comando a seguir usa curl
para emitir uma solicitação OPTIONS com informações:
curl -X OPTIONS https://cors3.azurewebsites.net/api/TodoItems2/5 -i
Testar o CORS com o atributo [EnableCors] e o método RequireCors
Considere o código a seguir que usa o roteamento de ponto de extremidade para habilitar o CORS por ponto de extremidade usando 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();
Observe que apenas o ponto de extremidade /echo
está usando o RequireCors
para permitir solicitações entre origens usando a política especificada. Os controladores abaixo habilitam o CORS usando o atributo [EnableCors].
O seguinte TodoItems1Controller
fornece pontos de extremidade para teste:
[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);
}
Os botões Excluir [EnableCors] e GET [EnableCors] têm êxito, pois os pontos de extremidade têm [EnableCors]
e respondem a solicitações de simulação. Os outros pontos de extremidade falham. O botão GET falha porque o JavaScript envia:
headers: {
"Content-Type": "x-custom-header"
},
O seguinte TodoItems2Controller
fornece pontos de extremidade semelhantes, mas inclui código explícito para responder a solicitações 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);
}
O código anterior pode ser testado implantando o exemplo no Azure. Na lista suspensa Controlador, selecione Simular e, em seguida , Definir Controlador. Todas as chamadas CORS para os pontos de extremidade TodoItems2Controller
são bem-sucedidas.
Recursos adicionais
Por Rick Anderson e Kirk Larkin
Este artigo mostra como habilitar o CORS em um aplicativo ASP.NET Core.
A segurança do navegador impede que uma página da Web faça solicitações para um domínio diferente daquele que ofereceu a página da Web. Essa restrição é chamada de política de mesma origem. Essa restrição se chama política da mesma origem e impede que um site mal-intencional leia dados confidenciais de outro site. Às vezes, talvez você queira permitir que outros sites façam solicitações entre origens para seu aplicativo. Para obter mais informações, consulte o artigo do Mozilla CORS.
CORS (compartilhamento de recursos entre origens):
- É um padrão W3C que permite que um servidor relaxe a política de mesma origem.
- Não é um recurso de segurança, o CORS relaxa a segurança. Uma API não é mais segura permitindo CORS. Para saber mais, veja Como funciona CORS.
- Permite que um servidor autorize explicitamente algumas solicitações de origem cruzada e rejeite outras.
- É mais seguro e flexível do que técnicas anteriores, como JSONP.
Exibir ou baixar código de exemplo (como baixar)
Mesma origem
Duas URLs têm a mesma origem se tiverem esquemas, hosts e portas idênticos (RFC 6454).
Essas duas URLs têm a mesma origem:
https://example.com/foo.html
https://example.com/bar.html
Essas URLs têm origens diferentes das duas URLs anteriores:
https://example.net
: Domínio diferentehttps://www.example.com/foo.html
: Subdomínio diferentehttp://example.com/foo.html
: Esquema diferentehttps://example.com:9000/foo.html
: Porta diferente
Habilitar CORS
Há três maneiras de habilitar CORS:
- No middleware usando uma política nomeada ou uma política padrão.
- Usando o roteamento de ponto de extremidade.
- Com o atributo [EnableCors] .
O uso do atributo [EnableCors] com uma política nomeada fornece o melhor controle na limitação de pontos de extremidade que dão suporte ao CORS.
Aviso
UseCors deve ser chamado na ordem correta. Para obter mais informações, veja ordem do Middleware. Por exemplo, UseCors
deve ser chamado antes de UseResponseCaching usando UseResponseCaching
.
Cada abordagem é detalhada nas seções a seguir.
CORS com política nomeada e middleware
O Middleware CORS lida com solicitações entre origens. O código a seguir aplica uma política CORS a todos os pontos de extremidade do aplicativo com as origens especificadas:
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();
O código anterior:
- Define o nome da política como
_myAllowSpecificOrigins
. O nome da política é arbitrário. - Chama o UseCors método de extensão e especifica a
_myAllowSpecificOrigins
política CORS.UseCors
adiciona o middleware CORS. A chamada paraUseCors
deve ser colocada apósUseRouting
, mas antes deUseAuthorization
. Para obter mais informações, veja ordem do Middleware. - Chama AddCors com uma expressão lambda. O lambda recebe um objeto CorsPolicyBuilder. As opções de configuração, como
WithOrigins
, são descritas posteriormente neste artigo. - Habilita a política CORS
_myAllowSpecificOrigins
para todos os pontos de extremidade do controlador. Confira Roteamento de ponto de extremidade para aplicar uma política CORS a pontos de extremidade específicos. - Ao usar o Middleware de Cache de Resposta, chame UseCors antes de UseResponseCaching.
Com o roteamento de ponto de extremidade, o middleware CORS deve ser configurado para ser executado entre as chamadas para UseRouting
e UseEndpoints
.
A chamada do método AddCors adiciona serviços CORS ao contêiner de serviços do aplicativo:
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();
Para obter mais informações, consulte Opções de política CORS neste documento.
Os métodos CorsPolicyBuilder podem ser encadeados, conforme mostrado no código a seguir:
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();
Observação: a URL especificada não deve conter uma barra à direita (/
). Se a URL terminar com /
, a comparação retornará false
e nenhum cabeçalho será retornado.
Aviso
UseCors
deve ser colocado após UseRouting
e antes de UseAuthorization
. Isso é para garantir que os cabeçalhos CORS sejam incluídos na resposta para chamadas autorizadas e não autorizadas.
Ordem de UseCors e UseStaticFiles
Normalmente, UseStaticFiles
é chamado antes de UseCors
. Os aplicativos que usam JavaScript para recuperar arquivos estáticos entre sites devem chamar UseCors
antes de UseStaticFiles
.
CORS com política padrão e middleware
O código realçado a seguir habilita a política padrão do 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();
O código anterior aplica a política CORS padrão a todos os pontos de extremidade do controlador.
Habilitar Cors com roteamento de ponto de extremidade
Com o roteamento de ponto de extremidade, o CORS pode ser habilitado por ponto de extremidade usando o RequireCors conjunto de métodos de extensão:
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();
No código anterior:
app.UseCors
adiciona o middleware CORS. Como uma política padrão não foi configurada,app.UseCors()
por si só não habilita o CORS.- Os pontos de extremidade do controlador e
/echo
permitem solicitações entre origens usando a política especificada. - Os pontos de extremidade
/echo2
e Razor páginas não permitem solicitações entre origens porque nenhuma política padrão foi especificada.
O atributo [DisableCors]não desabilita o CORS que foi habilitado pelo roteamento de ponto de extremidade com RequireCors
.
No ASP.NET Core 7.0, o atributo [EnableCors]
deve passar um parâmetro ou um aviso ASP0023 é gerado a partir de uma correspondência ambígua na rota. ASP.NET Core 8.0 e posterior não gera o aviso ASP0023
.
[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);
}
Consulte Testar CORS com o atributo [EnableCors] e o método RequireCors para obter instruções sobre como testar código semelhante ao anterior.
Habilitar CORS com atributos
Habilitar o CORS com o atributo [EnableCors] e aplicar uma política nomeada somente aos pontos de extremidade que exigem CORS fornece o melhor controle.
O atributo [EnableCors] fornece uma alternativa para aplicar o CORS globalmente. O atributo [EnableCors]
habilita o CORS para pontos de extremidade selecionados, em vez de todos os pontos de extremidade:
[EnableCors]
especifica a política padrão.[EnableCors("{Policy String}")]
especifica uma política nomeada.
O atributo [EnableCors]
pode ser aplicado a:
- Razor Página
PageModel
- Controller
- Método de ação do controlador
Políticas diferentes podem ser aplicadas a controladores, modelos de página ou métodos de ação com o atributo [EnableCors]
. Quando o atributo [EnableCors]
é aplicado a um controlador, modelo de página ou método de ação e o CORS está habilitado no middleware, ambas as políticas são aplicadas. É recomendável não combinar políticas. Use o [EnableCors]
atributo ou middleware, não ambos no mesmo aplicativo.
O código a seguir aplica uma política diferente a cada método:
[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(),
};
}
}
O código a seguir cria duas políticas 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();
Para obter o melhor controle de limitação de solicitações CORS:
- Use
[EnableCors("MyPolicy")]
com uma política nomeada. - Não defina uma política padrão.
- Não use o roteamento de ponto de extremidade.
O código na próxima seção atende à lista anterior.
Desabilitar CORS
O atributo [DisableCors]não desabilita o CORS que foi habilitado pelo roteamento de ponto de extremidade.
O código a seguir define a política CORS "MyPolicy"
:
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();
O código a seguir desabilita o CORS para a ação GetValues2
:
[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();
}
O código anterior:
- Não habilita o CORS com roteamento de ponto de extremidade.
- Não define uma política de CORS padrão.
- Usa [EnableCors("MyPolicy")] para habilitar a
"MyPolicy"
política CORS para o controlador. - Desabilita o CORS para o método
GetValues2
.
Consulte Testar CORS para obter instruções sobre como testar código semelhante ao código anterior.
Opções de política CORS
Esta seção descreve as várias opções que podem ser definidas em uma política CORS:
- Definir as origens permitidas
- Definir os métodos HTTP permitidos
- Definir os cabeçalhos de solicitação permitidos
- Definir os cabeçalhos de resposta expostos
- Credenciais em solicitações entre origens
- Definir o tempo de expiração do pré-vôo
AddPolicy é chamado em Program.cs
. Para algumas opções, pode ser útil ler primeiro a seção Como funciona o CORS.
Definir as origens permitidas
AllowAnyOrigin: permite solicitações CORS de todas as origens com qualquer esquema (http
ou https
). AllowAnyOrigin
não é seguro porque qualquer site pode fazer solicitações entre origens para o aplicativo.
Observação
A especificação de AllowAnyOrigin
e AllowCredentials
não é uma configuração segura e pode resultar em uma solicitação intersite forjada. O serviço CORS retorna uma resposta CORS inválida quando um aplicativo é configurado com os dois métodos.
AllowAnyOrigin
afeta as solicitações de pré-vôo e o Access-Control-Allow-Origin
cabeçalho. Para obter mais informações, consulte a seção Solicitações de pré-vôo.
SetIsOriginAllowedToAllowWildcardSubdomains: define a IsOriginAllowed propriedade da política como uma função que permite que as origens correspondam a um domínio curinga configurado ao avaliar se a origem é permitida.
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();
Definir os métodos HTTP permitidos
- Permite qualquer método HTTP:
- Afeta as solicitações de pré-vôo e o cabeçalho
Access-Control-Allow-Methods
. Para obter mais informações, consulte a seção Solicitações de pré-vôo.
Definir os cabeçalhos de solicitação permitidos
Para permitir que cabeçalhos específicos sejam enviados em uma solicitação CORS, chamado cabeçalhos de solicitação de autor, chame WithHeaders e especifique os cabeçalhos permitidos:
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();
Para permitir todos os cabeçalhos de solicitação de autor, chame 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
afeta as solicitações de pré-vôo e o cabeçalho Access-Control-Request-Headers. Para obter mais informações, consulte a seção Solicitações de pré-vôo.
Uma correspondência da política do CORS Middleware com cabeçalhos específicos especificados por WithHeaders
só é possível quando os cabeçalhos enviados em Access-Control-Request-Headers
correspondem exatamente aos cabeçalhos declarados em WithHeaders
.
Por exemplo, considere um aplicativo configurado da seguinte maneira:
app.UseCors(policy => policy.WithHeaders(HeaderNames.CacheControl));
O MIDDLEware cors recusa uma solicitação de pré-vôo com o cabeçalho de solicitação a seguir porque Content-Language
(HeaderNames.ContentLanguage) não está listado em WithHeaders
:
Access-Control-Request-Headers: Cache-Control, Content-Language
O aplicativo retorna uma resposta 200 OK, mas não envia os cabeçalhos CORS de volta. Portanto, o navegador não tenta a solicitação entre origens.
Definir os cabeçalhos de resposta expostos
Por padrão, o navegador não expõe todos os cabeçalhos de resposta ao aplicativo. Para obter mais informações, consulte Compartilhamento de recursos entre origens do W3C (Terminologia): cabeçalho de resposta simples.
Os cabeçalhos de resposta disponíveis por padrão são:
Cache-Control
Content-Language
Content-Type
Expires
Last-Modified
Pragma
A especificação CORS chama esses cabeçalhos de cabeçalhos de resposta simples. Para disponibilizar outros cabeçalhos para o aplicativo, chame 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();
Credenciais em solicitações entre origens
As credenciais exigem tratamento especial em uma solicitação CORS. Por padrão, o navegador não envia credenciais com uma solicitação de origem cruzada. As credenciais incluem cookies e esquemas de autenticação HTTP. Para enviar credenciais com uma solicitação entre origens, o cliente deve definir XMLHttpRequest.withCredentials
como true
.
Usando XMLHttpRequest
diretamente:
var xhr = new XMLHttpRequest();
xhr.open('get', 'https://www.example.com/api/test');
xhr.withCredentials = true;
Usando jQuery:
$.ajax({
type: 'get',
url: 'https://www.example.com/api/test',
xhrFields: {
withCredentials: true
}
});
Usando a API Fetch:
fetch('https://www.example.com/api/test', {
credentials: 'include'
});
O servidor deve permitir as credenciais. Para permitir credenciais entre origens, chame 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();
A resposta HTTP inclui um Access-Control-Allow-Credentials
cabeçalho, que informa ao navegador que o servidor permite credenciais para uma solicitação entre origens.
Se o navegador enviar credenciais, mas a resposta não incluir um cabeçalho válido Access-Control-Allow-Credentials
, o navegador não exporá a resposta ao aplicativo e a solicitação entre origens falhará.
Permitir credenciais entre origens é um risco de segurança. Um site em outro domínio pode enviar as credenciais de um usuário conectado para o aplicativo em nome do usuário sem o conhecimento do usuário.
A especificação CORS também afirma que definir origens como "*"
(todas as origens) é inválida se o Access-Control-Allow-Credentials
cabeçalho estiver presente.
Solicitações de pré-voo
Para algumas solicitações CORS, o navegador envia uma solicitação OPTIONS adicional antes de fazer a solicitação real. Essa solicitação é chamada de solicitação de pré-voo. O navegador poderá ignorar a solicitação de pré-vôo se todas as seguintes condições forem verdadeiras:
- O método de solicitação é GET, HEAD ou POST.
- O aplicativo não define cabeçalhos de solicitação diferentes de
Accept
,Accept-Language
,Content-Language
,Content-Type
ouLast-Event-ID
. - O cabeçalho
Content-Type
, se definido, tem um dos seguintes valores:application/x-www-form-urlencoded
multipart/form-data
text/plain
A regra nos cabeçalhos de solicitação definida para a solicitação do cliente se aplica aos cabeçalhos que o aplicativo define chamando setRequestHeader
no objeto XMLHttpRequest
. A especificação CORS chama esses cabeçalhos de cabeçalhos de solicitação de autor. A regra não se aplica a cabeçalhos que o navegador pode definir, como User-Agent
, Host
ou Content-Length
.
Veja a seguir um exemplo de resposta semelhante à solicitação de pré-voo feita no botão [Colocar teste] na seção Testar CORS deste documento.
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
A solicitação de pré-vôo usa o método HTTP OPTIONS. Ele pode incluir os seguintes cabeçalhos:
- Access-Control-Request-Method: o método HTTP que será usado para a solicitação real.
- Access-Control-Request-Headers: uma lista de cabeçalhos de solicitação que o aplicativo define na solicitação real. Conforme indicado anteriormente, isso não inclui cabeçalhos que o navegador define, como
User-Agent
. - Access-Control-Allow-Methods
Se a solicitação de pré-voo for negada, o aplicativo retornará uma resposta 200 OK
, mas não definirá os cabeçalhos CORS. Portanto, o navegador não tenta a solicitação entre origens. Para obter um exemplo de uma solicitação de pré-voo negada, consulte a seção Testar CORS deste documento.
Usando as ferramentas F12, o aplicativo de console mostra um erro semelhante a um dos seguintes, dependendo do navegador:
- Firefox: solicitação entre origens bloqueada: a mesma política de origem não permite a leitura do recurso remoto em
https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5
. (Motivo: a solicitação CORS não foi bem-sucedida). Saiba mais - Chromium baseado: o acesso para buscar em 'https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5' da origem 'https://cors3.azurewebsites.net' foi bloqueado pela política cors: a resposta à solicitação de pré-vôo não passa o controle de acesso marcar: nenhum cabeçalho 'Access-Control-Allow-Origin' está presente no recurso solicitado. Se uma resposta opaca atender às suas necessidades, defina o modo da solicitação como 'no-cors' para buscar o recurso com o CORS desabilitado.
Para permitir cabeçalhos específicos, chame 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();
Para permitir todos os cabeçalhos de solicitação de autor, chame 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();
Os navegadores não são consistentes em como eles definem Access-Control-Request-Headers
. Se um dos dois:
- Cabeçalhos são definidos como qualquer outra coisa que não seja
"*"
- AllowAnyHeader é chamado: inclua pelo menos
Accept
,Content-Type
eOrigin
, além de todos os cabeçalhos personalizados que você deseja dar suporte.
Código de solicitação de pré-vôo automático
Quando a política CORS é aplicada:
- Globalmente chamando
app.UseCors
emProgram.cs
. - Usando o atributo
[EnableCors]
.
ASP.NET Core responde à solicitação OPTIONS de pré-vôo.
A seção Testar CORS deste documento demonstra esse comportamento.
Atributo [HttpOptions] para solicitações de pré-voo
Quando o CORS está habilitado com a política apropriada, ASP.NET Core geralmente responde às solicitações de pré-vôo CORS automaticamente.
O código a seguir usa o atributo [HttpOptions] para criar pontos de extremidade para solicitações 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);
}
Consulte Testar CORS com o atributo [EnableCors] e o método RequireCors para obter instruções sobre como testar o código anterior.
Definir o tempo de expiração do pré-vôo
O cabeçalho Access-Control-Max-Age
especifica por quanto tempo a resposta à solicitação de pré-voo pode ser armazenada em cache. Para definir esse cabeçalho, chame 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();
Habilitar o CORS em um ponto de extremidade
Como funciona o CORS
Esta seção descreve o que acontece em uma solicitação CORS no nível das mensagens HTTP.
- O CORS não é um recurso de segurança. O CORS é um padrão W3C que permite ao servidor flexibilizar a política de same-origin.
- Por exemplo, um ator mal-intencionado pode usar o XSS (Script entre Sites) em seu site e executar uma solicitação entre sites no site habilitado para CORS para roubar informações.
- Uma API não é mais segura permitindo o CORS.
- Cabe ao cliente (navegador) impor o CORS. O servidor executa a solicitação e retorna a resposta, é o cliente que retorna um erro e bloqueia a resposta. Por exemplo, qualquer uma das seguintes ferramentas exibirá a resposta do servidor:
- Fiddler
- .NET HttpClient
- Um navegador da Web inserindo a URL na barra de endereços.
- Cabe ao cliente (navegador) impor o CORS. O servidor executa a solicitação e retorna a resposta, é o cliente que retorna um erro e bloqueia a resposta. Por exemplo, qualquer uma das seguintes ferramentas exibirá a resposta do servidor:
- É uma maneira de um servidor permitir que os navegadores executem uma solicitação de API XHR ou Fetch de origem cruzada que, de outra forma, seria proibida.
- Navegadores sem CORS não podem fazer solicitações entre origens. Antes do CORS, JSONP era usado para contornar essa restrição. O JSONP não usa XHR, ele usa a marca
<script>
para receber a resposta. Os scripts têm permissão para serem carregados entre origens.
- Navegadores sem CORS não podem fazer solicitações entre origens. Antes do CORS, JSONP era usado para contornar essa restrição. O JSONP não usa XHR, ele usa a marca
A especificação CORS introduziu vários novos cabeçalhos HTTP que habilitam solicitações entre origens. Se um navegador der suporte ao CORS, ele definirá esses cabeçalhos automaticamente para solicitações entre origens. O código JavaScript personalizado não é necessário para habilitar o CORS.
Clique no botão de teste PUT no exemplo implantado.
O cabeçalho Origin
:
- Fornece o domínio do site que está fazendo a solicitação.
- É necessário e deve ser diferente do host.
Cabeçalhos gerais
Request URL: https://cors1.azurewebsites.net/api/values
Request Method: GET
Status Code: 200 OK
Cabeçalhos de resposta
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
Cabeçalhos de solicitação
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 ...
Em solicitações OPTIONS
, o servidor define o cabeçalho Cabeçalhos de resposta Access-Control-Allow-Origin: {allowed origin}
na resposta. Por exemplo, no código de exemplo, a solicitação OPTIONS
de botão Delete [EnableCors]
contém os seguintes cabeçalhos:
Cabeçalhos gerais
Request URL: https://cors3.azurewebsites.net/api/TodoItems2/MyDelete2/5
Request Method: OPTIONS
Status Code: 204 No Content
Cabeçalhos de resposta
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
Cabeçalhos de solicitação
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
Nos cabeçalhos de resposta anteriores, o servidor define o cabeçalho Access-Control-Allow-Origin na resposta. O valor https://cors1.azurewebsites.net
desse cabeçalho corresponde ao cabeçalho Origin
da solicitação.
Se AllowAnyOrigin for chamado, o Access-Control-Allow-Origin: *
, o valor curinga, será retornado. AllowAnyOrigin
permite qualquer origem.
Se a resposta não incluir o cabeçalho Access-Control-Allow-Origin
, a solicitação entre origens falhará. Especificamente, o navegador não permite a solicitação. Mesmo que o servidor retorne uma resposta bem-sucedida, o navegador não disponibiliza a resposta para o aplicativo cliente.
O redirecionamento HTTP para HTTPS causa ERR_INVALID_REDIRECT na solicitação de simulação do CORS
Solicitações para um ponto de extremidade usando HTTP que são redirecionadas para HTTPS por falha de UseHttpsRedirection com ERR_INVALID_REDIRECT on the CORS preflight request
.
Os projetos de API podem rejeitar solicitações HTTP em vez de usar UseHttpsRedirection
para redirecionar solicitações para HTTPS.
CORS no IIS
Ao implantar no IIS, o CORS precisará ser executado antes da Autenticação do Windows se o servidor não estiver configurado para permitir o acesso anônimo. Para dar suporte a esse cenário, o módulo CORS do IIS precisa ser instalado e configurado para o aplicativo.
Testar o CORS
O download de exemplo tem código para testar o CORS. Consulte como baixar. O exemplo é um projeto de API com Razor Pages (Páginas) adicionado:
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();
Aviso
WithOrigins("https://localhost:<port>");
só deve ser usado para testar um aplicativo de exemplo semelhante ao código de exemplo de download.
O seguinte ValuesController
fornece os pontos de extremidade para teste:
[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 é fornecido pelo pacote NuGet Rick.Docs.Samples.RouteInfo e exibe as informações de rota.
Teste o código de exemplo anterior usando uma das seguintes abordagens:
- Execute o exemplo com
dotnet run
usando a URL padrão dehttps://localhost:5001
. - Execute o exemplo do Visual Studio com a porta definida como 44398 para uma URL de
https://localhost:44398
.
Usando um navegador com as ferramentas F12:
Selecione o botão Valores e examine os cabeçalhos na guia Rede.
Selecione o botão de teste PUT. Consulte Exibir solicitações OPTIONS para obter instruções sobre como exibir a solicitação OPTIONS. O teste PUT cria duas solicitações, uma solicitação de pré-vôo OPTIONS e a solicitação PUT.
Selecione o botão
GetValues2 [DisableCors]
para disparar uma solicitação CORS com falha. Conforme mencionado no documento, a resposta retorna 200 êxitos, mas a solicitação CORS não é feita. Selecione a guia Console para ver o erro CORS. Dependendo do navegador, um erro semelhante ao seguinte é exibido:O acesso para buscar na
'https://cors1.azurewebsites.net/api/values/GetValues2'
origem'https://cors3.azurewebsites.net'
foi bloqueado pela política do CORS: nenhum cabeçalho 'Access-Control-Allow-Origin' está presente no recurso solicitado. Se uma resposta opaca atender às suas necessidades, defina o modo da solicitação como 'no-cors' para buscar o recurso com o CORS desabilitado.
Os pontos de extremidade habilitados para CORS podem ser testados com uma ferramenta, como curl ou Fiddler. Ao usar uma ferramenta, a origem da solicitação especificada pelo cabeçalho Origin
deve ser diferente do host que recebe a solicitação. Se a solicitação não for entre origens com base no valor do cabeçalho Origin
:
- Não é necessário que o Middleware CORS processe a solicitação.
- Os cabeçalhos CORS não são retornados na resposta.
O comando a seguir usa curl
para emitir uma solicitação OPTIONS com informações:
curl -X OPTIONS https://cors3.azurewebsites.net/api/TodoItems2/5 -i
Testar o CORS com o atributo [EnableCors] e o método RequireCors
Considere o código a seguir que usa o roteamento de ponto de extremidade para habilitar o CORS por ponto de extremidade usando 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();
Observe que apenas o ponto de extremidade /echo
está usando o RequireCors
para permitir solicitações entre origens usando a política especificada. Os controladores abaixo habilitam o CORS usando o atributo [EnableCors].
O seguinte TodoItems1Controller
fornece pontos de extremidade para teste:
[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);
}
Os botões Excluir [EnableCors] e GET [EnableCors] têm êxito, pois os pontos de extremidade têm [EnableCors]
e respondem a solicitações de simulação. Os outros pontos de extremidade falham. O botão GET falha porque o JavaScript envia:
headers: {
"Content-Type": "x-custom-header"
},
O seguinte TodoItems2Controller
fornece pontos de extremidade semelhantes, mas inclui código explícito para responder a solicitações 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);
}
O código anterior pode ser testado implantando o exemplo no Azure. Na lista suspensa Controlador, selecione Simulação e, em seguida, Definir Controlador. Todas as chamadas CORS para os pontos de extremidade TodoItems2Controller
são bem-sucedidas.
Recursos adicionais
Por Rick Anderson e Kirk Larkin
Este artigo mostra como habilitar o CORS em um aplicativo ASP.NET Core.
A segurança do navegador impede que uma página da Web faça solicitações para um domínio diferente daquele que ofereceu a página da Web. Essa restrição é chamada de política de mesma origem. Essa restrição se chama política da mesma origem e impede que um site mal-intencional leia dados confidenciais de outro site. Às vezes, talvez você queira permitir que outros sites façam solicitações entre origens para seu aplicativo. Para obter mais informações, consulte o artigo do Mozilla CORS.
CORS (compartilhamento de recursos entre origens):
- É um padrão W3C que permite que um servidor relaxe a política de mesma origem.
- Não é um recurso de segurança, o CORS relaxa a segurança. Uma API não é mais segura permitindo CORS. Para saber mais, veja Como funciona CORS.
- Permite que um servidor autorize explicitamente algumas solicitações de origem cruzada e rejeite outras.
- É mais seguro e flexível do que técnicas anteriores, como JSONP.
Exibir ou baixar código de exemplo (como baixar)
Mesma origem
Duas URLs têm a mesma origem se tiverem esquemas, hosts e portas idênticos (RFC 6454).
Essas duas URLs têm a mesma origem:
https://example.com/foo.html
https://example.com/bar.html
Essas URLs têm origens diferentes das duas URLs anteriores:
https://example.net
: Domínio diferentehttps://www.example.com/foo.html
: Subdomínio diferentehttp://example.com/foo.html
: Esquema diferentehttps://example.com:9000/foo.html
: Porta diferente
Habilitar CORS
Há três maneiras de habilitar CORS:
- No middleware usando uma política nomeada ou uma política padrão.
- Usando o roteamento de ponto de extremidade.
- Com o atributo [EnableCors] .
O uso do atributo [EnableCors] com uma política nomeada fornece o melhor controle na limitação de pontos de extremidade que dão suporte ao CORS.
Aviso
UseCors deve ser chamado na ordem correta. Para obter mais informações, veja ordem do Middleware. Por exemplo, UseCors
deve ser chamado antes de UseResponseCaching usando UseResponseCaching
.
Cada abordagem é detalhada nas seções a seguir.
CORS com política nomeada e middleware
O Middleware CORS lida com solicitações entre origens. O código a seguir aplica uma política CORS a todos os pontos de extremidade do aplicativo com as origens especificadas:
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();
O código anterior:
- Define o nome da política como
_myAllowSpecificOrigins
. O nome da política é arbitrário. - Chama o UseCors método de extensão e especifica a
_myAllowSpecificOrigins
política CORS.UseCors
adiciona o middleware CORS. A chamada paraUseCors
deve ser colocada apósUseRouting
, mas antes deUseAuthorization
. Para obter mais informações, veja ordem do Middleware. - Chama AddCors com uma expressão lambda. O lambda recebe um objeto CorsPolicyBuilder. As opções de configuração, como
WithOrigins
, são descritas posteriormente neste artigo. - Habilita a política CORS
_myAllowSpecificOrigins
para todos os pontos de extremidade do controlador. Confira Roteamento de ponto de extremidade para aplicar uma política CORS a pontos de extremidade específicos. - Ao usar o Middleware de Cache de Resposta, chame UseCors antes de UseResponseCaching.
Com o roteamento de ponto de extremidade, o middleware CORS deve ser configurado para ser executado entre as chamadas para UseRouting
e UseEndpoints
.
A chamada do método AddCors adiciona serviços CORS ao contêiner de serviços do aplicativo:
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();
Para obter mais informações, consulte Opções de política CORS neste documento.
Os métodos CorsPolicyBuilder podem ser encadeados, conforme mostrado no código a seguir:
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();
Observação: a URL especificada não deve conter uma barra à direita (/
). Se a URL terminar com /
, a comparação retornará false
e nenhum cabeçalho será retornado.
Aviso
UseCors
deve ser colocado após UseRouting
e antes de UseAuthorization
. Isso é para garantir que os cabeçalhos CORS sejam incluídos na resposta para chamadas autorizadas e não autorizadas.
Ordem de UseCors e UseStaticFiles
Normalmente, UseStaticFiles
é chamado antes de UseCors
. Os aplicativos que usam JavaScript para recuperar arquivos estáticos entre sites devem chamar UseCors
antes de UseStaticFiles
.
CORS com política padrão e middleware
O código realçado a seguir habilita a política padrão do 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();
O código anterior aplica a política CORS padrão a todos os pontos de extremidade do controlador.
Habilitar Cors com roteamento de ponto de extremidade
Habilitar o CORS por ponto de extremidade usando RequireCors
não oferece suporte a solicitações de simulação automática. Para obter mais informações, confira esta edição do GitHub e Teste o CORS com roteamento de pontos de extremidade e [HttpOptions].
Com o roteamento de ponto de extremidade, o CORS pode ser habilitado por ponto de extremidade usando o RequireCors conjunto de métodos de extensão:
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();
No código anterior:
app.UseCors
adiciona o middleware CORS. Como uma política padrão não foi configurada,app.UseCors()
por si só não habilita o CORS.- Os pontos de extremidade do controlador e
/echo
permitem solicitações entre origens usando a política especificada. - Os pontos de extremidade
/echo2
e Razor páginas não permitem solicitações entre origens porque nenhuma política padrão foi especificada.
O atributo [DisableCors]não desabilita o CORS que foi habilitado pelo roteamento de ponto de extremidade com RequireCors
.
Consulte Testar CORS com roteamento de ponto de extremidade e [HttpOptions] para obter instruções sobre como testar código semelhante ao anterior.
Habilitar CORS com atributos
Habilitar o CORS com o atributo [EnableCors] e aplicar uma política nomeada somente aos pontos de extremidade que exigem CORS fornece o melhor controle.
O atributo [EnableCors] fornece uma alternativa para aplicar o CORS globalmente. O atributo [EnableCors]
habilita o CORS para pontos de extremidade selecionados, em vez de todos os pontos de extremidade:
[EnableCors]
especifica a política padrão.[EnableCors("{Policy String}")]
especifica uma política nomeada.
O atributo [EnableCors]
pode ser aplicado a:
- Razor Página
PageModel
- Controller
- Método de ação do controlador
Políticas diferentes podem ser aplicadas a controladores, modelos de página ou métodos de ação com o atributo [EnableCors]
. Quando o atributo [EnableCors]
é aplicado a um controlador, modelo de página ou método de ação e o CORS está habilitado no middleware, ambas as políticas são aplicadas. É recomendável não combinar políticas. Use o [EnableCors]
atributo ou middleware, não ambos no mesmo aplicativo.
O código a seguir aplica uma política diferente a cada método:
[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(),
};
}
}
O código a seguir cria duas políticas 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();
Para obter o melhor controle de limitação de solicitações CORS:
- Use
[EnableCors("MyPolicy")]
com uma política nomeada. - Não defina uma política padrão.
- Não use o roteamento de ponto de extremidade.
O código na próxima seção atende à lista anterior.
Desabilitar CORS
O atributo [DisableCors]não desabilita o CORS que foi habilitado pelo roteamento de ponto de extremidade.
O código a seguir define a política CORS "MyPolicy"
:
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();
O código a seguir desabilita o CORS para a ação GetValues2
:
[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();
}
O código anterior:
- Não habilita o CORS com roteamento de ponto de extremidade.
- Não define uma política de CORS padrão.
- Usa [EnableCors("MyPolicy")] para habilitar a
"MyPolicy"
política CORS para o controlador. - Desabilita o CORS para o método
GetValues2
.
Consulte Testar CORS para obter instruções sobre como testar código semelhante ao código anterior.
Opções de política CORS
Esta seção descreve as várias opções que podem ser definidas em uma política CORS:
- Definir as origens permitidas
- Definir os métodos HTTP permitidos
- Definir os cabeçalhos de solicitação permitidos
- Definir os cabeçalhos de resposta expostos
- Credenciais em solicitações entre origens
- Definir o tempo de expiração do pré-vôo
AddPolicy é chamado em Program.cs
. Para algumas opções, pode ser útil ler primeiro a seção Como funciona o CORS.
Definir as origens permitidas
AllowAnyOrigin: permite solicitações CORS de todas as origens com qualquer esquema (http
ou https
). AllowAnyOrigin
não é seguro porque qualquer site pode fazer solicitações entre origens para o aplicativo.
Observação
A especificação de AllowAnyOrigin
e AllowCredentials
não é uma configuração segura e pode resultar em uma solicitação intersite forjada. O serviço CORS retorna uma resposta CORS inválida quando um aplicativo é configurado com os dois métodos.
AllowAnyOrigin
afeta as solicitações de pré-vôo e o Access-Control-Allow-Origin
cabeçalho. Para obter mais informações, consulte a seção Solicitações de pré-vôo.
SetIsOriginAllowedToAllowWildcardSubdomains: define a IsOriginAllowed propriedade da política como uma função que permite que as origens correspondam a um domínio curinga configurado ao avaliar se a origem é permitida.
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();
Definir os métodos HTTP permitidos
- Permite qualquer método HTTP:
- Afeta as solicitações de pré-vôo e o cabeçalho
Access-Control-Allow-Methods
. Para obter mais informações, consulte a seção Solicitações de pré-vôo.
Definir os cabeçalhos de solicitação permitidos
Para permitir que cabeçalhos específicos sejam enviados em uma solicitação CORS, chamado cabeçalhos de solicitação de autor, chame WithHeaders e especifique os cabeçalhos permitidos:
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();
Para permitir todos os cabeçalhos de solicitação de autor, chame 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
afeta as solicitações de pré-vôo e o cabeçalho Access-Control-Request-Headers. Para obter mais informações, consulte a seção Solicitações de pré-vôo.
Uma correspondência da política do CORS Middleware com cabeçalhos específicos especificados por WithHeaders
só é possível quando os cabeçalhos enviados em Access-Control-Request-Headers
correspondem exatamente aos cabeçalhos declarados em WithHeaders
.
Por exemplo, considere um aplicativo configurado da seguinte maneira:
app.UseCors(policy => policy.WithHeaders(HeaderNames.CacheControl));
O MIDDLEware cors recusa uma solicitação de pré-vôo com o cabeçalho de solicitação a seguir porque Content-Language
(HeaderNames.ContentLanguage) não está listado em WithHeaders
:
Access-Control-Request-Headers: Cache-Control, Content-Language
O aplicativo retorna uma resposta 200 OK, mas não envia os cabeçalhos CORS de volta. Portanto, o navegador não tenta a solicitação entre origens.
Definir os cabeçalhos de resposta expostos
Por padrão, o navegador não expõe todos os cabeçalhos de resposta ao aplicativo. Para obter mais informações, consulte Compartilhamento de recursos entre origens do W3C (Terminologia): cabeçalho de resposta simples.
Os cabeçalhos de resposta disponíveis por padrão são:
Cache-Control
Content-Language
Content-Type
Expires
Last-Modified
Pragma
A especificação CORS chama esses cabeçalhos de cabeçalhos de resposta simples. Para disponibilizar outros cabeçalhos para o aplicativo, chame 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();
Credenciais em solicitações entre origens
As credenciais exigem tratamento especial em uma solicitação CORS. Por padrão, o navegador não envia credenciais com uma solicitação de origem cruzada. As credenciais incluem cookies e esquemas de autenticação HTTP. Para enviar credenciais com uma solicitação entre origens, o cliente deve definir XMLHttpRequest.withCredentials
como true
.
Usando XMLHttpRequest
diretamente:
var xhr = new XMLHttpRequest();
xhr.open('get', 'https://www.example.com/api/test');
xhr.withCredentials = true;
Usando jQuery:
$.ajax({
type: 'get',
url: 'https://www.example.com/api/test',
xhrFields: {
withCredentials: true
}
});
Usando a API Fetch:
fetch('https://www.example.com/api/test', {
credentials: 'include'
});
O servidor deve permitir as credenciais. Para permitir credenciais entre origens, chame 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();
A resposta HTTP inclui um Access-Control-Allow-Credentials
cabeçalho, que informa ao navegador que o servidor permite credenciais para uma solicitação entre origens.
Se o navegador enviar credenciais, mas a resposta não incluir um cabeçalho válido Access-Control-Allow-Credentials
, o navegador não exporá a resposta ao aplicativo e a solicitação entre origens falhará.
Permitir credenciais entre origens é um risco de segurança. Um site em outro domínio pode enviar as credenciais de um usuário conectado para o aplicativo em nome do usuário sem o conhecimento do usuário.
A especificação CORS também afirma que definir origens como "*"
(todas as origens) é inválida se o Access-Control-Allow-Credentials
cabeçalho estiver presente.
Solicitações de pré-voo
Para algumas solicitações CORS, o navegador envia uma solicitação OPTIONS adicional antes de fazer a solicitação real. Essa solicitação é chamada de solicitação de pré-voo. O navegador poderá ignorar a solicitação de pré-vôo se todas as seguintes condições forem verdadeiras:
- O método de solicitação é GET, HEAD ou POST.
- O aplicativo não define cabeçalhos de solicitação diferentes de
Accept
,Accept-Language
,Content-Language
,Content-Type
ouLast-Event-ID
. - O cabeçalho
Content-Type
, se definido, tem um dos seguintes valores:application/x-www-form-urlencoded
multipart/form-data
text/plain
A regra nos cabeçalhos de solicitação definida para a solicitação do cliente se aplica aos cabeçalhos que o aplicativo define chamando setRequestHeader
no objeto XMLHttpRequest
. A especificação CORS chama esses cabeçalhos de cabeçalhos de solicitação de autor. A regra não se aplica a cabeçalhos que o navegador pode definir, como User-Agent
, Host
ou Content-Length
.
Veja a seguir um exemplo de resposta semelhante à solicitação de pré-voo feita no botão [Colocar teste] na seção Testar CORS deste documento.
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
A solicitação de pré-vôo usa o método HTTP OPTIONS. Ele pode incluir os seguintes cabeçalhos:
- Access-Control-Request-Method: o método HTTP que será usado para a solicitação real.
- Access-Control-Request-Headers: uma lista de cabeçalhos de solicitação que o aplicativo define na solicitação real. Conforme indicado anteriormente, isso não inclui cabeçalhos que o navegador define, como
User-Agent
. - Access-Control-Allow-Methods
Se a solicitação de pré-voo for negada, o aplicativo retornará uma resposta 200 OK
, mas não definirá os cabeçalhos CORS. Portanto, o navegador não tenta a solicitação entre origens. Para obter um exemplo de uma solicitação de pré-voo negada, consulte a seção Testar CORS deste documento.
Usando as ferramentas F12, o aplicativo de console mostra um erro semelhante a um dos seguintes, dependendo do navegador:
- Firefox: solicitação entre origens bloqueada: a mesma política de origem não permite a leitura do recurso remoto em
https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5
. (Motivo: a solicitação CORS não foi bem-sucedida). Saiba mais - Chromium baseado: o acesso para buscar em 'https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5' da origem 'https://cors3.azurewebsites.net' foi bloqueado pela política cors: a resposta à solicitação de pré-vôo não passa o controle de acesso marcar: nenhum cabeçalho 'Access-Control-Allow-Origin' está presente no recurso solicitado. Se uma resposta opaca atender às suas necessidades, defina o modo da solicitação como 'no-cors' para buscar o recurso com o CORS desabilitado.
Para permitir cabeçalhos específicos, chame 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();
Para permitir todos os cabeçalhos de solicitação de autor, chame 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();
Os navegadores não são consistentes em como eles definem Access-Control-Request-Headers
. Se um dos dois:
- Cabeçalhos são definidos como qualquer outra coisa que não seja
"*"
- AllowAnyHeader é chamado: inclua pelo menos
Accept
,Content-Type
eOrigin
, além de todos os cabeçalhos personalizados que você deseja dar suporte.
Código de solicitação de pré-vôo automático
Quando a política CORS é aplicada:
- Globalmente chamando
app.UseCors
emProgram.cs
. - Usando o atributo
[EnableCors]
.
ASP.NET Core responde à solicitação OPTIONS de pré-vôo.
Habilitar o CORS por ponto de extremidade usando RequireCors
atualmente não dá suporte a solicitações de pré-voo automáticas.
A seção Testar CORS deste documento demonstra esse comportamento.
Atributo [HttpOptions] para solicitações de pré-voo
Quando o CORS está habilitado com a política apropriada, ASP.NET Core geralmente responde às solicitações de pré-vôo CORS automaticamente. Em alguns cenários, esse pode não ser o caso. Por exemplo, usando CORS com roteamento de ponto de extremidade.
O código a seguir usa o atributo [HttpOptions] para criar pontos de extremidade para solicitações 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);
}
Consulte Testar CORS com roteamento de ponto de extremidade e [HttpOptions] para obter instruções sobre como testar o código anterior.
Definir o tempo de expiração do pré-vôo
O cabeçalho Access-Control-Max-Age
especifica por quanto tempo a resposta à solicitação de pré-voo pode ser armazenada em cache. Para definir esse cabeçalho, chame 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();
Como funciona o CORS
Esta seção descreve o que acontece em uma solicitação CORS no nível das mensagens HTTP.
- O CORS não é um recurso de segurança. O CORS é um padrão W3C que permite ao servidor flexibilizar a política de same-origin.
- Por exemplo, um ator mal-intencionado pode usar o XSS (Script entre Sites) em seu site e executar uma solicitação entre sites no site habilitado para CORS para roubar informações.
- Uma API não é mais segura permitindo o CORS.
- Cabe ao cliente (navegador) impor o CORS. O servidor executa a solicitação e retorna a resposta, é o cliente que retorna um erro e bloqueia a resposta. Por exemplo, qualquer uma das seguintes ferramentas exibirá a resposta do servidor:
- Fiddler
- .NET HttpClient
- Um navegador da Web inserindo a URL na barra de endereços.
- Cabe ao cliente (navegador) impor o CORS. O servidor executa a solicitação e retorna a resposta, é o cliente que retorna um erro e bloqueia a resposta. Por exemplo, qualquer uma das seguintes ferramentas exibirá a resposta do servidor:
- É uma maneira de um servidor permitir que os navegadores executem uma solicitação de API XHR ou Fetch de origem cruzada que, de outra forma, seria proibida.
- Navegadores sem CORS não podem fazer solicitações entre origens. Antes do CORS, JSONP era usado para contornar essa restrição. O JSONP não usa XHR, ele usa a marca
<script>
para receber a resposta. Os scripts têm permissão para serem carregados entre origens.
- Navegadores sem CORS não podem fazer solicitações entre origens. Antes do CORS, JSONP era usado para contornar essa restrição. O JSONP não usa XHR, ele usa a marca
A especificação CORS introduziu vários novos cabeçalhos HTTP que habilitam solicitações entre origens. Se um navegador der suporte ao CORS, ele definirá esses cabeçalhos automaticamente para solicitações entre origens. O código JavaScript personalizado não é necessário para habilitar o CORS.
Veja a seguir um exemplo de uma solicitação entre origens do botão de teste Valores para https://cors1.azurewebsites.net/api/values
. O cabeçalho Origin
:
- Fornece o domínio do site que está fazendo a solicitação.
- É necessário e deve ser diferente do host.
Cabeçalhos gerais
Request URL: https://cors1.azurewebsites.net/api/values
Request Method: GET
Status Code: 200 OK
Cabeçalhos de resposta
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
Cabeçalhos de solicitação
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 ...
Em solicitações OPTIONS
, o servidor define o cabeçalho Cabeçalhos de resposta Access-Control-Allow-Origin: {allowed origin}
na resposta. Por exemplo, o exemplo implantado, a solicitação de botão Excluir [EnableCors]OPTIONS
contém os seguintes cabeçalhos:
Cabeçalhos gerais
Request URL: https://cors3.azurewebsites.net/api/TodoItems2/MyDelete2/5
Request Method: OPTIONS
Status Code: 204 No Content
Cabeçalhos de resposta
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
Cabeçalhos de solicitação
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
Nos cabeçalhos de resposta anteriores, o servidor define o cabeçalho Access-Control-Allow-Origin na resposta. O valor https://cors1.azurewebsites.net
desse cabeçalho corresponde ao cabeçalho Origin
da solicitação.
Se AllowAnyOrigin for chamado, o Access-Control-Allow-Origin: *
, o valor curinga, será retornado. AllowAnyOrigin
permite qualquer origem.
Se a resposta não incluir o cabeçalho Access-Control-Allow-Origin
, a solicitação entre origens falhará. Especificamente, o navegador não permite a solicitação. Mesmo que o servidor retorne uma resposta bem-sucedida, o navegador não disponibiliza a resposta para o aplicativo cliente.
O redirecionamento HTTP para HTTPS causa ERR_INVALID_REDIRECT na solicitação de simulação do CORS
Solicitações para um ponto de extremidade usando HTTP que são redirecionadas para HTTPS por falha de UseHttpsRedirection com ERR_INVALID_REDIRECT on the CORS preflight request
.
Os projetos de API podem rejeitar solicitações HTTP em vez de usar UseHttpsRedirection
para redirecionar solicitações para HTTPS.
Exibir solicitações OPTIONS
Por padrão, os navegadores Chrome e Edge não mostram solicitações OPTIONS na guia de rede das ferramentas F12. Para exibir solicitações OPTIONS nestes navegadores:
chrome://flags/#out-of-blink-cors
ouedge://flags/#out-of-blink-cors
- desabilite o sinalizador.
- reiniciar.
O Firefox mostra as solicitações OPTIONS por padrão.
CORS no IIS
Ao implantar no IIS, o CORS precisará ser executado antes da Autenticação do Windows se o servidor não estiver configurado para permitir o acesso anônimo. Para dar suporte a esse cenário, o módulo CORS do IIS precisa ser instalado e configurado para o aplicativo.
Testar o CORS
O download de exemplo tem código para testar o CORS. Consulte como baixar. O exemplo é um projeto de API com Razor Pages (Páginas) adicionado:
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();
Aviso
WithOrigins("https://localhost:<port>");
só deve ser usado para testar um aplicativo de exemplo semelhante ao código de exemplo de download.
O seguinte ValuesController
fornece os pontos de extremidade para teste:
[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 é fornecido pelo pacote NuGet Rick.Docs.Samples.RouteInfo e exibe as informações de rota.
Teste o código de exemplo anterior usando uma das seguintes abordagens:
- Execute o exemplo com
dotnet run
usando a URL padrão dehttps://localhost:5001
. - Execute o exemplo do Visual Studio com a porta definida como 44398 para uma URL de
https://localhost:44398
.
Usando um navegador com as ferramentas F12:
Selecione o botão Valores e examine os cabeçalhos na guia Rede.
Selecione o botão de teste PUT. Consulte Exibir solicitações OPTIONS para obter instruções sobre como exibir a solicitação OPTIONS. O teste PUT cria duas solicitações, uma solicitação de pré-vôo OPTIONS e a solicitação PUT.
Selecione o botão
GetValues2 [DisableCors]
para disparar uma solicitação CORS com falha. Conforme mencionado no documento, a resposta retorna 200 êxitos, mas a solicitação CORS não é feita. Selecione a guia Console para ver o erro CORS. Dependendo do navegador, um erro semelhante ao seguinte é exibido:O acesso para buscar na
'https://cors1.azurewebsites.net/api/values/GetValues2'
origem'https://cors3.azurewebsites.net'
foi bloqueado pela política do CORS: nenhum cabeçalho 'Access-Control-Allow-Origin' está presente no recurso solicitado. Se uma resposta opaca atender às suas necessidades, defina o modo da solicitação como 'no-cors' para buscar o recurso com o CORS desabilitado.
Os pontos de extremidade habilitados para CORS podem ser testados com uma ferramenta, como curl ou Fiddler. Ao usar uma ferramenta, a origem da solicitação especificada pelo cabeçalho Origin
deve ser diferente do host que recebe a solicitação. Se a solicitação não for entre origens com base no valor do cabeçalho Origin
:
- Não é necessário que o Middleware CORS processe a solicitação.
- Os cabeçalhos CORS não são retornados na resposta.
O comando a seguir usa curl
para emitir uma solicitação OPTIONS com informações:
curl -X OPTIONS https://cors3.azurewebsites.net/api/TodoItems2/5 -i
Testar o CORS com o roteamento de ponto de extremidade e [HttpOptions]
Habilitar o CORS por ponto de extremidade usando RequireCors
atualmente não dá suporte a solicitações de pré-voo automáticas. Considere o seguinte código que usa o roteamento de ponto de extremidade para habilitar o 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();
O seguinte TodoItems1Controller
fornece pontos de extremidade para teste:
[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);
}
Teste o código anterior na página de teste (https://cors1.azurewebsites.net/test?number=1
) da amostra implantada.
Os botões Excluir [EnableCors] e GET [EnableCors] têm êxito, pois os pontos de extremidade têm [EnableCors]
e respondem a solicitações de simulação. Os outros pontos de extremidade falham. O botão GET falha porque o JavaScript envia:
headers: {
"Content-Type": "x-custom-header"
},
O seguinte TodoItems2Controller
fornece pontos de extremidade semelhantes, mas inclui código explícito para responder a solicitações 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);
}
O código anterior pode ser testado implantando o exemplo no Azure. Na lista suspensa Controlador, selecione Simulação e, em seguida, Definir Controlador. Todas as chamadas CORS para os pontos de extremidade TodoItems2Controller
são bem-sucedidas.
Recursos adicionais
Por Rick Anderson e Kirk Larkin
Este artigo mostra como habilitar o CORS em um aplicativo ASP.NET Core.
A segurança do navegador impede que uma página da Web faça solicitações para um domínio diferente daquele que ofereceu a página da Web. Essa restrição é chamada de política de mesma origem. Essa restrição se chama política da mesma origem e impede que um site mal-intencional leia dados confidenciais de outro site. Às vezes, talvez você queira permitir que outros sites façam solicitações entre origens para seu aplicativo. Para obter mais informações, consulte o artigo do Mozilla CORS.
CORS (compartilhamento de recursos entre origens):
- É um padrão W3C que permite que um servidor relaxe a política de mesma origem.
- Não é um recurso de segurança, o CORS relaxa a segurança. Uma API não é mais segura permitindo CORS. Para saber mais, veja Como funciona CORS.
- Permite que um servidor autorize explicitamente algumas solicitações de origem cruzada e rejeite outras.
- É mais seguro e flexível do que técnicas anteriores, como JSONP.
Exibir ou baixar código de exemplo (como baixar)
Mesma origem
Duas URLs têm a mesma origem se tiverem esquemas, hosts e portas idênticos (RFC 6454).
Essas duas URLs têm a mesma origem:
https://example.com/foo.html
https://example.com/bar.html
Essas URLs têm origens diferentes das duas URLs anteriores:
https://example.net
: Domínio diferentehttps://www.example.com/foo.html
: Subdomínio diferentehttp://example.com/foo.html
: Esquema diferentehttps://example.com:9000/foo.html
: Porta diferente
Habilitar CORS
Há três maneiras de habilitar CORS:
- No middleware usando uma política nomeada ou uma política padrão.
- Usando o roteamento de ponto de extremidade.
- Com o atributo [EnableCors] .
O uso do atributo [EnableCors] com uma política nomeada fornece o melhor controle na limitação de pontos de extremidade que dão suporte ao CORS.
Aviso
UseCors deve ser chamado na ordem correta. Para obter mais informações, veja ordem do Middleware. Por exemplo, UseCors
deve ser chamado antes de UseResponseCaching usando UseResponseCaching
.
Cada abordagem é detalhada nas seções a seguir.
CORS com política nomeada e middleware
O Middleware CORS lida com solicitações entre origens. O código a seguir aplica uma política CORS a todos os pontos de extremidade do aplicativo com as origens especificadas:
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();
});
}
}
O código anterior:
- Define o nome da política como
_myAllowSpecificOrigins
. O nome da política é arbitrário. - Chama o UseCors método de extensão e especifica a
_myAllowSpecificOrigins
política CORS.UseCors
adiciona o middleware CORS. A chamada paraUseCors
deve ser colocada apósUseRouting
, mas antes deUseAuthorization
. Para obter mais informações, veja ordem do Middleware. - Chama AddCors com uma expressão lambda. O lambda recebe um objeto CorsPolicyBuilder. As opções de configuração, como
WithOrigins
, são descritas posteriormente neste artigo. - Habilita a política CORS
_myAllowSpecificOrigins
para todos os pontos de extremidade do controlador. Confira Roteamento de ponto de extremidade para aplicar uma política CORS a pontos de extremidade específicos. - Ao usar o Middleware de Cache de Resposta, chame UseCors antes de UseResponseCaching.
Com o roteamento de ponto de extremidade, o middleware CORS deve ser configurado para ser executado entre as chamadas para UseRouting
e UseEndpoints
.
Consulte Testar CORS para obter instruções sobre como testar código semelhante ao código anterior.
A chamada do método AddCors adiciona serviços CORS ao contêiner de serviços do aplicativo:
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();
}
Para obter mais informações, consulte Opções de política CORS neste documento.
Os métodos CorsPolicyBuilder podem ser encadeados, conforme mostrado no código a seguir:
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();
}
Observação: a URL especificada não deve conter uma barra à direita (/
). Se a URL terminar com /
, a comparação retornará false
e nenhum cabeçalho será retornado.
CORS com política padrão e middleware
O código realçado a seguir habilita a política padrão do 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();
});
}
}
O código anterior aplica a política CORS padrão a todos os pontos de extremidade do controlador.
Habilitar Cors com roteamento de ponto de extremidade
Habilitar o CORS por ponto de extremidade usando RequireCors
não oferece suporte a solicitações de simulação automática. Para obter mais informações, confira esta edição do GitHub e Teste o CORS com roteamento de pontos de extremidade e [HttpOptions].
Com o roteamento de ponto de extremidade, o CORS pode ser habilitado por ponto de extremidade usando o RequireCors conjunto de métodos de extensão:
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();
});
}
}
No código anterior:
app.UseCors
adiciona o middleware CORS. Como uma política padrão não foi configurada,app.UseCors()
por si só não habilita o CORS.- Os pontos de extremidade do controlador e
/echo
permitem solicitações entre origens usando a política especificada. - Os pontos de extremidade
/echo2
e Razor páginas não permitem solicitações entre origens porque nenhuma política padrão foi especificada.
O atributo [DisableCors]não desabilita o CORS que foi habilitado pelo roteamento de ponto de extremidade com RequireCors
.
Consulte Testar CORS com roteamento de ponto de extremidade e [HttpOptions] para obter instruções sobre como testar código semelhante ao anterior.
Habilitar CORS com atributos
Habilitar o CORS com o atributo [EnableCors] e aplicar uma política nomeada somente aos pontos de extremidade que exigem CORS fornece o melhor controle.
O atributo [EnableCors] fornece uma alternativa para aplicar o CORS globalmente. O atributo [EnableCors]
habilita o CORS para pontos de extremidade selecionados, em vez de todos os pontos de extremidade:
[EnableCors]
especifica a política padrão.[EnableCors("{Policy String}")]
especifica uma política nomeada.
O atributo [EnableCors]
pode ser aplicado a:
- Razor Página
PageModel
- Controller
- Método de ação do controlador
Políticas diferentes podem ser aplicadas a controladores, modelos de página ou métodos de ação com o atributo [EnableCors]
. Quando o atributo [EnableCors]
é aplicado a um controlador, modelo de página ou método de ação e o CORS está habilitado no middleware, ambas as políticas são aplicadas. É recomendável não combinar políticas. Use o [EnableCors]
atributo ou middleware, não ambos no mesmo aplicativo.
O código a seguir aplica uma política diferente a cada método:
[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(),
};
}
}
O código a seguir cria duas políticas 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();
});
}
}
Para obter o melhor controle de limitação de solicitações CORS:
- Use
[EnableCors("MyPolicy")]
com uma política nomeada. - Não defina uma política padrão.
- Não use o roteamento de ponto de extremidade.
O código na próxima seção atende à lista anterior.
Consulte Testar CORS para obter instruções sobre como testar código semelhante ao código anterior.
Desabilitar CORS
O atributo [DisableCors]não desabilita o CORS que foi habilitado pelo roteamento de ponto de extremidade.
O código a seguir define a política CORS "MyPolicy"
:
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();
});
}
}
O código a seguir desabilita o CORS para a ação GetValues2
:
[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();
}
O código anterior:
- Não habilita o CORS com roteamento de ponto de extremidade.
- Não define uma política de CORS padrão.
- Usa [EnableCors("MyPolicy")] para habilitar a
"MyPolicy"
política CORS para o controlador. - Desabilita o CORS para o método
GetValues2
.
Consulte Testar CORS para obter instruções sobre como testar código semelhante ao código anterior.
Opções de política CORS
Esta seção descreve as várias opções que podem ser definidas em uma política CORS:
- Definir as origens permitidas
- Definir os métodos HTTP permitidos
- Definir os cabeçalhos de solicitação permitidos
- Definir os cabeçalhos de resposta expostos
- Credenciais em solicitações entre origens
- Definir o tempo de expiração do pré-vôo
AddPolicy é chamado em Startup.ConfigureServices
. Para algumas opções, pode ser útil ler primeiro a seção Como funciona o CORS.
Definir as origens permitidas
AllowAnyOrigin: permite solicitações CORS de todas as origens com qualquer esquema (http
ou https
). AllowAnyOrigin
não é seguro porque qualquer site pode fazer solicitações entre origens para o aplicativo.
Observação
A especificação de AllowAnyOrigin
e AllowCredentials
não é uma configuração segura e pode resultar em uma solicitação intersite forjada. O serviço CORS retorna uma resposta CORS inválida quando um aplicativo é configurado com os dois métodos.
AllowAnyOrigin
afeta as solicitações de pré-vôo e o Access-Control-Allow-Origin
cabeçalho. Para obter mais informações, consulte a seção Solicitações de pré-vôo.
SetIsOriginAllowedToAllowWildcardSubdomains: define a IsOriginAllowed propriedade da política como uma função que permite que as origens correspondam a um domínio curinga configurado ao avaliar se a origem é permitida.
options.AddPolicy("MyAllowSubdomainPolicy",
policy =>
{
policy.WithOrigins("https://*.example.com")
.SetIsOriginAllowedToAllowWildcardSubdomains();
});
Definir os métodos HTTP permitidos
- Permite qualquer método HTTP:
- Afeta as solicitações de pré-vôo e o cabeçalho
Access-Control-Allow-Methods
. Para obter mais informações, consulte a seção Solicitações de pré-vôo.
Definir os cabeçalhos de solicitação permitidos
Para permitir que cabeçalhos específicos sejam enviados em uma solicitação CORS, chamado cabeçalhos de solicitação de autor, chame WithHeaders e especifique os cabeçalhos permitidos:
options.AddPolicy("MyAllowHeadersPolicy",
policy =>
{
// requires using Microsoft.Net.Http.Headers;
policy.WithOrigins("http://example.com")
.WithHeaders(HeaderNames.ContentType, "x-custom-header");
});
Para permitir todos os cabeçalhos de solicitação de autor, chame AllowAnyHeader:
options.AddPolicy("MyAllowAllHeadersPolicy",
policy =>
{
policy.WithOrigins("https://*.example.com")
.AllowAnyHeader();
});
AllowAnyHeader
afeta as solicitações de pré-vôo e o cabeçalho Access-Control-Request-Headers. Para obter mais informações, consulte a seção Solicitações de pré-vôo.
Uma correspondência da política do CORS Middleware com cabeçalhos específicos especificados por WithHeaders
só é possível quando os cabeçalhos enviados em Access-Control-Request-Headers
correspondem exatamente aos cabeçalhos declarados em WithHeaders
.
Por exemplo, considere um aplicativo configurado da seguinte maneira:
app.UseCors(policy => policy.WithHeaders(HeaderNames.CacheControl));
O MIDDLEware cors recusa uma solicitação de pré-vôo com o cabeçalho de solicitação a seguir porque Content-Language
(HeaderNames.ContentLanguage) não está listado em WithHeaders
:
Access-Control-Request-Headers: Cache-Control, Content-Language
O aplicativo retorna uma resposta 200 OK, mas não envia os cabeçalhos CORS de volta. Portanto, o navegador não tenta a solicitação entre origens.
Definir os cabeçalhos de resposta expostos
Por padrão, o navegador não expõe todos os cabeçalhos de resposta ao aplicativo. Para obter mais informações, consulte Compartilhamento de recursos entre origens do W3C (Terminologia): cabeçalho de resposta simples.
Os cabeçalhos de resposta disponíveis por padrão são:
Cache-Control
Content-Language
Content-Type
Expires
Last-Modified
Pragma
A especificação CORS chama esses cabeçalhos de cabeçalhos de resposta simples. Para disponibilizar outros cabeçalhos para o aplicativo, chame WithExposedHeaders:
options.AddPolicy("MyExposeResponseHeadersPolicy",
policy =>
{
policy.WithOrigins("https://*.example.com")
.WithExposedHeaders("x-custom-header");
});
Credenciais em solicitações entre origens
As credenciais exigem tratamento especial em uma solicitação CORS. Por padrão, o navegador não envia credenciais com uma solicitação de origem cruzada. As credenciais incluem cookies e esquemas de autenticação HTTP. Para enviar credenciais com uma solicitação entre origens, o cliente deve definir XMLHttpRequest.withCredentials
como true
.
Usando XMLHttpRequest
diretamente:
var xhr = new XMLHttpRequest();
xhr.open('get', 'https://www.example.com/api/test');
xhr.withCredentials = true;
Usando jQuery:
$.ajax({
type: 'get',
url: 'https://www.example.com/api/test',
xhrFields: {
withCredentials: true
}
});
Usando a API Fetch:
fetch('https://www.example.com/api/test', {
credentials: 'include'
});
O servidor deve permitir as credenciais. Para permitir credenciais entre origens, chame AllowCredentials:
options.AddPolicy("MyMyAllowCredentialsPolicy",
policy =>
{
policy.WithOrigins("http://example.com")
.AllowCredentials();
});
A resposta HTTP inclui um Access-Control-Allow-Credentials
cabeçalho, que informa ao navegador que o servidor permite credenciais para uma solicitação entre origens.
Se o navegador enviar credenciais, mas a resposta não incluir um cabeçalho válido Access-Control-Allow-Credentials
, o navegador não exporá a resposta ao aplicativo e a solicitação entre origens falhará.
Permitir credenciais entre origens é um risco de segurança. Um site em outro domínio pode enviar as credenciais de um usuário conectado para o aplicativo em nome do usuário sem o conhecimento do usuário.
A especificação CORS também afirma que definir origens como "*"
(todas as origens) é inválida se o Access-Control-Allow-Credentials
cabeçalho estiver presente.
Solicitações de pré-voo
Para algumas solicitações CORS, o navegador envia uma solicitação OPTIONS adicional antes de fazer a solicitação real. Essa solicitação é chamada de solicitação de pré-voo. O navegador poderá ignorar a solicitação de pré-vôo se todas as seguintes condições forem verdadeiras:
- O método de solicitação é GET, HEAD ou POST.
- O aplicativo não define cabeçalhos de solicitação diferentes de
Accept
,Accept-Language
,Content-Language
,Content-Type
ouLast-Event-ID
. - O cabeçalho
Content-Type
, se definido, tem um dos seguintes valores:application/x-www-form-urlencoded
multipart/form-data
text/plain
A regra nos cabeçalhos de solicitação definida para a solicitação do cliente se aplica aos cabeçalhos que o aplicativo define chamando setRequestHeader
no objeto XMLHttpRequest
. A especificação CORS chama esses cabeçalhos de cabeçalhos de solicitação de autor. A regra não se aplica a cabeçalhos que o navegador pode definir, como User-Agent
, Host
ou Content-Length
.
Veja a seguir um exemplo de resposta semelhante à solicitação de pré-voo feita no botão [Colocar teste] na seção Testar CORS deste documento.
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
A solicitação de pré-vôo usa o método HTTP OPTIONS. Ele pode incluir os seguintes cabeçalhos:
- Access-Control-Request-Method: o método HTTP que será usado para a solicitação real.
- Access-Control-Request-Headers: uma lista de cabeçalhos de solicitação que o aplicativo define na solicitação real. Conforme indicado anteriormente, isso não inclui cabeçalhos que o navegador define, como
User-Agent
. - Access-Control-Allow-Methods
Se a solicitação de pré-voo for negada, o aplicativo retornará uma resposta 200 OK
, mas não definirá os cabeçalhos CORS. Portanto, o navegador não tenta a solicitação entre origens. Para obter um exemplo de uma solicitação de pré-voo negada, consulte a seção Testar CORS deste documento.
Usando as ferramentas F12, o aplicativo de console mostra um erro semelhante a um dos seguintes, dependendo do navegador:
- Firefox: solicitação entre origens bloqueada: a mesma política de origem não permite a leitura do recurso remoto em
https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5
. (Motivo: a solicitação CORS não foi bem-sucedida). Saiba mais - Chromium baseado: o acesso para buscar em 'https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5' da origem 'https://cors3.azurewebsites.net' foi bloqueado pela política cors: a resposta à solicitação de pré-vôo não passa o controle de acesso marcar: nenhum cabeçalho 'Access-Control-Allow-Origin' está presente no recurso solicitado. Se uma resposta opaca atender às suas necessidades, defina o modo da solicitação como 'no-cors' para buscar o recurso com o CORS desabilitado.
Para permitir cabeçalhos específicos, chame WithHeaders:
options.AddPolicy("MyAllowHeadersPolicy",
policy =>
{
// requires using Microsoft.Net.Http.Headers;
policy.WithOrigins("http://example.com")
.WithHeaders(HeaderNames.ContentType, "x-custom-header");
});
Para permitir todos os cabeçalhos de solicitação de autor, chame AllowAnyHeader:
options.AddPolicy("MyAllowAllHeadersPolicy",
policy =>
{
policy.WithOrigins("https://*.example.com")
.AllowAnyHeader();
});
Os navegadores não são consistentes em como eles definem Access-Control-Request-Headers
. Se um dos dois:
- Cabeçalhos são definidos como qualquer outra coisa que não seja
"*"
- AllowAnyHeader é chamado: inclua pelo menos
Accept
,Content-Type
eOrigin
, além de todos os cabeçalhos personalizados que você deseja dar suporte.
Código de solicitação de pré-vôo automático
Quando a política CORS é aplicada:
- Globalmente chamando
app.UseCors
emStartup.Configure
. - Usando o atributo
[EnableCors]
.
ASP.NET Core responde à solicitação OPTIONS de pré-vôo.
Habilitar o CORS por ponto de extremidade usando RequireCors
atualmente não dá suporte a solicitações de pré-voo automáticas.
A seção Testar CORS deste documento demonstra esse comportamento.
Atributo [HttpOptions] para solicitações de pré-voo
Quando o CORS está habilitado com a política apropriada, ASP.NET Core geralmente responde às solicitações de pré-vôo CORS automaticamente. Em alguns cenários, esse pode não ser o caso. Por exemplo, usando CORS com roteamento de ponto de extremidade.
O código a seguir usa o atributo [HttpOptions] para criar pontos de extremidade para solicitações 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);
}
Consulte Testar CORS com roteamento de ponto de extremidade e [HttpOptions] para obter instruções sobre como testar o código anterior.
Definir o tempo de expiração do pré-vôo
O cabeçalho Access-Control-Max-Age
especifica por quanto tempo a resposta à solicitação de pré-voo pode ser armazenada em cache. Para definir esse cabeçalho, chame SetPreflightMaxAge:
options.AddPolicy("MySetPreflightExpirationPolicy",
policy =>
{
policy.WithOrigins("http://example.com")
.SetPreflightMaxAge(TimeSpan.FromSeconds(2520));
});
Como funciona o CORS
Esta seção descreve o que acontece em uma solicitação CORS no nível das mensagens HTTP.
- O CORS não é um recurso de segurança. O CORS é um padrão W3C que permite ao servidor flexibilizar a política de same-origin.
- Por exemplo, um ator mal-intencionado pode usar o XSS (Script entre Sites) em seu site e executar uma solicitação entre sites no site habilitado para CORS para roubar informações.
- Uma API não é mais segura permitindo o CORS.
- Cabe ao cliente (navegador) impor o CORS. O servidor executa a solicitação e retorna a resposta, é o cliente que retorna um erro e bloqueia a resposta. Por exemplo, qualquer uma das seguintes ferramentas exibirá a resposta do servidor:
- Fiddler
- .NET HttpClient
- Um navegador da Web inserindo a URL na barra de endereços.
- Cabe ao cliente (navegador) impor o CORS. O servidor executa a solicitação e retorna a resposta, é o cliente que retorna um erro e bloqueia a resposta. Por exemplo, qualquer uma das seguintes ferramentas exibirá a resposta do servidor:
- É uma maneira de um servidor permitir que os navegadores executem uma solicitação de API XHR ou Fetch de origem cruzada que, de outra forma, seria proibida.
- Navegadores sem CORS não podem fazer solicitações entre origens. Antes do CORS, JSONP era usado para contornar essa restrição. O JSONP não usa XHR, ele usa a marca
<script>
para receber a resposta. Os scripts têm permissão para serem carregados entre origens.
- Navegadores sem CORS não podem fazer solicitações entre origens. Antes do CORS, JSONP era usado para contornar essa restrição. O JSONP não usa XHR, ele usa a marca
A especificação CORS introduziu vários novos cabeçalhos HTTP que habilitam solicitações entre origens. Se um navegador der suporte ao CORS, ele definirá esses cabeçalhos automaticamente para solicitações entre origens. O código JavaScript personalizado não é necessário para habilitar o CORS.
Veja a seguir um exemplo de uma solicitação entre origens do botão de teste Valores para https://cors1.azurewebsites.net/api/values
. O cabeçalho Origin
:
- Fornece o domínio do site que está fazendo a solicitação.
- É necessário e deve ser diferente do host.
Cabeçalhos gerais
Request URL: https://cors1.azurewebsites.net/api/values
Request Method: GET
Status Code: 200 OK
Cabeçalhos de resposta
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
Cabeçalhos de solicitação
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 ...
Em solicitações OPTIONS
, o servidor define o cabeçalho Cabeçalhos de resposta Access-Control-Allow-Origin: {allowed origin}
na resposta. Por exemplo, o exemplo implantado, a solicitação de botão Excluir [EnableCors]OPTIONS
contém os seguintes cabeçalhos:
Cabeçalhos gerais
Request URL: https://cors3.azurewebsites.net/api/TodoItems2/MyDelete2/5
Request Method: OPTIONS
Status Code: 204 No Content
Cabeçalhos de resposta
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
Cabeçalhos de solicitação
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
Nos cabeçalhos de resposta anteriores, o servidor define o cabeçalho Access-Control-Allow-Origin na resposta. O valor https://cors1.azurewebsites.net
desse cabeçalho corresponde ao cabeçalho Origin
da solicitação.
Se AllowAnyOrigin for chamado, o Access-Control-Allow-Origin: *
, o valor curinga, será retornado. AllowAnyOrigin
permite qualquer origem.
Se a resposta não incluir o cabeçalho Access-Control-Allow-Origin
, a solicitação entre origens falhará. Especificamente, o navegador não permite a solicitação. Mesmo que o servidor retorne uma resposta bem-sucedida, o navegador não disponibiliza a resposta para o aplicativo cliente.
Exibir solicitações OPTIONS
Por padrão, os navegadores Chrome e Edge não mostram solicitações OPTIONS na guia de rede das ferramentas F12. Para exibir solicitações OPTIONS nestes navegadores:
chrome://flags/#out-of-blink-cors
ouedge://flags/#out-of-blink-cors
- desabilite o sinalizador.
- reiniciar.
O Firefox mostra as solicitações OPTIONS por padrão.
CORS no IIS
Ao implantar no IIS, o CORS precisará ser executado antes da Autenticação do Windows se o servidor não estiver configurado para permitir o acesso anônimo. Para dar suporte a esse cenário, o módulo CORS do IIS precisa ser instalado e configurado para o aplicativo.
Testar o CORS
O download de exemplo tem código para testar o CORS. Consulte como baixar. O exemplo é um projeto de API com Razor Pages (Páginas) adicionado:
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();
});
}
}
Aviso
WithOrigins("https://localhost:<port>");
só deve ser usado para testar um aplicativo de exemplo semelhante ao código de exemplo de download.
O seguinte ValuesController
fornece os pontos de extremidade para teste:
[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 é fornecido pelo pacote NuGet Rick.Docs.Samples.RouteInfo e exibe as informações de rota.
Teste o código de exemplo anterior usando uma das seguintes abordagens:
- Execute o exemplo com
dotnet run
usando a URL padrão dehttps://localhost:5001
. - Execute o exemplo do Visual Studio com a porta definida como 44398 para uma URL de
https://localhost:44398
.
Usando um navegador com as ferramentas F12:
Selecione o botão Valores e examine os cabeçalhos na guia Rede.
Selecione o botão de teste PUT. Consulte Exibir solicitações OPTIONS para obter instruções sobre como exibir a solicitação OPTIONS. O teste PUT cria duas solicitações, uma solicitação de pré-vôo OPTIONS e a solicitação PUT.
Selecione o botão
GetValues2 [DisableCors]
para disparar uma solicitação CORS com falha. Conforme mencionado no documento, a resposta retorna 200 êxitos, mas a solicitação CORS não é feita. Selecione a guia Console para ver o erro CORS. Dependendo do navegador, um erro semelhante ao seguinte é exibido:O acesso para buscar na
'https://cors1.azurewebsites.net/api/values/GetValues2'
origem'https://cors3.azurewebsites.net'
foi bloqueado pela política do CORS: nenhum cabeçalho 'Access-Control-Allow-Origin' está presente no recurso solicitado. Se uma resposta opaca atender às suas necessidades, defina o modo da solicitação como 'no-cors' para buscar o recurso com o CORS desabilitado.
Os pontos de extremidade habilitados para CORS podem ser testados com uma ferramenta, como curl ou Fiddler. Ao usar uma ferramenta, a origem da solicitação especificada pelo cabeçalho Origin
deve ser diferente do host que recebe a solicitação. Se a solicitação não for entre origens com base no valor do cabeçalho Origin
:
- Não é necessário que o Middleware CORS processe a solicitação.
- Os cabeçalhos CORS não são retornados na resposta.
O comando a seguir usa curl
para emitir uma solicitação OPTIONS com informações:
curl -X OPTIONS https://cors3.azurewebsites.net/api/TodoItems2/5 -i
Testar o CORS com o roteamento de ponto de extremidade e [HttpOptions]
Habilitar o CORS por ponto de extremidade usando RequireCors
atualmente não dá suporte a solicitações de pré-voo automáticas. Considere o seguinte código que usa o roteamento de ponto de extremidade para habilitar o 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();
});
}
}
O seguinte TodoItems1Controller
fornece pontos de extremidade para teste:
[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);
}
Teste o código anterior na página de teste (https://cors1.azurewebsites.net/test?number=1
) da amostra implantada.
Os botões Excluir [EnableCors] e GET [EnableCors] têm êxito, pois os pontos de extremidade têm [EnableCors]
e respondem a solicitações de simulação. Os outros pontos de extremidade falham. O botão GET falha porque o JavaScript envia:
headers: {
"Content-Type": "x-custom-header"
},
O seguinte TodoItems2Controller
fornece pontos de extremidade semelhantes, mas inclui código explícito para responder a solicitações 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);
}
O código anterior pode ser testado implantando o exemplo no Azure. Na lista suspensa Controlador, selecione Simulação e, em seguida, Definir Controlador. Todas as chamadas CORS para os pontos de extremidade TodoItems2Controller
são bem-sucedidas.