Delen via


CORS (Cross-Origin Requests) inschakelen in ASP.NET Core

Opmerking

Dit is niet de nieuwste versie van dit artikel. Zie de .NET 9-versie van dit artikel voor de huidige release.

Waarschuwing

Deze versie van ASP.NET Core wordt niet meer ondersteund. Zie het .NET- en .NET Core-ondersteuningsbeleid voor meer informatie. Zie de .NET 9-versie van dit artikel voor de huidige release.

Belangrijk

Deze informatie heeft betrekking op een pre-releaseproduct dat aanzienlijk kan worden gewijzigd voordat het commercieel wordt uitgebracht. Microsoft geeft geen garanties, uitdrukkelijk of impliciet, met betrekking tot de informatie die hier wordt verstrekt.

Zie de .NET 9-versie van dit artikel voor de huidige release.

Door Rick Anderson en Kirk Larkin

In dit artikel wordt laten zien hoe Cross-Origin Resource Sharing (CORS) is ingeschakeld in een ASP.NET Core-app.

Browserbeveiliging voorkomt dat een webpagina aanvragen indient naar een ander domein dan het domein dat de webpagina heeft geleverd. Deze beperking wordt het same-origin policy genoemd. Hetzelfde origin-beleid voorkomt dat een kwaadwillende site gevoelige gegevens van een andere site leest. Soms wilt u toestaan dat andere sites cross-origin-aanvragen indienen bij uw app. Zie het Mozilla CORS-artikel voor meer informatie.

Cross Origin Resource Sharing (CORS):

  • Is een W3C-standaard waarmee een server hetzelfde origin-beleid kan versoepelen.
  • Is geen beveiligingsfunctie, CORS maakt de beveiliging soepeler. Een API is niet veiliger door CORS toe te staan. Zie Hoe CORS werkt voor meer informatie.
  • Hiermee staat u een server toe om bepaalde cross-origin-aanvragen expliciet toe te staan terwijl andere aanvragen worden geweigerd.
  • Is veiliger en flexibeler dan eerdere technieken, zoals JSONP.

Voorbeeldcode bekijken of downloaden (hoe download je)

Dezelfde oorsprong

Twee URL's hebben dezelfde oorsprong als ze identieke schema's, hosts en poorten (RFC 6454) hebben.

Deze twee URL's hebben dezelfde oorsprong:

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

Deze URL's hebben verschillende oorsprongen dan de vorige twee URL's:

  • https://example.net: Ander domein
  • https://contoso.example.com/foo.html: Ander subdomein
  • http://example.com/foo.html: Verschillend schema
  • https://example.com:9000/foo.html: Andere poort

CORS inschakelen

Er zijn drie manieren om CORS in te schakelen:

Het gebruik van het kenmerk [EnableCors] met een benoemd beleid biedt het beste beheer voor het beperken van eindpunten die CORS ondersteunen.

Waarschuwing

UseCors moet in de juiste volgorde worden aangeroepen. Zie Middleware-bestelling voor meer informatie. Moet bijvoorbeeld UseCors worden aangeroepen voordat UseResponseCaching wanneer UseResponseCaching wordt gebruikt.

Elke benadering wordt in de volgende secties beschreven.

CORS met benoemd beleid en middleware

CORS Middleware verwerkt cross-origin-aanvragen. Met de volgende code wordt een CORS-beleid toegepast op alle eindpunten van de app met de opgegeven oorsprongen:

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

De voorgaande code:

Met eindpuntroutering moet de CORS-middleware worden geconfigureerd voor uitvoering tussen de aanroepen naar UseRouting en UseEndpoints.

Met de AddCors methodeoproep worden CORS-services toegevoegd aan de servicecontainer van de app:

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

Zie CORS-beleidsopties in dit document voor meer informatie.

De CorsPolicyBuilder methoden kunnen worden gekoppeld, zoals wordt weergegeven in de volgende code:

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

Opmerking: de opgegeven URL mag geen afsluitende slash (/) bevatten. Als de URL eindigt met /, levert de vergelijking false op en wordt er geen header geretourneerd.

Volgorde van UseCors en UseStaticFiles

UseStaticFiles Normaal gesproken wordt het eerder UseCorsaangeroepen. Apps die JavaScript gebruiken om statische bestanden cross-site op te halen, moeten UseCors aanroepen voordat ze UseStaticFiles.

CORS met standaardbeleid en middleware

Met de volgende gemarkeerde code wordt het standaard CORS-beleid ingeschakeld:

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

Met de voorgaande code wordt het standaard CORS-beleid toegepast op alle controllereindpunten.

Cors met eindpuntroutering inschakelen

Met eindpuntroutering kan CORS per eindpunt worden ingeschakeld met behulp van de RequireCors set extensiemethoden:

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

In de voorgaande code:

  • app.UseCors schakelt de CORS-middleware in. Omdat er geen standaardbeleid is geconfigureerd, maakt app.UseCors() alleen CORS niet mogelijk.
  • De /echo- en controle-eindpunten staan cross-origin-aanvragen toe met behulp van het opgegeven beleid.
  • De /echo2 en Razor Pagina-eindpunten staan geen cross-origin-aanvragen toe omdat er geen standaardbeleid is opgegeven.

Het kenmerk [DisableCors] schakelt niet de CORS uit die is ingeschakeld door eindpuntroutering met RequireCors.

Zie CORS testen met het kenmerk [EnableCors] en de RequireCors-methode voor instructies over het testen van code die vergelijkbaar is met de voorgaande.

CORS met kenmerken inschakelen

Het inschakelen van CORS met het kenmerk [EnableCors] en het toepassen van een benoemd beleid op alleen die eindpunten waarvoor CORS is vereist, biedt het beste beheer.

Het kenmerk [EnableCors] biedt een alternatief voor het wereldwijd toepassen van CORS. Met [EnableCors] het kenmerk wordt CORS ingeschakeld voor geselecteerde eindpunten, in plaats van alle eindpunten:

  • [EnableCors] hiermee geeft u het standaardbeleid.
  • [EnableCors("{Policy String}")] specificeert een benoemd beleid.

Het [EnableCors] kenmerk kan worden toegepast op:

  • Razor Bladzijde PageModel
  • Controleur
  • Controller-actiemethode

Verschillende beleidsregels kunnen worden toegepast op controllers, paginamodellen of actiemethoden met het [EnableCors] kenmerk. Wanneer het [EnableCors] kenmerk wordt toegepast op een controller, paginamodel of actiemethode en CORS is ingeschakeld in middleware, worden beide beleidsregels toegepast. Wij raden aan om beleidsregels niet te combineren. Gebruik de [EnableCors] kenmerk of middleware, niet beide in dezelfde app.

Met de volgende code wordt een ander beleid toegepast op elke methode:

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

Met de volgende code worden twee CORS-beleidsregels gemaakt:

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

Voor de beste controle over het beperken van CORS-aanvragen:

  • Gebruik [EnableCors("MyPolicy")] met een genaamd beleid.
  • Definieer geen standaardbeleid.
  • Gebruik geen eindpuntroutering.

De code in de volgende sectie voldoet aan de voorgaande lijst.

CORS uitschakelen

Het kenmerk [DisableCors] schakelt CORS die is ingeschakeld door eindpuntrouteringniet uit.

De volgende code definieert het CORS-beleid "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();

Met de volgende code wordt CORS uitgeschakeld voor de GetValues2 actie:

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

}

De voorgaande code:

Zie CORS testen voor instructies over het testen van de voorgaande code.

CORS-beleidsopties

In deze sectie worden de verschillende opties beschreven die kunnen worden ingesteld in een CORS-beleid:

AddPolicy wordt ingeroepen in Program.cs. Voor sommige opties kan het nuttig zijn om eerst de sectie Hoe CORS werkt te lezen.

De toegestane oorsprongen instellen

AllowAnyOrigin: Hiermee staat u CORS-aanvragen van alle oorsprongen toe met elk schema (http of https). AllowAnyOrigin is onveilig omdat elke website cross-origin aanvragen kan indienen bij de app.

Opmerking

Het opgeven van AllowAnyOrigin en AllowCredentials is een onveilige configuratie en leidt tot cross-site request-vervalsing. De CORS-service retourneert een ongeldig CORS-antwoord wanneer een app is geconfigureerd met beide methoden.

AllowAnyOrigin beïnvloedt preflight-aanvragen en de Access-Control-Allow-Origin-koptekst. Zie de sectie Voorbereidende aanvragen voor meer informatie.

SetIsOriginAllowedToAllowWildcardSubdomains: Hiermee stelt u de IsOriginAllowed eigenschap van het beleid in als een functie waarmee origins overeenkomen met een geconfigureerd wildcarddomein bij het evalueren of de oorsprong is toegestaan.

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

De toegestane HTTP-methoden instellen

AllowAnyMethod:

  • Hiermee staat u elke HTTP-methode toe:
  • Beïnvloedt voorbereidende aanvragen en de Access-Control-Allow-Methods-header. Zie de sectie Voorbereidende aanvragen voor meer informatie.

De toegestane aanvraagheaders instellen

Als u wilt toestaan dat specifieke headers worden verzonden in een CORS-aanvraag, genaamd headers van auteursaanvragen, roept WithHeaders u de toegestane headers aan en geeft u de toegestane headers op:

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

Als u alle verzoekheaders van de auteur wilt toestaan, roept u AllowAnyHeader aan.

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 beïnvloedt preflight-aanvragen en de Access-Control-Request-Headers-header. Zie de sectie Voorbereidende aanvragen voor meer informatie.

Een CORS Middleware-beleid matcht met specifieke headers gespecificeerd door WithHeaders alleen wanneer de headers in Access-Control-Request-Headers exact overeenkomen met de headers die zijn gespecificeerd in WithHeaders.

Denk bijvoorbeeld aan een app die als volgt is geconfigureerd:

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

CORS Middleware weigert een voorafgaande aanvraag met de volgende aanvraagheader omdat Content-Language (HeaderNames.ContentLanguage) niet wordt vermeld in WithHeaders:

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

De app retourneert een 200 OK-antwoord , maar stuurt de CORS-headers niet terug. Daarom probeert de browser de cross-origin-aanvraag niet uit te voeren.

De weergegeven antwoordheaders instellen

Standaard worden in de browser niet alle antwoordheaders voor de app weergegeven. Zie W3C Cross-Origin Resource Sharing (Terminologie): Simple Response Header voor meer informatie.

De antwoordheaders die standaard beschikbaar zijn, zijn:

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

De CORS-specificatie roept deze headers eenvoudige antwoordheaders aan. Als u andere headers beschikbaar wilt maken voor de app, roept u het volgende WithExposedHeadersaan:

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

Inloggegevens in cross-origin-aanvragen

Referenties vereisen speciale verwerking in een CORS-aanvraag. Standaard verzendt de browser geen inloggegevens met een cross-origin-aanvraag. Inloggegevens omvatten cookies en HTTP-authenticatieschema's. Om referenties met een cross-origin verzoek mee te sturen, moet de client XMLHttpRequest.withCredentials instellen op true.

Gebruik rechtstreeks XMLHttpRequest:

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

JQuery gebruiken:

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

De Fetch-API gebruiken:

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

De server moet de inloggegevens toestaan. Als u referenties voor meerdere oorsprongen wilt toestaan, roept u AllowCredentials op.

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

Het HTTP-antwoord bevat een Access-Control-Allow-Credentials header, waarmee de browser aangeeft dat de server referenties toestaat voor een cross-origin-aanvraag.

Als de browser referenties verzendt, maar het antwoord geen geldige Access-Control-Allow-Credentials header bevat, geeft de browser het antwoord niet beschikbaar aan de app en mislukt de cross-origin-aanvraag.

Het toestaan van cross-origin credentials is een beveiligingsrisico. Een website in een ander domein kan de referenties van een aangemelde gebruiker namens de gebruiker verzenden naar de app zonder dat de gebruiker dit weet.

De CORS-specificatie geeft ook aan dat het instellen van origins op "*" (alle origins) ongeldig is als de Access-Control-Allow-Credentials header aanwezig is.

Preflight-verzoeken

Voor sommige CORS-aanvragen verzendt de browser een extra OPTIONS-aanvraag voordat de werkelijke aanvraag wordt ingediend. Deze aanvraag wordt een voorbereidende aanvraag genoemd. De browser kan de voorbereidende aanvraag overslaan als aan alle volgende voorwaarden wordt voldaan:

  • De aanvraagmethode is GET, HEAD of POST.
  • De app stelt geen andere aanvraagheaders in dan Accept, Accept-Language, Content-Language, Content-Typeof Last-Event-ID.
  • De Content-Type header, indien ingesteld, heeft een van de volgende waarden:
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

De regel voor aanvraagheaders die zijn ingesteld voor de clientaanvraag is van toepassing op headers die door de app worden ingesteld door setRequestHeader aan te roepen op het XMLHttpRequest-object. De CORS-specificatie noemt deze headers auteursaanvraagheaders. De regel is niet van toepassing op headers die de browser kan instellen, zoals User-Agent, Hostof Content-Length.

Opmerking

Dit artikel bevat URL's die zijn gemaakt door de voorbeeldcode te implementeren op twee Azure-websites en https://cors3.azurewebsites.nethttps://cors.azurewebsites.net.

Hier volgt een voorbeeld van een antwoord dat lijkt op het preflight-verzoek dat is gedaan via de knop [Put test] in de Test CORS sectie van dit document.

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

Het preflight-verzoek gebruikt de HTTP OPTIONS methode. Het kan de volgende headers bevatten:

Als de voorbereidende aanvraag wordt geweigerd, retourneert de app een 200 OK antwoord, maar de CORS-headers worden niet ingesteld. Daarom probeert de browser de cross-origin-aanvraag niet uit te voeren. Voor een voorbeeld van een geweigerde voorbereidende aanvraag, zie de sectie Test CORS van dit document.

Met de F12-hulpprogramma's wordt in de console-app een fout weergegeven die vergelijkbaar is met een van de volgende, afhankelijk van de browser:

  • Firefox: Cross-Origin-aanvraag geblokkeerd: de Same-Origin Policy staat het lezen van de externe resource op https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5 niet toe. (Reden: CORS-aanvraag is niet geslaagd). Meer informatie
  • Op basis van Chromium: Toegang tot het ophalen van 'https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5' vanaf oorsprong 'https://cors3.azurewebsites.net' is geblokkeerd door CORS-beleid: Reactie op preflight-verzoek voldoet niet aan de toegangscontrole: Er is geen 'Access-Control-Allow-Origin'-header aanwezig op de opgevraagde resource. Als een ondoorzichtig antwoord aan uw behoeften voldoet, stelt u de modus van de aanvraag in op 'no-cors' om de resource op te halen waarvoor CORS is uitgeschakeld.

Als u specifieke headers wilt toestaan, roept u het volgende aan 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();

Als u alle verzoekheaders van de auteur wilt toestaan, roept u AllowAnyHeader aan.

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

Browsers zijn niet consistent in de wijze waarop ze zijn ingesteld Access-Control-Request-Headers. Als een van beide:

  • Kopteksten zijn ingesteld op iets anders dan "*"
  • AllowAnyHeader wordt aangeroepen: neem ten minste Accept, Content-Typeen Originplus eventuele aangepaste headers op die u wilt ondersteunen.

Code voor automatische preflightaanvraag

Wanneer het CORS-beleid wordt toegepast, ofwel:

  • Wereldwijd door app.UseCors in Program.cs te bellen.
  • Gebruikmakend van het [EnableCors] kenmerk.

ASP.NET Core reageert op de preflight-OPTIES-aanvraag.

In de sectie CORS testen van dit document ziet u dit gedrag.

Kenmerk [HttpOptions] voor preflightverzoeken

Wanneer CORS is ingeschakeld met het juiste beleid, reageert ASP.NET Core in het algemeen automatisch op CORS-voorbereidende aanvragen.

De volgende code maakt gebruik van het kenmerk [HttpOptions] voor het maken van eindpunten voor OPTIONS-aanvragen:

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

Zie CORS testen met het kenmerk [EnableCors] en de RequireCors-methode voor instructies over het testen van de voorgaande code.

De verlooptijd van de voorbereidende fase instellen

De Access-Control-Max-Age header geeft aan hoe lang het antwoord op het preflight-verzoek in de cache kan worden opgeslagen. Als u deze header wilt instellen, roept u het volgende SetPreflightMaxAgeaan:

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

CORS inschakelen op een eindpunt

Hoe CORS werkt

In deze sectie wordt beschreven wat er gebeurt in een CORS-aanvraag op het niveau van de HTTP-berichten.

  • CORS is geen beveiligingsfunctie. CORS is een W3C-standaard waarmee een server hetzelfde origin-beleid kan versoepelen.
    • Een kwaadwillende actor kan bijvoorbeeld XSS (Cross-Site Scripting) gebruiken op uw site en een cross-site-aanvraag uitvoeren op hun CORS-site om informatie te stelen.
  • Een API is niet veiliger door CORS toe te staan.
    • Het is aan de client (browser) om CORS af te dwingen. De server voert de aanvraag uit en retourneert het antwoord, het is de client die een fout retourneert en het antwoord blokkeert. Met een van de volgende hulpprogramma's wordt bijvoorbeeld het serverantwoord weergegeven:
  • Het is een manier voor een server om browsers toe te staan een cross-origin XHR - of Fetch API-aanvraag uit te voeren die anders verboden zou zijn.
    • Browsers zonder CORS kunnen geen cross-origin-aanvragen uitvoeren. Vóór CORS werd JSONP gebruikt om deze beperking te omzeilen. JSONP gebruikt geen XHR, maar gebruikt de <script> tag om het antwoord te ontvangen. Scripts mogen cross-origin worden geladen.

De CORS-specificatie heeft verschillende nieuwe HTTP-headers geïntroduceerd die cross-origin-aanvragen mogelijk maken. Als een browser CORS ondersteunt, worden deze headers automatisch ingesteld voor cross-origin-aanvragen. Aangepaste JavaScript-code is niet vereist om CORS in te schakelen.

Dit is een voorbeeld van een cross-origin-aanvraag van de waardentest-knop naar https://cors1.azurewebsites.net/api/values. De Origin koptekst:

  • Geeft het domein van de site die het verzoek indient.
  • Is vereist en moet afwijken van de host.

Algemene headers

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

Antwoordheaders

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

Verzoekheaders

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

In OPTIONS aanvragen stelt de server de header AntwoordheadersAccess-Control-Allow-Origin: {allowed origin} in het antwoord in. In de voorbeeldcode bevat de Delete [EnableCors] knopaanvraag OPTIONS bijvoorbeeld de volgende headers:

Algemene headers

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

Antwoordheaders

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

Verzoekheaders

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

In de voorgaande antwoordheaders stelt de server in het antwoord de header Access-Control-Allow-Origin in. De https://cors1.azurewebsites.net waarde van deze header komt overeen met de Origin header van de aanvraag.

Als AllowAnyOrigin wordt aangeroepen, wordt de Access-Control-Allow-Origin: *, de jokertekenwaarde, geretourneerd. AllowAnyOrigin staat elke oorsprong toe.

Als het antwoord de header niet bevat Access-Control-Allow-Origin , mislukt de cross-origin-aanvraag. De browser staat de aanvraag met name niet toe. Zelfs als de server een geslaagd antwoord retourneert, maakt de browser het antwoord niet beschikbaar voor de client-app.

HTTP-omleiding naar HTTPS veroorzaakt ERR_INVALID_REDIRECT op de preflight CORS-verzoek

Aanvragen naar een eindpunt met HTTP die door UseHttpsRedirection worden omgeleid naar HTTPS, mislukken met ERR_INVALID_REDIRECT on the CORS preflight request.

API-projecten kunnen HTTP-aanvragen weigeren in plaats van te gebruiken UseHttpsRedirection om aanvragen om te leiden naar HTTPS.

CORS in IIS

Bij de implementatie in IIS moet CORS worden uitgevoerd vóór Windows-verificatie als de server niet is geconfigureerd om anonieme toegang toe te staan. Ter ondersteuning van dit scenario moet de IIS CORS-module worden geïnstalleerd en geconfigureerd voor de app.

CORS testen

Het voorbeelddownload bevat code om CORS te testen. Zie hoe ukunt downloaden. Het voorbeeld is een API-project met Razor Pages toegevoegd:

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

Waarschuwing

WithOrigins("https://localhost:<port>"); mag alleen worden gebruikt voor het testen van een voorbeeld-app die vergelijkbaar is met de voorbeeldcode voor het downloaden.

Opmerking

Als u in Visual Studio werkt launchSettings.json of C#-foutopsporingsinstellingen in VS Code configureert en IIS Express gebruikt om lokaal fouten op te sporen, moet u ervoor zorgen dat u IIS Express hebt geconfigureerd voor "anonymousAuthentication": true. Wanneer "anonymousAuthentication"false is, ziet de host van de ASP.NET Core-webomgeving geen preflight-verzoeken. Met name als u gebruikmaakt van NTLM-verificatie ("windowsAuthentication": true), is de eerste stap van het NTLM-vraag-antwoord proces het versturen van een 401-uitdaging naar de webbrowser, waardoor het lastig kan zijn om te controleren of uw preflight-aanroep correct is geconfigureerd.

ValuesController Hieronder vindt u de eindpunten voor het testen:

[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 wordt geleverd door het Rick.Docs.Samples.RouteInfo NuGet-pakket en toont routegegevens.

Test de voorgaande voorbeeldcode met behulp van een van de volgende methoden:

  • Voer het voorbeeld uit met dotnet run behulp van de standaard-URL van https://localhost:5001.
  • Voer het voorbeeld uit vanuit Visual Studio met de poort ingesteld op 44398 voor een URL van https://localhost:44398.

Een browser gebruiken met de F12-hulpprogramma's:

  • Selecteer de knop Waarden en controleer de kopteksten op het tabblad Netwerk .

  • Selecteer de PUT-test knop. Zie WeergaveOPTIES-aanvragen voor instructies over het weergeven van de OPTIONS-aanvraag. De PUT-test maakt twee aanvragen, een OPTIONS preflight-aanvraag en een PUT-aanvraag.

  • Selecteer de GetValues2 [DisableCors] knop om een mislukte CORS-aanvraag te activeren. Zoals vermeld in het document, retourneert het antwoord 200 succes, maar wordt het CORS-verzoek niet gedaan. Selecteer het tabblad Console om de CORS-fout weer te geven. Afhankelijk van de browser wordt een fout weergegeven die lijkt op het volgende:

    Toegang voor het ophalen van 'https://cors1.azurewebsites.net/api/values/GetValues2' vanaf oorsprong 'https://cors3.azurewebsites.net' is geblokkeerd door het CORS-beleid: Er is geen 'Access-Control-Allow-Origin' header aanwezig op de aangevraagde resource. Als een ondoorzichtig antwoord aan uw behoeften voldoet, stelt u de modus van de aanvraag in op 'no-cors' om de resource op te halen waarvoor CORS is uitgeschakeld.

CORS-eindpunten kunnen worden getest met een hulpprogramma, zoals curl of Fiddler. Wanneer u een hulpprogramma gebruikt, moet de oorsprong van de aanvraag die is opgegeven door de Origin header verschillen van de host die de aanvraag ontvangt. Als de aanvraag niet cross-origin is op basis van de waarde van de Origin header:

  • Cors Middleware is niet nodig om de aanvraag te verwerken.
  • CORS-headers worden niet geretourneerd in het antwoord.

Met de volgende opdracht curl wordt een OPTIONS-aanvraag met informatie verzonden:

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

CORS testen met het kenmerk [EnableCors] en de RequireCors-methode

Houd rekening met de volgende code die eindpuntroutering gebruikt om CORS per eindpunt in te schakelen met behulp van 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();

Merk op dat alleen het /echo eindpunt het gebruik van RequireCors toestaat om cross-origin aanvragen mogelijk te maken volgens het opgegeven beleid. De onderstaande controllers schakelen CORS in met behulp van het kenmerk [EnableCors].

TodoItems1Controller Hieronder vindt u eindpunten voor het testen:

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

De knoppen Delete [EnableCors] en GET [EnableCors] slagen, omdat de eindpunten [EnableCors] hebben voor preflight-aanvragen en daarop reageren. De andere eindpunten mislukken. De get-knop mislukt, omdat javaScript het volgende verzendt:

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

Het volgende TodoItems2Controller biedt vergelijkbare eindpunten, maar bevat expliciete code om te reageren op OPTIONS-aanvragen:

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

De voorgaande code kan worden getest door het voorbeeld in Azure te implementeren. Selecteer Preflight in de vervolgkeuzelijst Controller en stel controller in. Alle CORS-aanroepen naar de TodoItems2Controller eindpunten zijn geslaagd.

Aanvullende bronnen

Door Rick Anderson en Kirk Larkin

In dit artikel wordt beschreven hoe u CORS inschakelt in een ASP.NET Core-app.

Browserbeveiliging voorkomt dat een webpagina aanvragen indient naar een ander domein dan het domein dat de webpagina heeft geleverd. Deze beperking wordt het same-origin policy genoemd. Hetzelfde origin-beleid voorkomt dat een kwaadwillende site gevoelige gegevens van een andere site leest. Soms wilt u toestaan dat andere sites cross-origin-aanvragen indienen bij uw app. Zie het Mozilla CORS-artikel voor meer informatie.

Cross Origin Resource Sharing (CORS):

  • Is een W3C-standaard waarmee een server hetzelfde origin-beleid kan versoepelen.
  • Is geen beveiligingsfunctie, CORS maakt de beveiliging soepeler. Een API is niet veiliger door CORS toe te staan. Zie Hoe CORS werkt voor meer informatie.
  • Hiermee staat u een server toe om bepaalde cross-origin-aanvragen expliciet toe te staan terwijl andere aanvragen worden geweigerd.
  • Is veiliger en flexibeler dan eerdere technieken, zoals JSONP.

Voorbeeldcode bekijken of downloaden (hoe download je)

Dezelfde oorsprong

Twee URL's hebben dezelfde oorsprong als ze identieke schema's, hosts en poorten (RFC 6454) hebben.

Deze twee URL's hebben dezelfde oorsprong:

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

Deze URL's hebben verschillende oorsprongen dan de vorige twee URL's:

  • https://example.net: Ander domein
  • https://www.example.com/foo.html: Ander subdomein
  • http://example.com/foo.html: Verschillend schema
  • https://example.com:9000/foo.html: Andere poort

CORS inschakelen

Er zijn drie manieren om CORS in te schakelen:

Het gebruik van het kenmerk [EnableCors] met een benoemd beleid biedt het beste beheer voor het beperken van eindpunten die CORS ondersteunen.

Waarschuwing

UseCors moet in de juiste volgorde worden aangeroepen. Zie Middleware-bestelling voor meer informatie. Moet bijvoorbeeld UseCors worden aangeroepen voordat UseResponseCaching wanneer UseResponseCaching wordt gebruikt.

Elke benadering wordt in de volgende secties beschreven.

CORS met benoemd beleid en middleware

CORS Middleware verwerkt cross-origin-aanvragen. Met de volgende code wordt een CORS-beleid toegepast op alle eindpunten van de app met de opgegeven oorsprongen:

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

De voorgaande code:

Met eindpuntroutering moet de CORS-middleware worden geconfigureerd voor uitvoering tussen de aanroepen naar UseRouting en UseEndpoints.

Met de AddCors methodeoproep worden CORS-services toegevoegd aan de servicecontainer van de app:

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

Zie CORS-beleidsopties in dit document voor meer informatie.

De CorsPolicyBuilder methoden kunnen worden gekoppeld, zoals wordt weergegeven in de volgende code:

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

Opmerking: de opgegeven URL mag geen afsluitende slash (/) bevatten. Als de URL eindigt met /, levert de vergelijking false op en wordt er geen header geretourneerd.

Waarschuwing

UseCors moet na UseRouting en vóór UseAuthorizationworden geplaatst. Dit is om ervoor te zorgen dat CORS-headers worden opgenomen in het antwoord voor geautoriseerde en niet-geautoriseerde aanroepen.

Volgorde van UseCors en UseStaticFiles

UseStaticFiles Normaal gesproken wordt het eerder UseCorsaangeroepen. Apps die JavaScript gebruiken om statische bestanden cross-site op te halen, moeten UseCors aanroepen voordat ze UseStaticFiles.

CORS met standaardbeleid en middleware

Met de volgende gemarkeerde code wordt het standaard CORS-beleid ingeschakeld:

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

Met de voorgaande code wordt het standaard CORS-beleid toegepast op alle controllereindpunten.

Cors met eindpuntroutering inschakelen

Met eindpuntroutering kan CORS per eindpunt worden ingeschakeld met behulp van de RequireCors set extensiemethoden:

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

In de voorgaande code:

  • app.UseCors schakelt de CORS-middleware in. Omdat er geen standaardbeleid is geconfigureerd, maakt app.UseCors() alleen CORS niet mogelijk.
  • De /echo- en controle-eindpunten staan cross-origin-aanvragen toe met behulp van het opgegeven beleid.
  • De /echo2 en Razor Pagina-eindpunten staan geen cross-origin-aanvragen toe omdat er geen standaardbeleid is opgegeven.

Het kenmerk [DisableCors] schakelt niet de CORS uit die is ingeschakeld door eindpuntroutering met RequireCors.

In .NET 7 moet het [EnableCors] kenmerk een parameter doorgeven, anders wordt er een ASP0023 waarschuwing gegenereerd vanwege een onduidelijke overeenkomst op de route. De waarschuwing wordt niet gegenereerd ASP0023 door .NET 8 of hoger.

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

Zie CORS testen met het kenmerk [EnableCors] en de RequireCors-methode voor instructies over het testen van code die vergelijkbaar is met de voorgaande.

CORS met kenmerken inschakelen

Het inschakelen van CORS met het kenmerk [EnableCors] en het toepassen van een benoemd beleid op alleen die eindpunten waarvoor CORS is vereist, biedt het beste beheer.

Het kenmerk [EnableCors] biedt een alternatief voor het wereldwijd toepassen van CORS. Met [EnableCors] het kenmerk wordt CORS ingeschakeld voor geselecteerde eindpunten, in plaats van alle eindpunten:

  • [EnableCors] hiermee geeft u het standaardbeleid.
  • [EnableCors("{Policy String}")] specificeert een benoemd beleid.

Het [EnableCors] kenmerk kan worden toegepast op:

  • Razor Bladzijde PageModel
  • Controleur
  • Controller-actiemethode

Verschillende beleidsregels kunnen worden toegepast op controllers, paginamodellen of actiemethoden met het [EnableCors] kenmerk. Wanneer het [EnableCors] kenmerk wordt toegepast op een controller, paginamodel of actiemethode en CORS is ingeschakeld in middleware, worden beide beleidsregels toegepast. Wij raden aan om beleidsregels niet te combineren. Gebruik de [EnableCors] kenmerk of middleware, niet beide in dezelfde app.

Met de volgende code wordt een ander beleid toegepast op elke methode:

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

Met de volgende code worden twee CORS-beleidsregels gemaakt:

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

Voor de beste controle over het beperken van CORS-aanvragen:

  • Gebruik [EnableCors("MyPolicy")] met een genaamd beleid.
  • Definieer geen standaardbeleid.
  • Gebruik geen eindpuntroutering.

De code in de volgende sectie voldoet aan de voorgaande lijst.

CORS uitschakelen

Het kenmerk [DisableCors] schakelt CORS die is ingeschakeld door eindpuntrouteringniet uit.

De volgende code definieert het CORS-beleid "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();

Met de volgende code wordt CORS uitgeschakeld voor de GetValues2 actie:

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

}

De voorgaande code:

Zie CORS testen voor instructies over het testen van de voorgaande code.

CORS-beleidsopties

In deze sectie worden de verschillende opties beschreven die kunnen worden ingesteld in een CORS-beleid:

AddPolicy wordt ingeroepen in Program.cs. Voor sommige opties kan het nuttig zijn om eerst de sectie Hoe CORS werkt te lezen.

De toegestane oorsprongen instellen

AllowAnyOrigin: Hiermee staat u CORS-aanvragen van alle oorsprongen toe met elk schema (http of https). AllowAnyOrigin is onveilig omdat elke website cross-origin aanvragen kan indienen bij de app.

Opmerking

Het opgeven van AllowAnyOrigin en AllowCredentials is een onveilige configuratie en leidt tot cross-site request-vervalsing. De CORS-service retourneert een ongeldig CORS-antwoord wanneer een app is geconfigureerd met beide methoden.

AllowAnyOrigin beïnvloedt preflight-aanvragen en de Access-Control-Allow-Origin-koptekst. Zie de sectie Voorbereidende aanvragen voor meer informatie.

SetIsOriginAllowedToAllowWildcardSubdomains: Hiermee stelt u de IsOriginAllowed eigenschap van het beleid in als een functie waarmee origins overeenkomen met een geconfigureerd wildcarddomein bij het evalueren of de oorsprong is toegestaan.

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

De toegestane HTTP-methoden instellen

AllowAnyMethod:

  • Hiermee staat u elke HTTP-methode toe:
  • Beïnvloedt voorbereidende aanvragen en de Access-Control-Allow-Methods-header. Zie de sectie Voorbereidende aanvragen voor meer informatie.

De toegestane aanvraagheaders instellen

Als u wilt toestaan dat specifieke headers worden verzonden in een CORS-aanvraag, genaamd headers van auteursaanvragen, roept WithHeaders u de toegestane headers aan en geeft u de toegestane headers op:

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

Als u alle auteursaanvraagheaders wilt toestaan, roept u het volgende AllowAnyHeaderaan:

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 beïnvloedt preflight-aanvragen en de Access-Control-Request-Headers-header. Zie de sectie Voorbereidende aanvragen voor meer informatie.

Een CORS Middleware-beleid matcht met specifieke headers gespecificeerd door WithHeaders alleen wanneer de headers in Access-Control-Request-Headers exact overeenkomen met de headers die zijn gespecificeerd in WithHeaders.

Denk bijvoorbeeld aan een app die als volgt is geconfigureerd:

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

CORS Middleware weigert een voorafgaande aanvraag met de volgende aanvraagheader omdat Content-Language (HeaderNames.ContentLanguage) niet wordt vermeld in WithHeaders:

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

De app retourneert een 200 OK-antwoord , maar stuurt de CORS-headers niet terug. Daarom probeert de browser de cross-origin-aanvraag niet uit te voeren.

De weergegeven antwoordheaders instellen

Standaard worden in de browser niet alle antwoordheaders voor de app weergegeven. Zie W3C Cross-Origin Resource Sharing (Terminologie): Simple Response Header voor meer informatie.

De antwoordheaders die standaard beschikbaar zijn, zijn:

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

De CORS-specificatie roept deze headers eenvoudige antwoordheaders aan. Als u andere headers beschikbaar wilt maken voor de app, roept u het volgende WithExposedHeadersaan:

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

Inloggegevens in cross-origin-aanvragen

Referenties vereisen speciale verwerking in een CORS-aanvraag. Standaard verzendt de browser geen inloggegevens met een cross-origin-aanvraag. Inloggegevens omvatten cookies en HTTP-authenticatieschema's. Om referenties met een cross-origin verzoek mee te sturen, moet de client XMLHttpRequest.withCredentials instellen op true.

Gebruik rechtstreeks XMLHttpRequest:

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

JQuery gebruiken:

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

De Fetch-API gebruiken:

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

De server moet de inloggegevens toestaan. Als u referenties voor meerdere oorsprongen wilt toestaan, roept u AllowCredentials op.

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

Het HTTP-antwoord bevat een Access-Control-Allow-Credentials header, waarmee de browser aangeeft dat de server referenties toestaat voor een cross-origin-aanvraag.

Als de browser referenties verzendt, maar het antwoord geen geldige Access-Control-Allow-Credentials header bevat, geeft de browser het antwoord niet beschikbaar aan de app en mislukt de cross-origin-aanvraag.

Het toestaan van cross-origin credentials is een beveiligingsrisico. Een website in een ander domein kan de referenties van een aangemelde gebruiker namens de gebruiker verzenden naar de app zonder dat de gebruiker dit weet.

De CORS-specificatie geeft ook aan dat het instellen van origins op "*" (alle origins) ongeldig is als de Access-Control-Allow-Credentials header aanwezig is.

Preflight-verzoeken

Voor sommige CORS-aanvragen verzendt de browser een extra OPTIONS-aanvraag voordat de werkelijke aanvraag wordt ingediend. Deze aanvraag wordt een voorbereidende aanvraag genoemd. De browser kan de voorbereidende aanvraag overslaan als aan alle volgende voorwaarden wordt voldaan:

  • De aanvraagmethode is GET, HEAD of POST.
  • De app stelt geen andere aanvraagheaders in dan Accept, Accept-Language, Content-Language, Content-Typeof Last-Event-ID.
  • De Content-Type header, indien ingesteld, heeft een van de volgende waarden:
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

De regel voor aanvraagheaders die zijn ingesteld voor de clientaanvraag is van toepassing op headers die door de app worden ingesteld door setRequestHeader aan te roepen op het XMLHttpRequest-object. De CORS-specificatie noemt deze headers auteursaanvraagheaders. De regel is niet van toepassing op headers die de browser kan instellen, zoals User-Agent, Hostof Content-Length.

Hier volgt een voorbeeld van een antwoord dat lijkt op het preflight-verzoek dat is gedaan via de knop [Put test] in de Test CORS sectie van dit document.

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

Het preflight-verzoek gebruikt de HTTP OPTIONS methode. Het kan de volgende headers bevatten:

Als de voorbereidende aanvraag wordt geweigerd, retourneert de app een 200 OK antwoord, maar de CORS-headers worden niet ingesteld. Daarom probeert de browser de cross-origin-aanvraag niet uit te voeren. Voor een voorbeeld van een geweigerde voorbereidende aanvraag, zie de sectie Test CORS van dit document.

Met de F12-hulpprogramma's wordt in de console-app een fout weergegeven die vergelijkbaar is met een van de volgende, afhankelijk van de browser:

  • Firefox: Cross-Origin-aanvraag geblokkeerd: de Same-Origin Policy staat het lezen van de externe resource op https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5 niet toe. (Reden: CORS-aanvraag is niet geslaagd). Meer informatie
  • Op basis van Chromium: Toegang tot het ophalen van 'https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5' vanaf oorsprong 'https://cors3.azurewebsites.net' is geblokkeerd door CORS-beleid: Reactie op preflight-verzoek voldoet niet aan de toegangscontrole: Er is geen 'Access-Control-Allow-Origin'-header aanwezig op de opgevraagde resource. Als een ondoorzichtig antwoord aan uw behoeften voldoet, stelt u de modus van de aanvraag in op 'no-cors' om de resource op te halen waarvoor CORS is uitgeschakeld.

Als u specifieke headers wilt toestaan, roept u het volgende aan 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();

Als u alle auteursaanvraagheaders wilt toestaan, roept u het volgende AllowAnyHeaderaan:

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

Browsers zijn niet consistent in de wijze waarop ze zijn ingesteld Access-Control-Request-Headers. Als een van beide:

  • Kopteksten zijn ingesteld op iets anders dan "*"
  • AllowAnyHeader wordt aangeroepen: neem ten minste Accept, Content-Typeen Originplus eventuele aangepaste headers op die u wilt ondersteunen.

Code voor automatische preflightaanvraag

Wanneer het CORS-beleid wordt toegepast, ofwel:

  • Wereldwijd door app.UseCors in Program.cs te bellen.
  • Gebruikmakend van het [EnableCors] kenmerk.

ASP.NET Core reageert op de preflight-OPTIES-aanvraag.

In de sectie CORS testen van dit document ziet u dit gedrag.

Kenmerk [HttpOptions] voor preflightverzoeken

Wanneer CORS is ingeschakeld met het juiste beleid, reageert ASP.NET Core in het algemeen automatisch op CORS-voorbereidende aanvragen.

De volgende code maakt gebruik van het kenmerk [HttpOptions] voor het maken van eindpunten voor OPTIONS-aanvragen:

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

Zie CORS testen met het kenmerk [EnableCors] en de RequireCors-methode voor instructies over het testen van de voorgaande code.

De verlooptijd van de voorbereidende fase instellen

De Access-Control-Max-Age header geeft aan hoe lang het antwoord op het preflight-verzoek in de cache kan worden opgeslagen. Als u deze header wilt instellen, roept u het volgende SetPreflightMaxAgeaan:

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

CORS inschakelen op een eindpunt

Hoe CORS werkt

In deze sectie wordt beschreven wat er gebeurt in een CORS-aanvraag op het niveau van de HTTP-berichten.

  • CORS is geen beveiligingsfunctie. CORS is een W3C-standaard waarmee een server hetzelfde origin-beleid kan versoepelen.
    • Een kwaadwillende actor kan bijvoorbeeld XSS (Cross-Site Scripting) gebruiken op uw site en een cross-site-aanvraag uitvoeren op hun CORS-site om informatie te stelen.
  • Een API is niet veiliger door CORS toe te staan.
    • Het is aan de client (browser) om CORS af te dwingen. De server voert de aanvraag uit en retourneert het antwoord, het is de client die een fout retourneert en het antwoord blokkeert. Met een van de volgende hulpprogramma's wordt bijvoorbeeld het serverantwoord weergegeven:
  • Het is een manier voor een server om browsers toe te staan een cross-origin XHR - of Fetch API-aanvraag uit te voeren die anders verboden zou zijn.
    • Browsers zonder CORS kunnen geen cross-origin-aanvragen uitvoeren. Vóór CORS werd JSONP gebruikt om deze beperking te omzeilen. JSONP gebruikt geen XHR, maar gebruikt de <script> tag om het antwoord te ontvangen. Scripts mogen cross-origin worden geladen.

De CORS-specificatie heeft verschillende nieuwe HTTP-headers geïntroduceerd die cross-origin-aanvragen mogelijk maken. Als een browser CORS ondersteunt, worden deze headers automatisch ingesteld voor cross-origin-aanvragen. Aangepaste JavaScript-code is niet vereist om CORS in te schakelen.

Selecteer de knop PUT-test in het geïmplementeerde voorbeeld. De Origin koptekst:

  • Geeft het domein van de site die het verzoek indient.
  • Is vereist en moet afwijken van de host.

Algemene headers

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

Antwoordheaders

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

Verzoekheaders

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

In OPTIONS aanvragen stelt de server de header AntwoordheadersAccess-Control-Allow-Origin: {allowed origin} in het antwoord in. In de voorbeeldcode bevat de Delete [EnableCors] knopaanvraag OPTIONS bijvoorbeeld de volgende headers:

Algemene headers

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

Antwoordheaders

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

Verzoekheaders

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

In de voorgaande antwoordheaders stelt de server in het antwoord de header Access-Control-Allow-Origin in. De https://cors1.azurewebsites.net waarde van deze header komt overeen met de Origin header van de aanvraag.

Als AllowAnyOrigin wordt aangeroepen, wordt de Access-Control-Allow-Origin: *, de jokertekenwaarde, geretourneerd. AllowAnyOrigin staat elke oorsprong toe.

Als het antwoord de header niet bevat Access-Control-Allow-Origin , mislukt de cross-origin-aanvraag. De browser staat de aanvraag met name niet toe. Zelfs als de server een geslaagd antwoord retourneert, maakt de browser het antwoord niet beschikbaar voor de client-app.

HTTP-omleiding naar HTTPS veroorzaakt ERR_INVALID_REDIRECT op de preflight CORS-verzoek

Aanvragen naar een eindpunt met HTTP die door UseHttpsRedirection worden omgeleid naar HTTPS, mislukken met ERR_INVALID_REDIRECT on the CORS preflight request.

API-projecten kunnen HTTP-aanvragen weigeren in plaats van te gebruiken UseHttpsRedirection om aanvragen om te leiden naar HTTPS.

CORS in IIS

Bij de implementatie in IIS moet CORS worden uitgevoerd vóór Windows-verificatie als de server niet is geconfigureerd om anonieme toegang toe te staan. Ter ondersteuning van dit scenario moet de IIS CORS-module worden geïnstalleerd en geconfigureerd voor de app.

CORS testen

Het voorbeelddownload bevat code om CORS te testen. Zie hoe ukunt downloaden. Het voorbeeld is een API-project met Razor Pages toegevoegd:

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

Waarschuwing

WithOrigins("https://localhost:<port>"); mag alleen worden gebruikt voor het testen van een voorbeeld-app die vergelijkbaar is met de voorbeeldcode voor het downloaden.

ValuesController Hieronder vindt u de eindpunten voor het testen:

[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 wordt geleverd door het Rick.Docs.Samples.RouteInfo NuGet-pakket en toont routegegevens.

Test de voorgaande voorbeeldcode met behulp van een van de volgende methoden:

  • Voer het voorbeeld uit met dotnet run behulp van de standaard-URL van https://localhost:5001.
  • Voer het voorbeeld uit vanuit Visual Studio met de poort ingesteld op 44398 voor een URL van https://localhost:44398.

Een browser gebruiken met de F12-hulpprogramma's:

  • Selecteer de knop Waarden en controleer de kopteksten op het tabblad Netwerk .

  • Selecteer de PUT-test knop. Zie WeergaveOPTIES-aanvragen voor instructies over het weergeven van de OPTIONS-aanvraag. De PUT-test maakt twee aanvragen, een OPTIONS preflight-aanvraag en een PUT-aanvraag.

  • Selecteer de GetValues2 [DisableCors] knop om een mislukte CORS-aanvraag te activeren. Zoals vermeld in het document, retourneert het antwoord 200 succes, maar wordt het CORS-verzoek niet gedaan. Selecteer het tabblad Console om de CORS-fout weer te geven. Afhankelijk van de browser wordt een fout weergegeven die lijkt op het volgende:

    Toegang voor het ophalen van 'https://cors1.azurewebsites.net/api/values/GetValues2' vanaf oorsprong 'https://cors3.azurewebsites.net' is geblokkeerd door het CORS-beleid: Er is geen 'Access-Control-Allow-Origin' header aanwezig op de aangevraagde resource. Als een ondoorzichtig antwoord aan uw behoeften voldoet, stelt u de modus van de aanvraag in op 'no-cors' om de resource op te halen waarvoor CORS is uitgeschakeld.

CORS-eindpunten kunnen worden getest met een hulpprogramma, zoals curl of Fiddler. Wanneer u een hulpprogramma gebruikt, moet de oorsprong van de aanvraag die is opgegeven door de Origin header verschillen van de host die de aanvraag ontvangt. Als de aanvraag niet cross-origin is op basis van de waarde van de Origin header:

  • Cors Middleware is niet nodig om de aanvraag te verwerken.
  • CORS-headers worden niet geretourneerd in het antwoord.

Met de volgende opdracht curl wordt een OPTIONS-aanvraag met informatie verzonden:

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

CORS testen met het kenmerk [EnableCors] en de RequireCors-methode

Houd rekening met de volgende code die eindpuntroutering gebruikt om CORS per eindpunt in te schakelen met behulp van 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();

Merk op dat alleen het /echo eindpunt het gebruik van RequireCors toestaat om cross-origin aanvragen mogelijk te maken volgens het opgegeven beleid. De onderstaande controllers schakelen CORS in met behulp van het kenmerk [EnableCors].

TodoItems1Controller Hieronder vindt u eindpunten voor het testen:

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

De knoppen Delete [EnableCors] en GET [EnableCors] slagen, omdat de eindpunten [EnableCors] hebben voor preflight-aanvragen en daarop reageren. De andere eindpunten mislukken. De get-knop mislukt, omdat javaScript het volgende verzendt:

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

Het volgende TodoItems2Controller biedt vergelijkbare eindpunten, maar bevat expliciete code om te reageren op OPTIONS-aanvragen:

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

De voorgaande code kan worden getest door het voorbeeld te implementeren in Azure.In de vervolgkeuzelijst Controller , preflight te selecteren en vervolgens Controller in te stellen. Alle CORS-aanroepen naar de TodoItems2Controller eindpunten zijn geslaagd.

Aanvullende bronnen

Door Rick Anderson en Kirk Larkin

In dit artikel wordt beschreven hoe u CORS inschakelt in een ASP.NET Core-app.

Browserbeveiliging voorkomt dat een webpagina aanvragen indient naar een ander domein dan het domein dat de webpagina heeft geleverd. Deze beperking wordt het same-origin policy genoemd. Hetzelfde origin-beleid voorkomt dat een kwaadwillende site gevoelige gegevens van een andere site leest. Soms wilt u toestaan dat andere sites cross-origin-aanvragen indienen bij uw app. Zie het Mozilla CORS-artikel voor meer informatie.

Cross Origin Resource Sharing (CORS):

  • Is een W3C-standaard waarmee een server hetzelfde origin-beleid kan versoepelen.
  • Is geen beveiligingsfunctie, CORS maakt de beveiliging soepeler. Een API is niet veiliger door CORS toe te staan. Zie Hoe CORS werkt voor meer informatie.
  • Hiermee staat u een server toe om bepaalde cross-origin-aanvragen expliciet toe te staan terwijl andere aanvragen worden geweigerd.
  • Is veiliger en flexibeler dan eerdere technieken, zoals JSONP.

Voorbeeldcode bekijken of downloaden (hoe download je)

Dezelfde oorsprong

Twee URL's hebben dezelfde oorsprong als ze identieke schema's, hosts en poorten (RFC 6454) hebben.

Deze twee URL's hebben dezelfde oorsprong:

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

Deze URL's hebben verschillende oorsprongen dan de vorige twee URL's:

  • https://example.net: Ander domein
  • https://www.example.com/foo.html: Ander subdomein
  • http://example.com/foo.html: Verschillend schema
  • https://example.com:9000/foo.html: Andere poort

CORS inschakelen

Er zijn drie manieren om CORS in te schakelen:

Het gebruik van het kenmerk [EnableCors] met een benoemd beleid biedt het beste beheer voor het beperken van eindpunten die CORS ondersteunen.

Waarschuwing

UseCors moet in de juiste volgorde worden aangeroepen. Zie Middleware-bestelling voor meer informatie. Moet bijvoorbeeld UseCors worden aangeroepen voordat UseResponseCaching wanneer UseResponseCaching wordt gebruikt.

Elke benadering wordt in de volgende secties beschreven.

CORS met benoemd beleid en middleware

CORS Middleware verwerkt cross-origin-aanvragen. Met de volgende code wordt een CORS-beleid toegepast op alle eindpunten van de app met de opgegeven oorsprongen:

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

De voorgaande code:

Met eindpuntroutering moet de CORS-middleware worden geconfigureerd voor uitvoering tussen de aanroepen naar UseRouting en UseEndpoints.

Met de AddCors methodeoproep worden CORS-services toegevoegd aan de servicecontainer van de app:

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

Zie CORS-beleidsopties in dit document voor meer informatie.

De CorsPolicyBuilder methoden kunnen worden gekoppeld, zoals wordt weergegeven in de volgende code:

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

Opmerking: de opgegeven URL mag geen afsluitende slash (/) bevatten. Als de URL eindigt met /, levert de vergelijking false op en wordt er geen header geretourneerd.

Waarschuwing

UseCors moet na UseRouting en vóór UseAuthorizationworden geplaatst. Dit is om ervoor te zorgen dat CORS-headers worden opgenomen in het antwoord voor geautoriseerde en niet-geautoriseerde aanroepen.

Volgorde van UseCors en UseStaticFiles

UseStaticFiles Normaal gesproken wordt het eerder UseCorsaangeroepen. Apps die JavaScript gebruiken om statische bestanden cross-site op te halen, moeten UseCors aanroepen voordat ze UseStaticFiles.

CORS met standaardbeleid en middleware

Met de volgende gemarkeerde code wordt het standaard CORS-beleid ingeschakeld:

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

Met de voorgaande code wordt het standaard CORS-beleid toegepast op alle controllereindpunten.

Cors met eindpuntroutering inschakelen

Het inschakelen van CORS per eindpunt RequireCors biedt geen ondersteuning voor automatische voorbereidende aanvragen. Zie dit GitHub-probleem en test CORS met eindpuntroutering en [HttpOptions]voor meer informatie.

Met eindpuntroutering kan CORS per eindpunt worden ingeschakeld met behulp van de RequireCors set extensiemethoden:

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

In de voorgaande code:

  • app.UseCors schakelt de CORS-middleware in. Omdat er geen standaardbeleid is geconfigureerd, maakt app.UseCors() alleen CORS niet mogelijk.
  • De /echo- en controle-eindpunten staan cross-origin-aanvragen toe met behulp van het opgegeven beleid.
  • De /echo2 en Razor Pagina-eindpunten staan geen cross-origin-aanvragen toe omdat er geen standaardbeleid is opgegeven.

Het kenmerk [DisableCors] schakelt niet de CORS uit die is ingeschakeld door eindpuntroutering met RequireCors.

Zie CORS testen met eindpuntroutering en [HttpOptions] voor instructies over het testen van code die vergelijkbaar is met de voorgaande.

CORS met kenmerken inschakelen

Het inschakelen van CORS met het kenmerk [EnableCors] en het toepassen van een benoemd beleid op alleen die eindpunten waarvoor CORS is vereist, biedt het beste beheer.

Het kenmerk [EnableCors] biedt een alternatief voor het wereldwijd toepassen van CORS. Met [EnableCors] het kenmerk wordt CORS ingeschakeld voor geselecteerde eindpunten, in plaats van alle eindpunten:

  • [EnableCors] hiermee geeft u het standaardbeleid.
  • [EnableCors("{Policy String}")] specificeert een benoemd beleid.

Het [EnableCors] kenmerk kan worden toegepast op:

  • Razor Bladzijde PageModel
  • Controleur
  • Controller-actiemethode

Verschillende beleidsregels kunnen worden toegepast op controllers, paginamodellen of actiemethoden met het [EnableCors] kenmerk. Wanneer het [EnableCors] kenmerk wordt toegepast op een controller, paginamodel of actiemethode en CORS is ingeschakeld in middleware, worden beide beleidsregels toegepast. Wij raden aan om beleidsregels niet te combineren. Gebruik de [EnableCors] kenmerk of middleware, niet beide in dezelfde app.

Met de volgende code wordt een ander beleid toegepast op elke methode:

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

Met de volgende code worden twee CORS-beleidsregels gemaakt:

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

Voor de beste controle over het beperken van CORS-aanvragen:

  • Gebruik [EnableCors("MyPolicy")] met een genaamd beleid.
  • Definieer geen standaardbeleid.
  • Gebruik geen eindpuntroutering.

De code in de volgende sectie voldoet aan de voorgaande lijst.

CORS uitschakelen

Het kenmerk [DisableCors] schakelt CORS die is ingeschakeld door eindpuntrouteringniet uit.

De volgende code definieert het CORS-beleid "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();

Met de volgende code wordt CORS uitgeschakeld voor de GetValues2 actie:

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

}

De voorgaande code:

Zie CORS testen voor instructies over het testen van de voorgaande code.

CORS-beleidsopties

In deze sectie worden de verschillende opties beschreven die kunnen worden ingesteld in een CORS-beleid:

AddPolicy wordt ingeroepen in Program.cs. Voor sommige opties kan het nuttig zijn om eerst de sectie Hoe CORS werkt te lezen.

De toegestane oorsprongen instellen

AllowAnyOrigin: Hiermee staat u CORS-aanvragen van alle oorsprongen toe met elk schema (http of https). AllowAnyOrigin is onveilig omdat elke website cross-origin aanvragen kan indienen bij de app.

Opmerking

Het opgeven van AllowAnyOrigin en AllowCredentials is een onveilige configuratie en leidt tot cross-site request-vervalsing. De CORS-service retourneert een ongeldig CORS-antwoord wanneer een app is geconfigureerd met beide methoden.

AllowAnyOrigin beïnvloedt preflight-aanvragen en de Access-Control-Allow-Origin-koptekst. Zie de sectie Voorbereidende aanvragen voor meer informatie.

SetIsOriginAllowedToAllowWildcardSubdomains: Hiermee stelt u de IsOriginAllowed eigenschap van het beleid in als een functie waarmee origins overeenkomen met een geconfigureerd wildcarddomein bij het evalueren of de oorsprong is toegestaan.

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

De toegestane HTTP-methoden instellen

AllowAnyMethod:

  • Hiermee staat u elke HTTP-methode toe:
  • Beïnvloedt voorbereidende aanvragen en de Access-Control-Allow-Methods-header. Zie de sectie Voorbereidende aanvragen voor meer informatie.

De toegestane aanvraagheaders instellen

Als u wilt toestaan dat specifieke headers worden verzonden in een CORS-aanvraag, genaamd headers van auteursaanvragen, roept WithHeaders u de toegestane headers aan en geeft u de toegestane headers op:

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

Als u alle auteursaanvraagheaders wilt toestaan, roept u het volgende AllowAnyHeaderaan:

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 beïnvloedt preflight-aanvragen en de Access-Control-Request-Headers-header. Zie de sectie Voorbereidende aanvragen voor meer informatie.

Een CORS Middleware-beleid matcht met specifieke headers gespecificeerd door WithHeaders alleen wanneer de headers in Access-Control-Request-Headers exact overeenkomen met de headers die zijn gespecificeerd in WithHeaders.

Denk bijvoorbeeld aan een app die als volgt is geconfigureerd:

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

CORS Middleware weigert een voorafgaande aanvraag met de volgende aanvraagheader omdat Content-Language (HeaderNames.ContentLanguage) niet wordt vermeld in WithHeaders:

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

De app retourneert een 200 OK-antwoord , maar stuurt de CORS-headers niet terug. Daarom probeert de browser de cross-origin-aanvraag niet uit te voeren.

De weergegeven antwoordheaders instellen

Standaard worden in de browser niet alle antwoordheaders voor de app weergegeven. Zie W3C Cross-Origin Resource Sharing (Terminologie): Simple Response Header voor meer informatie.

De antwoordheaders die standaard beschikbaar zijn, zijn:

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

De CORS-specificatie roept deze headers eenvoudige antwoordheaders aan. Als u andere headers beschikbaar wilt maken voor de app, roept u het volgende WithExposedHeadersaan:

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

Inloggegevens in cross-origin-aanvragen

Referenties vereisen speciale verwerking in een CORS-aanvraag. Standaard verzendt de browser geen inloggegevens met een cross-origin-aanvraag. Inloggegevens omvatten cookies en HTTP-authenticatieschema's. Om referenties met een cross-origin verzoek mee te sturen, moet de client XMLHttpRequest.withCredentials instellen op true.

Gebruik rechtstreeks XMLHttpRequest:

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

JQuery gebruiken:

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

De Fetch-API gebruiken:

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

De server moet de inloggegevens toestaan. Als u referenties voor meerdere oorsprongen wilt toestaan, roept u AllowCredentials op.

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

Het HTTP-antwoord bevat een Access-Control-Allow-Credentials header, waarmee de browser aangeeft dat de server referenties toestaat voor een cross-origin-aanvraag.

Als de browser referenties verzendt, maar het antwoord geen geldige Access-Control-Allow-Credentials header bevat, geeft de browser het antwoord niet beschikbaar aan de app en mislukt de cross-origin-aanvraag.

Het toestaan van cross-origin credentials is een beveiligingsrisico. Een website in een ander domein kan de referenties van een aangemelde gebruiker namens de gebruiker verzenden naar de app zonder dat de gebruiker dit weet.

De CORS-specificatie geeft ook aan dat het instellen van origins op "*" (alle origins) ongeldig is als de Access-Control-Allow-Credentials header aanwezig is.

Preflight-verzoeken

Voor sommige CORS-aanvragen verzendt de browser een extra OPTIONS-aanvraag voordat de werkelijke aanvraag wordt ingediend. Deze aanvraag wordt een voorbereidende aanvraag genoemd. De browser kan de voorbereidende aanvraag overslaan als aan alle volgende voorwaarden wordt voldaan:

  • De aanvraagmethode is GET, HEAD of POST.
  • De app stelt geen andere aanvraagheaders in dan Accept, Accept-Language, Content-Language, Content-Typeof Last-Event-ID.
  • De Content-Type header, indien ingesteld, heeft een van de volgende waarden:
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

De regel voor aanvraagheaders die zijn ingesteld voor de clientaanvraag is van toepassing op headers die door de app worden ingesteld door setRequestHeader aan te roepen op het XMLHttpRequest-object. De CORS-specificatie noemt deze headers auteursaanvraagheaders. De regel is niet van toepassing op headers die de browser kan instellen, zoals User-Agent, Hostof Content-Length.

Hier volgt een voorbeeld van een antwoord dat lijkt op het preflight-verzoek dat is gedaan via de knop [Put test] in de Test CORS sectie van dit document.

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

Het preflight-verzoek gebruikt de HTTP OPTIONS methode. Het kan de volgende headers bevatten:

Als de voorbereidende aanvraag wordt geweigerd, retourneert de app een 200 OK antwoord, maar de CORS-headers worden niet ingesteld. Daarom probeert de browser de cross-origin-aanvraag niet uit te voeren. Voor een voorbeeld van een geweigerde voorbereidende aanvraag, zie de sectie Test CORS van dit document.

Met de F12-hulpprogramma's wordt in de console-app een fout weergegeven die vergelijkbaar is met een van de volgende, afhankelijk van de browser:

  • Firefox: Cross-Origin-aanvraag geblokkeerd: de Same-Origin Policy staat het lezen van de externe resource op https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5 niet toe. (Reden: CORS-aanvraag is niet geslaagd). Meer informatie
  • Op basis van Chromium: Toegang tot het ophalen van 'https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5' vanaf oorsprong 'https://cors3.azurewebsites.net' is geblokkeerd door CORS-beleid: Reactie op preflight-verzoek voldoet niet aan de toegangscontrole: Er is geen 'Access-Control-Allow-Origin'-header aanwezig op de opgevraagde resource. Als een ondoorzichtig antwoord aan uw behoeften voldoet, stelt u de modus van de aanvraag in op 'no-cors' om de resource op te halen waarvoor CORS is uitgeschakeld.

Als u specifieke headers wilt toestaan, roept u het volgende aan 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();

Als u alle auteursaanvraagheaders wilt toestaan, roept u het volgende AllowAnyHeaderaan:

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

Browsers zijn niet consistent in de wijze waarop ze zijn ingesteld Access-Control-Request-Headers. Als een van beide:

  • Kopteksten zijn ingesteld op iets anders dan "*"
  • AllowAnyHeader wordt aangeroepen: neem ten minste Accept, Content-Typeen Originplus eventuele aangepaste headers op die u wilt ondersteunen.

Code voor automatische preflightaanvraag

Wanneer het CORS-beleid wordt toegepast, ofwel:

  • Wereldwijd door app.UseCors in Program.cs te bellen.
  • Gebruikmakend van het [EnableCors] kenmerk.

ASP.NET Core reageert op de preflight-OPTIES-aanvraag.

Het inschakelen van CORS per eindpunt RequireCors biedt momenteel geen ondersteuning voor automatische preflight-verzoeken.

In de sectie CORS testen van dit document ziet u dit gedrag.

Kenmerk [HttpOptions] voor preflightverzoeken

Wanneer CORS is ingeschakeld met het juiste beleid, reageert ASP.NET Core in het algemeen automatisch op CORS-voorbereidende aanvragen. In sommige scenario's is dit mogelijk niet het geval. Gebruik bijvoorbeeld CORS met eindpuntroutering.

De volgende code maakt gebruik van het kenmerk [HttpOptions] voor het maken van eindpunten voor OPTIONS-aanvragen:

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

Zie CORS testen met eindpuntroutering en [HttpOptions] voor instructies over het testen van de voorgaande code.

De verlooptijd van de voorbereidende fase instellen

De Access-Control-Max-Age header geeft aan hoe lang het antwoord op het preflight-verzoek in de cache kan worden opgeslagen. Als u deze header wilt instellen, roept u het volgende SetPreflightMaxAgeaan:

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

Hoe CORS werkt

In deze sectie wordt beschreven wat er gebeurt in een CORS-aanvraag op het niveau van de HTTP-berichten.

  • CORS is geen beveiligingsfunctie. CORS is een W3C-standaard waarmee een server hetzelfde origin-beleid kan versoepelen.
    • Een kwaadwillende actor kan bijvoorbeeld XSS (Cross-Site Scripting) gebruiken op uw site en een cross-site-aanvraag uitvoeren op hun CORS-site om informatie te stelen.
  • Een API is niet veiliger door CORS toe te staan.
    • Het is aan de client (browser) om CORS af te dwingen. De server voert de aanvraag uit en retourneert het antwoord, het is de client die een fout retourneert en het antwoord blokkeert. Met een van de volgende hulpprogramma's wordt bijvoorbeeld het serverantwoord weergegeven:
  • Het is een manier voor een server om browsers toe te staan een cross-origin XHR - of Fetch API-aanvraag uit te voeren die anders verboden zou zijn.
    • Browsers zonder CORS kunnen geen cross-origin-aanvragen uitvoeren. Vóór CORS werd JSONP gebruikt om deze beperking te omzeilen. JSONP gebruikt geen XHR, maar gebruikt de <script> tag om het antwoord te ontvangen. Scripts mogen cross-origin worden geladen.

De CORS-specificatie heeft verschillende nieuwe HTTP-headers geïntroduceerd die cross-origin-aanvragen mogelijk maken. Als een browser CORS ondersteunt, worden deze headers automatisch ingesteld voor cross-origin-aanvragen. Aangepaste JavaScript-code is niet vereist om CORS in te schakelen.

Dit is een voorbeeld van een cross-origin-aanvraag van de waardentest-knop naar https://cors1.azurewebsites.net/api/values. De Origin koptekst:

  • Geeft het domein van de site die het verzoek indient.
  • Is vereist en moet afwijken van de host.

Algemene headers

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

Antwoordheaders

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

Verzoekheaders

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

In OPTIONS aanvragen stelt de server de header AntwoordheadersAccess-Control-Allow-Origin: {allowed origin} in het antwoord in. Het geïmplementeerde voorbeeld, knopaanvraag OPTIONS Verwijderen, bevat bijvoorbeeld de volgende headers:

Algemene headers

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

Antwoordheaders

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

Verzoekheaders

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

In de voorgaande antwoordheaders stelt de server in het antwoord de header Access-Control-Allow-Origin in. De https://cors1.azurewebsites.net waarde van deze header komt overeen met de Origin header van de aanvraag.

Als AllowAnyOrigin wordt aangeroepen, wordt de Access-Control-Allow-Origin: *, de jokertekenwaarde, geretourneerd. AllowAnyOrigin staat elke oorsprong toe.

Als het antwoord de header niet bevat Access-Control-Allow-Origin , mislukt de cross-origin-aanvraag. De browser staat de aanvraag met name niet toe. Zelfs als de server een geslaagd antwoord retourneert, maakt de browser het antwoord niet beschikbaar voor de client-app.

HTTP-omleiding naar HTTPS veroorzaakt ERR_INVALID_REDIRECT op de preflight CORS-verzoek

Aanvragen naar een eindpunt met HTTP die door UseHttpsRedirection worden omgeleid naar HTTPS, mislukken met ERR_INVALID_REDIRECT on the CORS preflight request.

API-projecten kunnen HTTP-aanvragen weigeren in plaats van te gebruiken UseHttpsRedirection om aanvragen om te leiden naar HTTPS.

OPTIES-aanvragen weergeven

Standaard worden in de browsers Chrome en Edge geen OPTIES-aanvragen weergegeven op het netwerktabblad van de F12-hulpprogramma's. OPTIES-aanvragen weergeven in deze browsers:

  • chrome://flags/#out-of-blink-cors of edge://flags/#out-of-blink-cors
  • schakel de vlag uit.
  • herstarten.

In Firefox worden OPTIES-aanvragen standaard weergegeven.

CORS in IIS

Bij de implementatie in IIS moet CORS worden uitgevoerd vóór Windows-verificatie als de server niet is geconfigureerd om anonieme toegang toe te staan. Ter ondersteuning van dit scenario moet de IIS CORS-module worden geïnstalleerd en geconfigureerd voor de app.

CORS testen

Het voorbeelddownload bevat code om CORS te testen. Zie hoe ukunt downloaden. Het voorbeeld is een API-project met Razor Pages toegevoegd:

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

Waarschuwing

WithOrigins("https://localhost:<port>"); mag alleen worden gebruikt voor het testen van een voorbeeld-app die vergelijkbaar is met de voorbeeldcode voor het downloaden.

ValuesController Hieronder vindt u de eindpunten voor het testen:

[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 wordt geleverd door het Rick.Docs.Samples.RouteInfo NuGet-pakket en toont routegegevens.

Test de voorgaande voorbeeldcode met behulp van een van de volgende methoden:

  • Voer het voorbeeld uit met dotnet run behulp van de standaard-URL van https://localhost:5001.
  • Voer het voorbeeld uit vanuit Visual Studio met de poort ingesteld op 44398 voor een URL van https://localhost:44398.

Een browser gebruiken met de F12-hulpprogramma's:

  • Selecteer de knop Waarden en controleer de kopteksten op het tabblad Netwerk .

  • Selecteer de PUT-test knop. Zie WeergaveOPTIES-aanvragen voor instructies over het weergeven van de OPTIONS-aanvraag. De PUT-test maakt twee aanvragen, een OPTIONS preflight-aanvraag en een PUT-aanvraag.

  • Selecteer de GetValues2 [DisableCors] knop om een mislukte CORS-aanvraag te activeren. Zoals vermeld in het document, retourneert het antwoord 200 succes, maar wordt het CORS-verzoek niet gedaan. Selecteer het tabblad Console om de CORS-fout weer te geven. Afhankelijk van de browser wordt een fout weergegeven die lijkt op het volgende:

    Toegang voor het ophalen van 'https://cors1.azurewebsites.net/api/values/GetValues2' vanaf oorsprong 'https://cors3.azurewebsites.net' is geblokkeerd door het CORS-beleid: Er is geen 'Access-Control-Allow-Origin' header aanwezig op de aangevraagde resource. Als een ondoorzichtig antwoord aan uw behoeften voldoet, stelt u de modus van de aanvraag in op 'no-cors' om de resource op te halen waarvoor CORS is uitgeschakeld.

CORS-eindpunten kunnen worden getest met een hulpprogramma, zoals curl of Fiddler. Wanneer u een hulpprogramma gebruikt, moet de oorsprong van de aanvraag die is opgegeven door de Origin header verschillen van de host die de aanvraag ontvangt. Als de aanvraag niet cross-origin is op basis van de waarde van de Origin header:

  • Cors Middleware is niet nodig om de aanvraag te verwerken.
  • CORS-headers worden niet geretourneerd in het antwoord.

Met de volgende opdracht curl wordt een OPTIONS-aanvraag met informatie verzonden:

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

CORS testen met eindpuntroutering en [HttpOptions]

Het inschakelen van CORS per eindpunt RequireCors ondersteunt momenteel geen automatische preflight-aanvragen. Houd rekening met de volgende code die gebruikmaakt van eindpuntroutering om CORS in te schakelen:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy(name: "MyPolicy",
                policy =>
                {
                    policy.WithOrigins("http://example.com",
                        "http://www.contoso.com",
                        "https://cors1.azurewebsites.net",
                        "https://cors3.azurewebsites.net",
                        "https://localhost:44398",
                        "https://localhost:5001")
                            .WithMethods("PUT", "DELETE", "GET");
                });
});

builder.Services.AddControllers();
builder.Services.AddRazorPages();

var app = builder.Build();

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();

app.UseCors();

app.UseAuthorization();

app.MapControllers();
app.MapRazorPages();

app.Run();

TodoItems1Controller Hieronder vindt u eindpunten voor het testen:

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

Test de voorgaande code vanaf de testpagina (https://cors1.azurewebsites.net/test?number=1) van het geïmplementeerde voorbeeld.

De knoppen Delete [EnableCors] en GET [EnableCors] slagen, omdat de eindpunten [EnableCors] hebben voor preflight-aanvragen en daarop reageren. De andere eindpunten mislukken. De get-knop mislukt, omdat javaScript het volgende verzendt:

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

Het volgende TodoItems2Controller biedt vergelijkbare eindpunten, maar bevat expliciete code om te reageren op OPTIONS-aanvragen:

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

De voorgaande code kan worden getest door het voorbeeld te implementeren in Azure.In de vervolgkeuzelijst Controller , preflight te selecteren en vervolgens Controller in te stellen. Alle CORS-aanroepen naar de TodoItems2Controller eindpunten zijn geslaagd.

Aanvullende bronnen

Door Rick Anderson en Kirk Larkin

In dit artikel wordt beschreven hoe u CORS inschakelt in een ASP.NET Core-app.

Browserbeveiliging voorkomt dat een webpagina aanvragen indient naar een ander domein dan het domein dat de webpagina heeft geleverd. Deze beperking wordt het same-origin policy genoemd. Hetzelfde origin-beleid voorkomt dat een kwaadwillende site gevoelige gegevens van een andere site leest. Soms wilt u toestaan dat andere sites cross-origin-aanvragen indienen bij uw app. Zie het Mozilla CORS-artikel voor meer informatie.

Cross Origin Resource Sharing (CORS):

  • Is een W3C-standaard waarmee een server hetzelfde origin-beleid kan versoepelen.
  • Is geen beveiligingsfunctie, CORS maakt de beveiliging soepeler. Een API is niet veiliger door CORS toe te staan. Zie Hoe CORS werkt voor meer informatie.
  • Hiermee staat u een server toe om bepaalde cross-origin-aanvragen expliciet toe te staan terwijl andere aanvragen worden geweigerd.
  • Is veiliger en flexibeler dan eerdere technieken, zoals JSONP.

Voorbeeldcode bekijken of downloaden (hoe download je)

Dezelfde oorsprong

Twee URL's hebben dezelfde oorsprong als ze identieke schema's, hosts en poorten (RFC 6454) hebben.

Deze twee URL's hebben dezelfde oorsprong:

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

Deze URL's hebben verschillende oorsprongen dan de vorige twee URL's:

  • https://example.net: Ander domein
  • https://www.example.com/foo.html: Ander subdomein
  • http://example.com/foo.html: Verschillend schema
  • https://example.com:9000/foo.html: Andere poort

CORS inschakelen

Er zijn drie manieren om CORS in te schakelen:

Het gebruik van het kenmerk [EnableCors] met een benoemd beleid biedt het beste beheer voor het beperken van eindpunten die CORS ondersteunen.

Waarschuwing

UseCors moet in de juiste volgorde worden aangeroepen. Zie Middleware-bestelling voor meer informatie. Moet bijvoorbeeld UseCors worden aangeroepen voordat UseResponseCaching wanneer UseResponseCaching wordt gebruikt.

Elke benadering wordt in de volgende secties beschreven.

CORS met benoemd beleid en middleware

CORS Middleware verwerkt cross-origin-aanvragen. Met de volgende code wordt een CORS-beleid toegepast op alle eindpunten van de app met de opgegeven oorsprongen:

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

De voorgaande code:

Met eindpuntroutering moet de CORS-middleware worden geconfigureerd voor uitvoering tussen de aanroepen naar UseRouting en UseEndpoints.

Zie CORS testen voor instructies over het testen van code die vergelijkbaar is met de voorgaande code.

Met de AddCors methodeoproep worden CORS-services toegevoegd aan de servicecontainer van de app:

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

Zie CORS-beleidsopties in dit document voor meer informatie.

De CorsPolicyBuilder methoden kunnen worden gekoppeld, zoals wordt weergegeven in de volgende code:

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

Opmerking: de opgegeven URL mag geen afsluitende slash (/) bevatten. Als de URL eindigt met /, levert de vergelijking false op en wordt er geen header geretourneerd.

CORS met standaardbeleid en middleware

Met de volgende gemarkeerde code wordt het standaard CORS-beleid ingeschakeld:

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

Met de voorgaande code wordt het standaard CORS-beleid toegepast op alle controllereindpunten.

Cors met eindpuntroutering inschakelen

Het inschakelen van CORS per eindpunt RequireCors biedt geen ondersteuning voor automatische voorbereidende aanvragen. Zie dit GitHub-probleem en test CORS met eindpuntroutering en [HttpOptions]voor meer informatie.

Met eindpuntroutering kan CORS per eindpunt worden ingeschakeld met behulp van de RequireCors set extensiemethoden:

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

In de voorgaande code:

  • app.UseCors schakelt de CORS-middleware in. Omdat er geen standaardbeleid is geconfigureerd, maakt app.UseCors() alleen CORS niet mogelijk.
  • De /echo- en controle-eindpunten staan cross-origin-aanvragen toe met behulp van het opgegeven beleid.
  • De /echo2 en Razor Pagina-eindpunten staan geen cross-origin-aanvragen toe omdat er geen standaardbeleid is opgegeven.

Het kenmerk [DisableCors] schakelt niet de CORS uit die is ingeschakeld door eindpuntroutering met RequireCors.

Zie CORS testen met eindpuntroutering en [HttpOptions] voor instructies over het testen van code die vergelijkbaar is met de voorgaande.

CORS met kenmerken inschakelen

Het inschakelen van CORS met het kenmerk [EnableCors] en het toepassen van een benoemd beleid op alleen die eindpunten waarvoor CORS is vereist, biedt het beste beheer.

Het kenmerk [EnableCors] biedt een alternatief voor het wereldwijd toepassen van CORS. Met [EnableCors] het kenmerk wordt CORS ingeschakeld voor geselecteerde eindpunten, in plaats van alle eindpunten:

  • [EnableCors] hiermee geeft u het standaardbeleid.
  • [EnableCors("{Policy String}")] specificeert een benoemd beleid.

Het [EnableCors] kenmerk kan worden toegepast op:

  • Razor Bladzijde PageModel
  • Controleur
  • Controller-actiemethode

Verschillende beleidsregels kunnen worden toegepast op controllers, paginamodellen of actiemethoden met het [EnableCors] kenmerk. Wanneer het [EnableCors] kenmerk wordt toegepast op een controller, paginamodel of actiemethode en CORS is ingeschakeld in middleware, worden beide beleidsregels toegepast. Wij raden aan om beleidsregels niet te combineren. Gebruik de [EnableCors] kenmerk of middleware, niet beide in dezelfde app.

Met de volgende code wordt een ander beleid toegepast op elke methode:

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

Met de volgende code worden twee CORS-beleidsregels gemaakt:

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

Voor de beste controle over het beperken van CORS-aanvragen:

  • Gebruik [EnableCors("MyPolicy")] met een genaamd beleid.
  • Definieer geen standaardbeleid.
  • Gebruik geen eindpuntroutering.

De code in de volgende sectie voldoet aan de voorgaande lijst.

Zie CORS testen voor instructies over het testen van code die vergelijkbaar is met de voorgaande code.

CORS uitschakelen

Het kenmerk [DisableCors] schakelt CORS die is ingeschakeld door eindpuntrouteringniet uit.

De volgende code definieert het CORS-beleid "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();
        });
    }
}

Met de volgende code wordt CORS uitgeschakeld voor de GetValues2 actie:

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

}

De voorgaande code:

Zie CORS testen voor instructies over het testen van de voorgaande code.

CORS-beleidsopties

In deze sectie worden de verschillende opties beschreven die kunnen worden ingesteld in een CORS-beleid:

AddPolicy wordt ingeroepen in Startup.ConfigureServices. Voor sommige opties kan het nuttig zijn om eerst de sectie Hoe CORS werkt te lezen.

De toegestane oorsprongen instellen

AllowAnyOrigin: Hiermee staat u CORS-aanvragen van alle oorsprongen toe met elk schema (http of https). AllowAnyOrigin is onveilig omdat elke website cross-origin aanvragen kan indienen bij de app.

Opmerking

Het opgeven van AllowAnyOrigin en AllowCredentials is een onveilige configuratie en leidt tot cross-site request-vervalsing. De CORS-service retourneert een ongeldig CORS-antwoord wanneer een app is geconfigureerd met beide methoden.

AllowAnyOrigin beïnvloedt preflight-aanvragen en de Access-Control-Allow-Origin-koptekst. Zie de sectie Voorbereidende aanvragen voor meer informatie.

SetIsOriginAllowedToAllowWildcardSubdomains: Hiermee stelt u de IsOriginAllowed eigenschap van het beleid in als een functie waarmee origins overeenkomen met een geconfigureerd wildcarddomein bij het evalueren of de oorsprong is toegestaan.

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

De toegestane HTTP-methoden instellen

AllowAnyMethod:

  • Hiermee staat u elke HTTP-methode toe:
  • Beïnvloedt voorbereidende aanvragen en de Access-Control-Allow-Methods-header. Zie de sectie Voorbereidende aanvragen voor meer informatie.

De toegestane aanvraagheaders instellen

Als u wilt toestaan dat specifieke headers worden verzonden in een CORS-aanvraag, genaamd headers van auteursaanvragen, roept WithHeaders u de toegestane headers aan en geeft u de toegestane headers op:

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

Als u alle auteursaanvraagheaders wilt toestaan, roept u het volgende AllowAnyHeaderaan:

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

AllowAnyHeader beïnvloedt preflight-aanvragen en de Access-Control-Request-Headers-header. Zie de sectie Voorbereidende aanvragen voor meer informatie.

Een CORS Middleware-beleid matcht met specifieke headers gespecificeerd door WithHeaders alleen wanneer de headers in Access-Control-Request-Headers exact overeenkomen met de headers die zijn gespecificeerd in WithHeaders.

Denk bijvoorbeeld aan een app die als volgt is geconfigureerd:

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

CORS Middleware weigert een voorafgaande aanvraag met de volgende aanvraagheader omdat Content-Language (HeaderNames.ContentLanguage) niet wordt vermeld in WithHeaders:

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

De app retourneert een 200 OK-antwoord , maar stuurt de CORS-headers niet terug. Daarom probeert de browser de cross-origin-aanvraag niet uit te voeren.

De weergegeven antwoordheaders instellen

Standaard worden in de browser niet alle antwoordheaders voor de app weergegeven. Zie W3C Cross-Origin Resource Sharing (Terminologie): Simple Response Header voor meer informatie.

De antwoordheaders die standaard beschikbaar zijn, zijn:

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

De CORS-specificatie roept deze headers eenvoudige antwoordheaders aan. Als u andere headers beschikbaar wilt maken voor de app, roept u het volgende WithExposedHeadersaan:

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

Inloggegevens in cross-origin-aanvragen

Referenties vereisen speciale verwerking in een CORS-aanvraag. Standaard verzendt de browser geen inloggegevens met een cross-origin-aanvraag. Inloggegevens omvatten cookies en HTTP-authenticatieschema's. Om referenties met een cross-origin verzoek mee te sturen, moet de client XMLHttpRequest.withCredentials instellen op true.

Gebruik rechtstreeks XMLHttpRequest:

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

JQuery gebruiken:

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

De Fetch-API gebruiken:

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

De server moet de inloggegevens toestaan. Als u referenties voor meerdere oorsprongen wilt toestaan, roept u AllowCredentials op.

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

Het HTTP-antwoord bevat een Access-Control-Allow-Credentials header, waarmee de browser aangeeft dat de server referenties toestaat voor een cross-origin-aanvraag.

Als de browser referenties verzendt, maar het antwoord geen geldige Access-Control-Allow-Credentials header bevat, geeft de browser het antwoord niet beschikbaar aan de app en mislukt de cross-origin-aanvraag.

Het toestaan van cross-origin credentials is een beveiligingsrisico. Een website in een ander domein kan de referenties van een aangemelde gebruiker namens de gebruiker verzenden naar de app zonder dat de gebruiker dit weet.

De CORS-specificatie geeft ook aan dat het instellen van origins op "*" (alle origins) ongeldig is als de Access-Control-Allow-Credentials header aanwezig is.

Preflight-verzoeken

Voor sommige CORS-aanvragen verzendt de browser een extra OPTIONS-aanvraag voordat de werkelijke aanvraag wordt ingediend. Deze aanvraag wordt een voorbereidende aanvraag genoemd. De browser kan de voorbereidende aanvraag overslaan als aan alle volgende voorwaarden wordt voldaan:

  • De aanvraagmethode is GET, HEAD of POST.
  • De app stelt geen andere aanvraagheaders in dan Accept, Accept-Language, Content-Language, Content-Typeof Last-Event-ID.
  • De Content-Type header, indien ingesteld, heeft een van de volgende waarden:
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

De regel voor aanvraagheaders die zijn ingesteld voor de clientaanvraag is van toepassing op headers die door de app worden ingesteld door setRequestHeader aan te roepen op het XMLHttpRequest-object. De CORS-specificatie noemt deze headers auteursaanvraagheaders. De regel is niet van toepassing op headers die de browser kan instellen, zoals User-Agent, Hostof Content-Length.

Hier volgt een voorbeeld van een antwoord dat lijkt op het preflight-verzoek dat is gedaan via de knop [Put test] in de Test CORS sectie van dit document.

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

Het preflight-verzoek gebruikt de HTTP OPTIONS methode. Het kan de volgende headers bevatten:

Als de voorbereidende aanvraag wordt geweigerd, retourneert de app een 200 OK antwoord, maar de CORS-headers worden niet ingesteld. Daarom probeert de browser de cross-origin-aanvraag niet uit te voeren. Voor een voorbeeld van een geweigerde voorbereidende aanvraag, zie de sectie Test CORS van dit document.

Met de F12-hulpprogramma's wordt in de console-app een fout weergegeven die vergelijkbaar is met een van de volgende, afhankelijk van de browser:

  • Firefox: Cross-Origin-aanvraag geblokkeerd: de Same-Origin Policy staat het lezen van de externe resource op https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5 niet toe. (Reden: CORS-aanvraag is niet geslaagd). Meer informatie
  • Op basis van Chromium: Toegang tot het ophalen van 'https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5' vanaf oorsprong 'https://cors3.azurewebsites.net' is geblokkeerd door CORS-beleid: Reactie op preflight-verzoek voldoet niet aan de toegangscontrole: Er is geen 'Access-Control-Allow-Origin'-header aanwezig op de opgevraagde resource. Als een ondoorzichtig antwoord aan uw behoeften voldoet, stelt u de modus van de aanvraag in op 'no-cors' om de resource op te halen waarvoor CORS is uitgeschakeld.

Als u specifieke headers wilt toestaan, roept u het volgende aan WithHeaders:

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

Als u alle auteursaanvraagheaders wilt toestaan, roept u het volgende AllowAnyHeaderaan:

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

Browsers zijn niet consistent in de wijze waarop ze zijn ingesteld Access-Control-Request-Headers. Als een van beide:

  • Kopteksten zijn ingesteld op iets anders dan "*"
  • AllowAnyHeader wordt aangeroepen: neem ten minste Accept, Content-Typeen Originplus eventuele aangepaste headers op die u wilt ondersteunen.

Code voor automatische preflightaanvraag

Wanneer het CORS-beleid wordt toegepast, ofwel:

  • Wereldwijd door app.UseCors in Startup.Configure te bellen.
  • Gebruikmakend van het [EnableCors] kenmerk.

ASP.NET Core reageert op de preflight-OPTIES-aanvraag.

Het inschakelen van CORS per eindpunt RequireCors biedt momenteel geen ondersteuning voor automatische preflight-verzoeken.

In de sectie CORS testen van dit document ziet u dit gedrag.

Kenmerk [HttpOptions] voor preflightverzoeken

Wanneer CORS is ingeschakeld met het juiste beleid, reageert ASP.NET Core in het algemeen automatisch op CORS-voorbereidende aanvragen. In sommige scenario's is dit mogelijk niet het geval. Gebruik bijvoorbeeld CORS met eindpuntroutering.

De volgende code maakt gebruik van het kenmerk [HttpOptions] voor het maken van eindpunten voor OPTIONS-aanvragen:

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

Zie CORS testen met eindpuntroutering en [HttpOptions] voor instructies over het testen van de voorgaande code.

De verlooptijd van de voorbereidende fase instellen

De Access-Control-Max-Age header geeft aan hoe lang het antwoord op het preflight-verzoek in de cache kan worden opgeslagen. Als u deze header wilt instellen, roept u het volgende SetPreflightMaxAgeaan:

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

Hoe CORS werkt

In deze sectie wordt beschreven wat er gebeurt in een CORS-aanvraag op het niveau van de HTTP-berichten.

  • CORS is geen beveiligingsfunctie. CORS is een W3C-standaard waarmee een server hetzelfde origin-beleid kan versoepelen.
    • Een kwaadwillende actor kan bijvoorbeeld XSS (Cross-Site Scripting) gebruiken op uw site en een cross-site-aanvraag uitvoeren op hun CORS-site om informatie te stelen.
  • Een API is niet veiliger door CORS toe te staan.
    • Het is aan de client (browser) om CORS af te dwingen. De server voert de aanvraag uit en retourneert het antwoord, het is de client die een fout retourneert en het antwoord blokkeert. Met een van de volgende hulpprogramma's wordt bijvoorbeeld het serverantwoord weergegeven:
  • Het is een manier voor een server om browsers toe te staan een cross-origin XHR - of Fetch API-aanvraag uit te voeren die anders verboden zou zijn.
    • Browsers zonder CORS kunnen geen cross-origin-aanvragen uitvoeren. Vóór CORS werd JSONP gebruikt om deze beperking te omzeilen. JSONP gebruikt geen XHR, maar gebruikt de <script> tag om het antwoord te ontvangen. Scripts mogen cross-origin worden geladen.

De CORS-specificatie heeft verschillende nieuwe HTTP-headers geïntroduceerd die cross-origin-aanvragen mogelijk maken. Als een browser CORS ondersteunt, worden deze headers automatisch ingesteld voor cross-origin-aanvragen. Aangepaste JavaScript-code is niet vereist om CORS in te schakelen.

Dit is een voorbeeld van een cross-origin-aanvraag van de waardentest-knop naar https://cors1.azurewebsites.net/api/values. De Origin koptekst:

  • Geeft het domein van de site die het verzoek indient.
  • Is vereist en moet afwijken van de host.

Algemene headers

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

Antwoordheaders

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

Verzoekheaders

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

In OPTIONS aanvragen stelt de server de header AntwoordheadersAccess-Control-Allow-Origin: {allowed origin} in het antwoord in. Het geïmplementeerde voorbeeld, knopaanvraag OPTIONS Verwijderen, bevat bijvoorbeeld de volgende headers:

Algemene headers

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

Antwoordheaders

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

Verzoekheaders

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

In de voorgaande antwoordheaders stelt de server in het antwoord de header Access-Control-Allow-Origin in. De https://cors1.azurewebsites.net waarde van deze header komt overeen met de Origin header van de aanvraag.

Als AllowAnyOrigin wordt aangeroepen, wordt de Access-Control-Allow-Origin: *, de jokertekenwaarde, geretourneerd. AllowAnyOrigin staat elke oorsprong toe.

Als het antwoord de header niet bevat Access-Control-Allow-Origin , mislukt de cross-origin-aanvraag. De browser staat de aanvraag met name niet toe. Zelfs als de server een geslaagd antwoord retourneert, maakt de browser het antwoord niet beschikbaar voor de client-app.

OPTIES-aanvragen weergeven

Standaard worden in de browsers Chrome en Edge geen OPTIES-aanvragen weergegeven op het netwerktabblad van de F12-hulpprogramma's. OPTIES-aanvragen weergeven in deze browsers:

  • chrome://flags/#out-of-blink-cors of edge://flags/#out-of-blink-cors
  • schakel de vlag uit.
  • herstarten.

In Firefox worden OPTIES-aanvragen standaard weergegeven.

CORS in IIS

Bij de implementatie in IIS moet CORS worden uitgevoerd vóór Windows-verificatie als de server niet is geconfigureerd om anonieme toegang toe te staan. Ter ondersteuning van dit scenario moet de IIS CORS-module worden geïnstalleerd en geconfigureerd voor de app.

CORS testen

Het voorbeelddownload bevat code om CORS te testen. Zie hoe ukunt downloaden. Het voorbeeld is een API-project met Razor Pages toegevoegd:

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

Waarschuwing

WithOrigins("https://localhost:<port>"); mag alleen worden gebruikt voor het testen van een voorbeeld-app die vergelijkbaar is met de voorbeeldcode voor het downloaden.

ValuesController Hieronder vindt u de eindpunten voor het testen:

[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 wordt geleverd door het Rick.Docs.Samples.RouteInfo NuGet-pakket en toont routegegevens.

Test de voorgaande voorbeeldcode met behulp van een van de volgende methoden:

  • Voer het voorbeeld uit met dotnet run behulp van de standaard-URL van https://localhost:5001.
  • Voer het voorbeeld uit vanuit Visual Studio met de poort ingesteld op 44398 voor een URL van https://localhost:44398.

Een browser gebruiken met de F12-hulpprogramma's:

  • Selecteer de knop Waarden en controleer de kopteksten op het tabblad Netwerk .

  • Selecteer de PUT-test knop. Zie WeergaveOPTIES-aanvragen voor instructies over het weergeven van de OPTIONS-aanvraag. De PUT-test maakt twee aanvragen, een OPTIONS preflight-aanvraag en een PUT-aanvraag.

  • Selecteer de GetValues2 [DisableCors] knop om een mislukte CORS-aanvraag te activeren. Zoals vermeld in het document, retourneert het antwoord 200 succes, maar wordt het CORS-verzoek niet gedaan. Selecteer het tabblad Console om de CORS-fout weer te geven. Afhankelijk van de browser wordt een fout weergegeven die lijkt op het volgende:

    Toegang voor het ophalen van 'https://cors1.azurewebsites.net/api/values/GetValues2' vanaf oorsprong 'https://cors3.azurewebsites.net' is geblokkeerd door het CORS-beleid: Er is geen 'Access-Control-Allow-Origin' header aanwezig op de aangevraagde resource. Als een ondoorzichtig antwoord aan uw behoeften voldoet, stelt u de modus van de aanvraag in op 'no-cors' om de resource op te halen waarvoor CORS is uitgeschakeld.

CORS-eindpunten kunnen worden getest met een hulpprogramma, zoals curl of Fiddler. Wanneer u een hulpprogramma gebruikt, moet de oorsprong van de aanvraag die is opgegeven door de Origin header verschillen van de host die de aanvraag ontvangt. Als de aanvraag niet cross-origin is op basis van de waarde van de Origin header:

  • Cors Middleware is niet nodig om de aanvraag te verwerken.
  • CORS-headers worden niet geretourneerd in het antwoord.

Met de volgende opdracht curl wordt een OPTIONS-aanvraag met informatie verzonden:

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

CORS testen met eindpuntroutering en [HttpOptions]

Het inschakelen van CORS per eindpunt RequireCors ondersteunt momenteel geen automatische preflight-aanvragen. Houd rekening met de volgende code die gebruikmaakt van eindpuntroutering om CORS in te schakelen:

public class StartupEndPointBugTest
{
    readonly string MyPolicy = "_myPolicy";

    // .WithHeaders(HeaderNames.ContentType, "x-custom-header")
    // forces browsers to require a preflight request with GET

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddCors(options =>
        {
            options.AddPolicy(name: MyPolicy,
                policy =>
                {
                    policy.WithOrigins("http://example.com",
                                        "http://www.contoso.com",
                                        "https://cors1.azurewebsites.net",
                                        "https://cors3.azurewebsites.net",
                                        "https://localhost:44398",
                                        "https://localhost:5001")
                           .WithHeaders(HeaderNames.ContentType, "x-custom-header")
                           .WithMethods("PUT", "DELETE", "GET", "OPTIONS");
                });
        });

        services.AddControllers();
        services.AddRazorPages();
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        app.UseHttpsRedirection();
        app.UseStaticFiles();
        app.UseRouting();

        app.UseCors();

        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers().RequireCors(MyPolicy);
            endpoints.MapRazorPages();
        });
    }
}

TodoItems1Controller Hieronder vindt u eindpunten voor het testen:

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

Test de voorgaande code vanaf de testpagina (https://cors1.azurewebsites.net/test?number=1) van het geïmplementeerde voorbeeld.

De knoppen Delete [EnableCors] en GET [EnableCors] slagen, omdat de eindpunten [EnableCors] hebben voor preflight-aanvragen en daarop reageren. De andere eindpunten mislukken. De get-knop mislukt, omdat javaScript het volgende verzendt:

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

Het volgende TodoItems2Controller biedt vergelijkbare eindpunten, maar bevat expliciete code om te reageren op OPTIONS-aanvragen:

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

De voorgaande code kan worden getest door het voorbeeld te implementeren in Azure.In de vervolgkeuzelijst Controller , preflight te selecteren en vervolgens Controller in te stellen. Alle CORS-aanroepen naar de TodoItems2Controller eindpunten zijn geslaagd.

Aanvullende bronnen