This article describes how to enable CORS in ASP.NET Core applications.
Browser security prevents web pages from sending requests to other domains rather than serving them. This restriction is known as the same origin policy. The same source policy prevents malicious sites from reading sensitive data from another site. Sometimes, you may want to allow other sites to make cross domain requests for your app. For more information, see MOZILLA CORS.
Cross source resource sharing(CORS):
- Is a W3C standard that allows servers to relax the same source policy.
- It is not a security function. CORS relaxes security. The API cannot be more secure by allowing CORS. For more information, see CORS work Principle.
- Allow the server to explicitly allow some cross source requests while rejecting others.
- Than earlier technologies (e.g. JSONP )Safer and more flexible.
View or download sample code(How to download)
Same origin
If two URLs have the same scheme, host and port( RFC 6454 ), they have the same source.
The two URLs have the same source:
- https://example.com/foo.html
- https://example.com/bar.html
The origins of these URLs are different from the first two:
- https://example.net – different domains
- https://www.example.com/foo.html – different subdomains
- http://example.com/foo.html – different scenarios
- https://example.com:9000/foo.html – different ports
Internet Explorer does not consider this port when comparing sources.
CORS with naming strategy and Middleware
CORS middleware handles cross domain requests. The following code enables CORS for the entire application by specifying the source:
public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins"; public IConfiguration Configuration { get; } public void ConfigureServices(IServiceCollection services) { services.AddCors(options => { options.AddPolicy(MyAllowSpecificOrigins, builder => { builder.WithOrigins("http://example.com", "http://www.contoso.com"); }); }); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); } public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseHsts(); } app.UseCors(MyAllowSpecificOrigins); app.UseHttpsRedirection(); app.UseMvc(); } }
Previous code:
- Set the policy name to "myAllowSpecificOrigins". The policy name is any name.
- Call UseCors Extension method, which enables CORS.
- Use lambda expression Call AddCors . Lambda takes the @ no \t 0 object. Later in this article configuration option , such as WithOrigins.
@The NO-0 method call adds the CORS service to the application's service container:
public void ConfigureServices(IServiceCollection services) { services.AddCors(options => { options.AddPolicy(MyAllowSpecificOrigins, builder => { builder.WithOrigins("http://example.com", "http://www.contoso.com"); }); }); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); }
For more information, refer to the CORS policy options.
@The NO-0 method can link methods, as shown in the following code:
public void ConfigureServices(IServiceCollection services) { services.AddCors(options => { options.AddPolicy(MyAllowSpecificOrigins, builder => { builder.WithOrigins("http://example.com", "http://www.contoso.com") .AllowAnyHeader() .AllowAnyMethod(); }); }); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); }
Note: URLs must not contain trailing slashes (/). If the URL terminates with /, the comparison returns false with no headers.
Apply CORS policy to all endpoints
The following code applies the CORS policy to all application endpoints through the CORS middleware:
public void Configure(IApplicationBuilder app, IHostingEnvironment env) { // Preceding code ommitted. app.UseRouting(); app.UseCors(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); // Following code ommited. }
Warning
Through endpoint routing, the CORS middleware must be configured to execute between calls to @ no \\\\\\\\\. Incorrect configuration will cause the middleware to stop running normally.
see also Enable cors in Razor Pages, controllers, and methods of operation, To apply the cors policy at the page / controller / operation level.
For instructions on testing the above codes, see Test CORS .
Enabling Cors with endpoint routing
With endpoint routing, you can enable CORS based on each endpoint and use the extended method set of @ no \t.
app.UseEndpoints(endpoints => { endpoints.MapGet("/echo", async context => context.Response.WriteAsync("echo")) .RequireCors("policy-name"); });
Similarly, CORS can be enabled for all controllers:
app.UseEndpoints(endpoints => { endpoints.MapControllers().RequireCors("policy-name"); });
Enable CORS with properties
@No__t-1EnableCors @ no__t Property provides an alternative method for global application of CORS. The @ NO-0 attribute enables CORS for the selected endpoint, not all endpoints.
Use @ no \t to specify the default policy, and [EnableCors("{Policy String}")] to specify the policy.
@The NO-0 feature can be applied to:
- Razor page PageModel
- Controller
- Operation method of controller
You can apply different policies to the controller / page model / operation, [EnableCors] property. When [EnableCors] attribute is applied to controller / page model / operation method and CORS is enabled in middleware, these two strategies will be applied. It is recommended not to combine strategies. Use the [EnableCors] feature or middleware in the same application.
The following code applies different policies to each method:
[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] // Default policy. [HttpGet("{id}")] public ActionResult<string> Get(int id) { switch (id) { case 1: return "green widget"; case 2: return "red widget"; default: return NotFound(); } } }
The following code is created CORS The default policy and name are "AnotherPolicy" Strategy:
public class StartupMultiPolicy { public StartupMultiPolicy(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } public void ConfigureServices(IServiceCollection services) { services.AddCors(options => { options.AddDefaultPolicy( builder => { builder.WithOrigins("http://example.com", "http://www.contoso.com"); }); options.AddPolicy("AnotherPolicy", builder => { builder.WithOrigins("http://www.contoso.com") .AllowAnyHeader() .AllowAnyMethod(); }); }); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); } public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseHsts(); } app.UseHttpsRedirection(); app.UseMvc(); } }
Disable CORS
@No__t-1DisableCors @ no__t-2 Property to disable CORS for controller / page model / operation.
CORS policy options
This section describes the various options that can be set in the CORS policy:
- Set allowed sources
- Set allowed HTTP methods
- Set allowed request headers
- Set the exposed response header
- Credentials in a cross domain request
- Set pre inspection expiration time
Call in Startup.ConfigureServices AddPolicy . For some options, it's best to read first How CORS works Part.
Set allowed sources
AllowAnyOrigin - allow CORS requests from all sources and any scenarios (http or https). AllowAnyOrigin is not secure because any web site can make cross domain requests to applications.
Remarks
Specifying @ No UU T 0 and @ No UU t0 as insecure configurations may result in cross site request forgery. When using these two methods to configure an application, the CORS service will return an invalid CORS response.
AllowAnyOrigin affects the prefetch request and the @ No UU t header. For more information, see Preview request Part.
SetIsOriginAllowedToAllowWildcardSubdomains - set @ no \t of the policy to a function that allows the source to match the configured wildcard field when evaluating whether to allow the source.
options.AddPolicy("AllowSubdomain", builder => { builder.WithOrigins("https://*.example.com") .SetIsOriginAllowedToAllowWildcardSubdomains(); });
Set allowed HTTP methods
- Allow any HTTP method:
- Affects the prefetch request and the @ no buut 0 header. For more information, see Preview request Part.
Set allowed request headers
To allow a specific header (called the author request header) to be sent in a CORS request, call WithHeaders And specify the allowed headers:
options.AddPolicy("AllowHeaders", builder => { builder.WithOrigins("http://example.com") .WithHeaders(HeaderNames.ContentType, "x-custom-header"); });
To allow all authors to request headers, call AllowAnyHeader:
options.AddPolicy("AllowAllHeaders", builder => { builder.WithOrigins("http://example.com") .AllowAnyHeader(); });
This setting affects the prefetch request and the @ no buut 0 header. For more information, see Preview request Part.
The CORS middleware policy can only be used to match the specific headers specified by WithHeaders if the headers sent in access control request headers exactly match the headers specified in WithHeaders.
For example, consider an application configured as follows:
CORS middleware uses the following request header to reject the pre check request because content language is not listed in WithHeaders( HeaderNames):
Access-Control-Request-Headers: Cache-Control, Content-Language
The app returns a 200 OK response, but does not send the CORS header back. As a result, the browser will not attempt cross domain requests.
Set the exposed response header
By default, the browser does not expose all the response headers to the application. For more information, see W3C cross domain resource sharing (terminology): simple response headers.
The response headers available by default are:
- Cache-Control
- Content-Language
- Content-Type
- Expires
- Last-Modified
- Pragma
The CORS specification calls these headers simple response headers. To make other headers available to the application, call WithExposedHeaders:
options.AddPolicy("ExposeResponseHeaders", builder => { builder.WithOrigins("http://example.com") .WithExposedHeaders("x-custom-header"); });
Credentials in a cross domain request
Credentials need to be specially processed in the CORS request. By default, browsers do not use cross domain requests to send credentials. Credentials include cookie s and HTTP authentication schemes. To send credentials using a cross domain request, the client must set XMLHttpRequest.withCredentials to true.
Directly use @ no \t:
var xhr = new XMLHttpRequest(); xhr.open('get', 'https://www.example.com/api/test'); xhr.withCredentials = true;
Using jQuery:
$.ajax({ type: 'get', url: 'https://www.example.com/api/test', xhrFields: { withCredentials: true } });
Use Extract API:
fetch('https://www.example.com/api/test', { credentials: 'include' });
The server must allow credentials. To allow cross domain credentials, call AllowCredentials:
options.AddPolicy("AllowCredentials", builder => { builder.WithOrigins("http://example.com") .AllowCredentials(); });
The HTTP response contains a @ no \t 0 header that informs the browser server to allow credentials for cross source requests.
If the browser sends credentials, but the response does no t contain a valid @ no \t 0 header, the browser does not expose the response to the application and the cross source request fails.
Allowing cross domain credentials poses a security risk. A web site in another domain can send the credentials of the logged in user to the application on behalf of the user without the knowledge of the user.
The CORS specification also states that it is no t valid to set the source to "*" (all sources) if the @ No UU t header exists.
Preview request
For some CORS requests, the browser will send other requests before the actual request. This request is called a pre inspection request. The browser can skip the pre check request if:
- The request method is GET, HEAD, or POST.
- The request header with 'Accept, Accept language, content language, content type' or @ no \.
-
@The header for no, if set, has one of the following values:
- application/x-www-form-urlencoded
- multipart/form-data
- text/plain
The rules on the request header set for client requests apply by calling the header on the @ No UUT @ No UUT object. The CORS specification calls these header authors to request headers. The rule does not apply to headers that the browser can set, such as user agent, Host, or content length.
The following is an example of a pre check request:
OPTIONS https://myservice.azurewebsites.net/api/test HTTP/1.1 Accept: */* Origin: https://myclient.azurewebsites.net Access-Control-Request-Method: PUT Access-Control-Request-Headers: accept, x-my-custom-header Accept-Encoding: gzip, deflate User-Agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0) Host: myservice.azurewebsites.net Content-Length: 0
The pre flight request uses the HTTP OPTIONS method. It includes two special headers:
- Access control request method: the HTTP method that will be used for the actual request.
- Access control request headers: list of request headers applied to the actual request. As mentioned earlier, this does not include headers for browser settings, such as user agent.
The CORS prefetch request may include a @ no \\\\\\\\\.
To allow specific headers, call WithHeaders:
options.AddPolicy("AllowHeaders", builder => { builder.WithOrigins("http://example.com") .WithHeaders(HeaderNames.ContentType, "x-custom-header"); });
To allow all authors to request headers, call AllowAnyHeader:
options.AddPolicy("AllowAllHeaders", builder => { builder.WithOrigins("http://example.com") .AllowAnyHeader(); });
Browser settings are not exactly the same access control request headers. If the header is set to @ no \ AllowAnyHeader )Any content other than, should contain at least Accept, content type, and @ no \t, as well as any custom headers to support.
Here is a sample response to a pre check request (assuming the server allows it):
HTTP/1.1 200 OK Cache-Control: no-cache Pragma: no-cache Content-Length: 0 Access-Control-Allow-Origin: https://myclient.azurewebsites.net Access-Control-Allow-Headers: x-my-custom-header Access-Control-Allow-Methods: PUT Date: Wed, 20 May 2015 06:33:22 GMT
The response includes a @ No UU T 0 header that lists the allowed methods and optionally a @ No UU t0 header that lists the allowed headers. If the pre check request is successful, the browser sends the actual request.
If the pre check request is rejected, the application will return a 200 OK response, but the CORS header will not be sent back. As a result, the browser will not attempt cross domain requests.
Set pre inspection expiration time
@The no header specifies the length of time that a response to a pre check request can be cached. To set this header, call SetPreflightMaxAge:
options.AddPolicy("SetPreflightExpiration", builder => { builder.WithOrigins("http://example.com") .SetPreflightMaxAge(TimeSpan.FromSeconds(2520)); });
How CORS works
This section describes the HTTP message level CORS What happens in the request.
-
CORS is not a security function. CORS is a W3C standard that allows servers to relax the same source policy.
- For example, a malicious execution component might use Block cross site scripting (XSS) And perform cross site requests to CORS enabled sites to steal information.
-
The API cannot be more secure by allowing CORS.
-
It is enforced by the client (browser). The server executes the request and returns the response, which is the client that returns the error and blocks the response. For example, any of the following tools will display the server response:
- Fiddler
- Postman
- .NET HttpClient
- Web browser by entering the URL in the address bar.
-
It is enforced by the client (browser). The server executes the request and returns the response, which is the client that returns the error and blocks the response. For example, any of the following tools will display the server response:
-
This is a method that enables the server to allow browsers to perform cross source XHR or Get API Request, otherwise it will be forbidden.
- The browser (without CORS) cannot perform cross domain requests. Before CORS, use JSONP To bypass this restriction. JSONP does not use XHR, it uses < script > tags to receive responses. Allow scripts to be loaded across sources.
CORS specification Introduces several new HTTP headers that enable cross domain requests. If the browser supports CORS, these headers are automatically set for cross domain requests. To enable CORS, you do not need to customize JavaScript code.
Here is an example of a cross source request. The @ no? 0 header provides the domain of the requested site. The header of @ no \t is required and must be different from the host.
GET https://myservice.azurewebsites.net/api/test HTTP/1.1 Referer: https://myclient.azurewebsites.net/ Accept: */* Accept-Language: en-US Origin: https://myclient.azurewebsites.net Accept-Encoding: gzip, deflate User-Agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0) Host: myservice.azurewebsites.net
If the server allows the request, the header of @ no \t is set in the response. The value of this header can match the @ No UU T 0 header in the request, or it can be a wildcard value "*", indicating that any source is allowed:
HTTP/1.1 200 OK Cache-Control: no-cache Pragma: no-cache Content-Type: text/plain; charset=utf-8 Access-Control-Allow-Origin: https://myclient.azurewebsites.net Date: Wed, 20 May 2015 06:27:30 GMT Content-Length: 12 Test message
Cross domain requests fail if the response does no t include a header for @ no \. Specifically, the browser does not allow the request. Even if the server returns a successful response, the browser will not provide the response to the client application.
Test CORS
Test CORS:
- Create API project . Or, you can Download the sample.
- Use one of the methods in this document to enable CORS. For example:
public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseHsts(); } // Shows UseCors with CorsPolicyBuilder. app.UseCors(builder => { builder.WithOrigins("http://example.com", "http://www.contoso.com", "https://localhost:44375", "https://localhost:5001"); }); app.UseHttpsRedirection(); app.UseMvc(); }
warning
WithOrigins("https://Localhost: < port > ");; should only be used for testing similar to Download sample code Example application of.
- Establish web Application project( Razor Pages or MVC). This example uses Razor Pages. Can be in conjunction with API Created in the same solution for the project web Application.
- Add the following highlighted code to the index cshtml In the document:
@page @model IndexModel @{ ViewData["Title"] = "Home page"; } <div class="text-center"> <h1 class="display-4">CORS Test</h1> </div> <div> <input type="button" value="Test" onclick="requestVal('https://<web app>.azurewebsites.net/api/values')" /> <span id='result'></span> </div> <script> function requestVal(uri) { const resultSpan = document.getElementById('result'); fetch(uri) .then(response => response.json()) .then(data => resultSpan.innerText = data) .catch(error => resultSpan.innerText = 'See F12 Console for error'); } </script>