Mengaktifkan Permintaan Lintas-Asal (CORS) di ASP.NET Core 1.0

Catatan

Ini bukan versi terbaru dari artikel ini. Untuk rilis saat ini, lihat versi .NET 8 dari artikel ini.

Penting

Informasi ini berkaitan dengan produk pra-rilis yang mungkin dimodifikasi secara substansial sebelum dirilis secara komersial. Microsoft tidak memberikan jaminan, tersirat maupun tersurat, sehubungan dengan informasi yang diberikan di sini.

Untuk rilis saat ini, lihat versi .NET 8 dari artikel ini.

Oleh Rick Anderson dan Kirk Larkin

Artikel ini menunjukkan bagaimana Cross-O rigin Resource Sharing (CORS) diaktifkan di aplikasi ASP.NET Core.

Keamanan browser mencegah halaman web membuat permintaan ke domain yang berbeda dari yang melayani halaman web. Pembatasan ini disebut kebijakan asal yang sama. Pembatasan ini disebut kebijakan asal yang sama, dan mencegah situs yang berbahaya membaca data yang bersifat sensitif dari situs lain. Terkadang, Anda mungkin ingin mengizinkan situs lain membuat permintaan lintas asal ke aplikasi Anda. Untuk informasi selengkapnya, lihat artikel Mozilla CORS.

Berbagi Sumber Daya Lintas Asal (CORS):

  • Adalah standar W3C yang memungkinkan server untuk melonggarkan kebijakan asal yang sama.
  • Bukan fitur keamanan, CORS melonggarkan keamanan. API tidak lebih aman dengan mengizinkan CORS. Untuk informasi selengkapnya, lihat Cara kerja CORS.
  • Memungkinkan server untuk secara eksplisit mengizinkan beberapa permintaan lintas asal sambil menolak yang lain.
  • Lebih aman dan fleksibel daripada teknik sebelumnya, seperti JSONP.

Melihat atau mengunduh kode sampel (cara mengunduh)

Asal yang sama

Dua URL memiliki asal yang sama jika memiliki skema, host, dan port yang identik (RFC 6454).

Kedua URL ini memiliki asal yang sama:

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

URL ini memiliki asal yang berbeda dari dua URL sebelumnya:

  • https://example.net: Domain yang berbeda
  • https://www.example.com/foo.html: Subdomain yang berbeda
  • http://example.com/foo.html: Skema yang berbeda
  • https://example.com:9000/foo.html: Port yang berbeda

Mengaktifkan CORS

Ada tiga cara untuk mengaktifkan CORS:

Menggunakan atribut [EnableCors] dengan kebijakan bernama memberikan kontrol terbaik dalam membatasi titik akhir yang mendukung CORS.

Peringatan

UseCors harus dipanggil dalam urutan yang benar. Untuk informasi selengkapnya, lihat Pesanan Middleware. Misalnya, UseCors harus dipanggil sebelumnya UseResponseCaching saat menggunakan UseResponseCaching.

Setiap pendekatan dirinci di bagian berikut.

CORS dengan kebijakan dan middleware bernama

CORS Middleware menangani permintaan lintas asal. Kode berikut menerapkan kebijakan CORS ke semua titik akhir aplikasi dengan asal yang ditentukan:

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

Kode sebelumnya:

  • Mengatur nama kebijakan ke _myAllowSpecificOrigins. Nama kebijakan bersifat arbitrer.
  • UseCors Memanggil metode ekstensi dan menentukan _myAllowSpecificOrigins kebijakan CORS. UseCors menambahkan middleware CORS. Panggilan ke UseCors harus ditempatkan setelah UseRouting, tetapi sebelum UseAuthorization. Untuk informasi selengkapnya, lihat Pesanan Middleware.
  • AddCors Panggilan dengan ekspresi lambda. Lambda mengambil CorsPolicyBuilder objek. Opsi konfigurasi, seperti WithOrigins, dijelaskan nanti dalam artikel ini.
  • _myAllowSpecificOrigins Mengaktifkan kebijakan CORS untuk semua titik akhir pengontrol. Lihat perutean titik akhir untuk menerapkan kebijakan CORS ke titik akhir tertentu.
  • Saat menggunakan Middleware Penembolokan Respons, hubungi UseCors sebelum UseResponseCaching.

Dengan perutean titik akhir, middleware CORS harus dikonfigurasi untuk dijalankan antara panggilan ke UseRouting dan UseEndpoints.

Lihat Menguji CORS untuk petunjuk tentang kode pengujian yang mirip dengan kode sebelumnya.

Panggilan AddCors metode menambahkan layanan CORS ke kontainer layanan aplikasi:

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

Untuk informasi selengkapnya, lihat opsi kebijakan CORS dalam dokumen ini.

Metode CorsPolicyBuilder dapat ditautkan, seperti yang ditunjukkan dalam kode berikut:

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

Catatan: URL yang ditentukan tidak boleh berisi garis miring berikutnya (/). Jika URL berakhir dengan /, perbandingan false akan kembali dan tidak ada header yang dikembalikan.

Urutan UseCors dan UseStaticFiles

Biasanya, UseStaticFiles dipanggil sebelum UseCors. Aplikasi yang menggunakan JavaScript untuk mengambil file statis lintas situs harus memanggil UseCors sebelum UseStaticFiles.

CORS dengan kebijakan default dan middleware

Kode yang disorot berikut memungkinkan kebijakan CORS default:

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

Kode sebelumnya menerapkan kebijakan CORS default ke semua titik akhir pengontrol.

Mengaktifkan Cors dengan perutean titik akhir

Dengan perutean titik akhir, CORS dapat diaktifkan berdasarkan per titik akhir menggunakan RequireCors serangkaian metode ekstensi:

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

Dalam kode sebelumnya:

  • app.UseCors mengaktifkan middleware CORS. Karena kebijakan default belum dikonfigurasi, app.UseCors() saja tidak mengaktifkan CORS.
  • /echo Titik akhir pengontrol dan memungkinkan permintaan lintas asal menggunakan kebijakan yang ditentukan.
  • /echo2 Titik akhir Halaman dan Razor tidak mengizinkan permintaan lintas asal karena tidak ada kebijakan default yang ditentukan.

Atribut [DisableCors] tidak menonaktifkan CORS yang telah diaktifkan oleh perutean titik akhir dengan RequireCors.

Lihat Menguji CORS dengan atribut [EnableCors] dan metode RequireCors untuk petunjuk tentang kode pengujian yang mirip dengan sebelumnya.

Mengaktifkan CORS dengan atribut

Mengaktifkan CORS dengan atribut [EnableCors] dan menerapkan kebijakan bernama hanya ke titik akhir yang memerlukan CORS memberikan kontrol terbaik.

Atribut [EnableCors] menyediakan alternatif untuk menerapkan CORS secara global. Atribut [EnableCors] ini memungkinkan CORS untuk titik akhir yang dipilih, bukan semua titik akhir:

  • [EnableCors] menentukan kebijakan default.
  • [EnableCors("{Policy String}")] menentukan kebijakan bernama.

Atribut [EnableCors] dapat diterapkan ke:

  • Razor Halaman PageModel
  • Pengontrol
  • Metode tindakan pengontrol

Kebijakan yang berbeda dapat diterapkan ke pengontrol, model halaman, atau metode tindakan dengan [EnableCors] atribut . [EnableCors] Saat atribut diterapkan ke pengontrol, model halaman, atau metode tindakan, dan CORS diaktifkan di middleware, kedua kebijakan diterapkan. Sebaiknya jangan menggabungkan kebijakan. Gunakan [EnableCors]atribut atau middleware, bukan keduanya di aplikasi yang sama.

Kode berikut menerapkan kebijakan yang berbeda untuk setiap metode:

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

Kode berikut membuat dua kebijakan CORS:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy("Policy1",
        policy =>
        {
            policy.WithOrigins("http://example.com",
                                "http://www.contoso.com");
        });

    options.AddPolicy("AnotherPolicy",
        policy =>
        {
            policy.WithOrigins("http://www.contoso.com")
                                .AllowAnyHeader()
                                .AllowAnyMethod();
        });
});

builder.Services.AddControllers();

var app = builder.Build();

app.UseHttpsRedirection();

app.UseRouting();

app.UseCors();

app.UseAuthorization();

app.MapControllers();

app.Run();

Untuk kontrol terbaik membatasi permintaan CORS:

  • Gunakan [EnableCors("MyPolicy")] dengan kebijakan bernama.
  • Jangan tentukan kebijakan default.
  • Jangan gunakan perutean titik akhir.

Kode di bagian berikutnya memenuhi daftar sebelumnya.

Lihat Menguji CORS untuk petunjuk tentang kode pengujian yang mirip dengan kode sebelumnya.

Menonaktifkan CORS

Atribut [DisableCors] tidak menonaktifkan CORS yang telah diaktifkan oleh perutean titik akhir.

Kode berikut mendefinisikan kebijakan "MyPolicy"CORS :

var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy(name: "MyPolicy",
        policy =>
        {
            policy.WithOrigins("http://example.com",
                                "http://www.contoso.com")
                    .WithMethods("PUT", "DELETE", "GET");
        });
});

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

var app = builder.Build();

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

app.UseCors();

app.UseAuthorization();

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

app.Run();

Kode berikut menonaktifkan CORS untuk tindakan:GetValues2

[EnableCors("MyPolicy")]
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
    // GET api/values
    [HttpGet]
    public IActionResult Get() =>
        ControllerContext.MyDisplayRouteInfo();

    // GET api/values/5
    [HttpGet("{id}")]
    public IActionResult Get(int id) =>
        ControllerContext.MyDisplayRouteInfo(id);

    // PUT api/values/5
    [HttpPut("{id}")]
    public IActionResult Put(int id) =>
        ControllerContext.MyDisplayRouteInfo(id);


    // GET: api/values/GetValues2
    [DisableCors]
    [HttpGet("{action}")]
    public IActionResult GetValues2() =>
        ControllerContext.MyDisplayRouteInfo();

}

Kode sebelumnya:

Lihat Menguji CORS untuk petunjuk tentang menguji kode sebelumnya.

Opsi kebijakan CORS

Bagian ini menjelaskan berbagai opsi yang dapat diatur dalam kebijakan CORS:

AddPolicy dipanggil dalam Program.cs. Untuk beberapa opsi, mungkin berguna untuk membaca bagian Cara kerja CORS terlebih dahulu.

Mengatur asal yang diizinkan

AllowAnyOrigin: Memungkinkan permintaan CORS dari semua asal dengan skema apa pun (http atau https). AllowAnyOrigin tidak aman karena situs web apa pun dapat membuat permintaan lintas asal ke aplikasi.

Catatan

Menentukan AllowAnyOrigin dan AllowCredentials adalah konfigurasi tidak aman dan dapat mengakibatkan pemalsuan permintaan antarsitus. Layanan CORS mengembalikan respons CORS yang tidak valid saat aplikasi dikonfigurasi dengan kedua metode.

AllowAnyOrigin mempengaruhi permintaan preflight dan Access-Control-Allow-Origin header. Untuk informasi selengkapnya, lihat bagian Permintaan preflight.

SetIsOriginAllowedToAllowWildcardSubdomains: Mengatur IsOriginAllowed properti kebijakan menjadi fungsi yang memungkinkan asal untuk mencocokkan domain wildcard yang dikonfigurasi saat mengevaluasi apakah asal diizinkan.

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

Mengatur metode HTTP yang diizinkan

AllowAnyMethod:

  • Mengizinkan metode HTTP apa pun:
  • Mempengaruhi permintaan preflight dan Access-Control-Allow-Methods header. Untuk informasi selengkapnya, lihat bagian Permintaan preflight.

Mengatur header permintaan yang diizinkan

Untuk mengizinkan header tertentu dikirim dalam permintaan CORS, yang disebut header permintaan penulis, panggil WithHeaders dan tentukan header yang diizinkan:

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

Untuk mengizinkan semua header permintaan penulis, panggil AllowAnyHeader:

var MyAllowSpecificOrigins = "_MyAllowSubdomainPolicy";

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy(name: MyAllowSpecificOrigins,
        policy =>
        {
            policy.WithOrigins("https://*.example.com")
                   .AllowAnyHeader();
        });
});

builder.Services.AddControllers();

var app = builder.Build();

AllowAnyHeader memengaruhi permintaan preflight dan header Access-Control-Request-Headers . Untuk informasi selengkapnya, lihat bagian Permintaan preflight.

Kebijakan MIDDLEware CORS cocok dengan WithHeaders header tertentu yang ditentukan hanya dimungkinkan ketika header yang dikirim Access-Control-Request-Headers sama persis dengan header yang dinyatakan dalam WithHeaders.

Misalnya, pertimbangkan aplikasi yang dikonfigurasi sebagai berikut:

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

CORS Middleware menolak permintaan preflight dengan header permintaan berikut karena Content-Language (HeaderNames.ContentLanguage) tidak tercantum dalam WithHeaders:

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

Aplikasi mengembalikan respons 200 OK tetapi tidak mengirim header CORS kembali. Oleh karena itu, browser tidak mencoba permintaan lintas asal.

Mengatur header respons yang diekspos

Secara default, browser tidak mengekspos semua header respons ke aplikasi. Untuk informasi selengkapnya, lihat Berbagi Sumber Daya Lintas Asal W3C (Terminologi): Header Respons Sederhana.

Header respons yang tersedia secara default adalah:

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

Spesifikasi CORS memanggil header ini header respons sederhana. Untuk membuat header lain tersedia untuk aplikasi, panggil WithExposedHeaders:

var builder = WebApplication.CreateBuilder(args);

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

builder.Services.AddControllers();

var app = builder.Build();

Kredensial dalam permintaan lintas asal

Kredensial memerlukan penanganan khusus dalam permintaan CORS. Secara default, browser tidak mengirim kredensial dengan permintaan lintas asal. Kredensial termasuk cookies dan skema autentikasi HTTP. Untuk mengirim kredensial dengan permintaan lintas asal, klien harus mengatur XMLHttpRequest.withCredentials ke true.

Menggunakan XMLHttpRequest secara langsung:

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

Menggunakan jQuery:

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

Menggunakan Fetch API:

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

Server harus memperbolehkan kredensial. Untuk mengizinkan kredensial lintas asal, panggil AllowCredentials:

var builder = WebApplication.CreateBuilder(args);

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

builder.Services.AddControllers();

var app = builder.Build();

Respons HTTP menyertakan Access-Control-Allow-Credentials header, yang memberi tahu browser bahwa server mengizinkan kredensial untuk permintaan lintas asal.

Jika browser mengirim kredensial tetapi respons tidak menyertakan header yang valid Access-Control-Allow-Credentials , browser tidak mengekspos respons ke aplikasi, dan permintaan lintas asal gagal.

Mengizinkan kredensial lintas asal adalah risiko keamanan. Situs web di domain lain dapat mengirim kredensial pengguna yang masuk ke aplikasi atas nama pengguna tanpa sepengetahuan pengguna.

Spesifikasi CORS juga menyatakan bahwa pengaturan asal ke "*" (semua asal) tidak valid jika Access-Control-Allow-Credentials header ada.

Permintaan preflight

Untuk beberapa permintaan CORS, browser mengirimkan permintaan OPTIONS tambahan sebelum membuat permintaan aktual. Permintaan ini disebut permintaan preflight. Browser dapat melewati permintaan preflight jika semua kondisi berikut ini benar:

  • Metode permintaan adalah GET, HEAD, atau POST.
  • Aplikasi ini tidak mengatur header permintaan selain Accept, , Accept-Language, Content-LanguageContent-Type, atau Last-Event-ID.
  • Header Content-Type , jika diatur, memiliki salah satu nilai berikut:
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

Aturan pada header permintaan yang ditetapkan untuk permintaan klien berlaku untuk header yang ditetapkan aplikasi dengan memanggil setRequestHeaderXMLHttpRequest objek. Spesifikasi CORS memanggil header ini menulis header permintaan header. Aturan tidak berlaku untuk header yang dapat diatur browser, seperti User-Agent, , Hostatau Content-Length.

Berikut ini adalah contoh respons yang mirip dengan permintaan preflight yang dibuat dari tombol [Letakkan uji] di bagian Uji CORS dari dokumen ini.

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

Permintaan preflight menggunakan metode HTTP OPTIONS . Ini mungkin termasuk header berikut:

Jika permintaan preflight ditolak, aplikasi mengembalikan 200 OK respons tetapi tidak mengatur header CORS. Oleh karena itu, browser tidak mencoba permintaan lintas asal. Untuk contoh permintaan preflight yang ditolak, lihat bagian Uji CORS dari dokumen ini.

Dengan menggunakan alat F12, aplikasi konsol menampilkan kesalahan yang mirip dengan salah satu hal berikut, tergantung pada browser:

  • Firefox: Permintaan Lintas Asal Diblokir: Kebijakan Asal yang Sama melarang membaca sumber daya jarak jauh di https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5. (Alasan: Permintaan CORS tidak berhasil). Pelajari Selengkapnya
  • Berbasis Chromium: Akses untuk mengambil di 'https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5' dari asal 'https://cors3.azurewebsites.net' telah diblokir oleh kebijakan CORS: Respons terhadap permintaan preflight tidak melewati pemeriksaan kontrol akses: Tidak ada header 'Access-Control-Allow-Origin' yang ada di sumber daya yang diminta. Jika respons buram melayani kebutuhan Anda, atur mode permintaan ke 'tanpa cor' untuk mengambil sumber daya dengan CORS dinonaktifkan.

Untuk mengizinkan header tertentu, panggil 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();

Untuk mengizinkan semua header permintaan penulis, panggil AllowAnyHeader:

using Microsoft.Net.Http.Headers;

var builder = WebApplication.CreateBuilder(args);

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

builder.Services.AddControllers();

var app = builder.Build();

Browser tidak konsisten dalam cara mereka mengatur Access-Control-Request-Headers. Jika:

  • Header diatur ke apa pun selain "*"
  • AllowAnyHeader dipanggil: Sertakan setidaknya Accept, , Content-Typedan Origin, ditambah header kustom apa pun yang ingin Anda dukung.

Kode permintaan preflight otomatis

Ketika kebijakan CORS diterapkan:

  • Secara global dengan memanggil app.UseCors di Program.cs.
  • [EnableCors] Menggunakan atribut .

ASP.NET Core merespons permintaan OPTIONS preflight.

Bagian Uji CORS dari dokumen ini menunjukkan perilaku ini.

Atribut [HttpOptions] untuk permintaan preflight

Ketika CORS diaktifkan dengan kebijakan yang sesuai, ASP.NET Core umumnya merespons permintaan preflight CORS secara otomatis.

Kode berikut menggunakan atribut [HttpOptions] untuk membuat titik akhir untuk permintaan OPTIONS:

[Route("api/[controller]")]
[ApiController]
public class TodoItems2Controller : ControllerBase
{
    // OPTIONS: api/TodoItems2/5
    [HttpOptions("{id}")]
    public IActionResult PreflightRoute(int id)
    {
        return NoContent();
    }

    // OPTIONS: api/TodoItems2 
    [HttpOptions]
    public IActionResult PreflightRoute()
    {
        return NoContent();
    }

    [HttpPut("{id}")]
    public IActionResult PutTodoItem(int id)
    {
        if (id < 1)
        {
            return BadRequest();
        }

        return ControllerContext.MyDisplayRouteInfo(id);
    }

Lihat Menguji CORS dengan atribut [EnableCors] dan metode RequireCors untuk petunjuk tentang menguji kode sebelumnya.

Mengatur waktu kedaluwarsa preflight

Header Access-Control-Max-Age menentukan berapa lama respons terhadap permintaan preflight dapat di-cache. Untuk mengatur header ini, panggil SetPreflightMaxAge:

var builder = WebApplication.CreateBuilder(args);

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

builder.Services.AddControllers();

var app = builder.Build();

Mengaktifkan CORS pada titik akhir

Cara kerja CORS

Bagian ini menjelaskan apa yang terjadi dalam permintaan CORS di tingkat pesan HTTP.

  • CORS bukan fitur keamanan. CORS adalah standar W3C yang memungkinkan server untuk melonggarkan kebijakan asal yang sama.
    • Misalnya, aktor jahat dapat menggunakan Scripting Lintas Situs (XSS) terhadap situs Anda dan menjalankan permintaan lintas situs ke situs cors yang diaktifkan untuk mencuri informasi.
  • API tidak lebih aman dengan mengizinkan CORS.
    • Terserah klien (browser) untuk memberlakukan CORS. Server menjalankan permintaan dan mengembalikan respons, itu adalah klien yang mengembalikan kesalahan dan memblokir respons. Misalnya, salah satu alat berikut akan menampilkan respons server:
  • Ini adalah cara bagi server untuk memungkinkan browser menjalankan permintaan XHR lintas asal atau Fetch API yang jika tidak akan dilarang.
    • Browser tanpa CORS tidak dapat melakukan permintaan lintas asal. Sebelum CORS, JSONP digunakan untuk menghindari pembatasan ini. JSONP tidak menggunakan XHR, menggunakan <script> tag untuk menerima respons. Skrip diizinkan untuk dimuat lintas asal.

Spesifikasi CORS memperkenalkan beberapa header HTTP baru yang mengaktifkan permintaan lintas asal. Jika browser mendukung CORS, ia mengatur header ini secara otomatis untuk permintaan lintas asal. Kode JavaScript kustom tidak diperlukan untuk mengaktifkan CORS.

Tombol uji PUT pada sampel yang disebarkan

Berikut ini adalah contoh permintaan lintas asal dari tombol Uji nilai ke https://cors1.azurewebsites.net/api/values. Header Origin :

  • Menyediakan domain situs yang membuat permintaan.
  • Diperlukan dan harus berbeda dari host.

Header umum

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

Header respons

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

Header permintaan

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

Dalam OPTIONS permintaan, server mengatur header ResponsAccess-Control-Allow-Origin: {allowed origin} dalam respons. Misalnya, sampel yang disebarkan, Permintaan tombol OPTIONS Hapus [EnableCors] berisi header berikut:

Header umum

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

Header respons

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

Header permintaan

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

Di header Respons sebelumnya, server mengatur header Access-Control-Allow-Origin dalam respons. Nilai https://cors1.azurewebsites.net header ini cocok dengan Origin header dari permintaan.

Jika AllowAnyOrigin dipanggil, Access-Control-Allow-Origin: *nilai kartubebas, dikembalikan. AllowAnyOrigin memungkinkan asal apa pun.

Jika respons tidak menyertakan Access-Control-Allow-Origin header, permintaan lintas asal gagal. Secara khusus, browser melarang permintaan. Bahkan jika server mengembalikan respons yang berhasil, browser tidak membuat respons tersedia untuk aplikasi klien.

Pengalihan HTTP ke HTTPS menyebabkan ERR_INVALID_REDIRECT pada permintaan preflight CORS

Permintaan ke titik akhir menggunakan HTTP yang dialihkan ke HTTPS dengan UseHttpsRedirection gagal dengan ERR_INVALID_REDIRECT on the CORS preflight request.

Proyek API dapat menolak permintaan HTTP daripada menggunakan UseHttpsRedirection untuk mengalihkan permintaan ke HTTPS.

CORS di IIS

Saat menyebarkan ke IIS, CORS harus berjalan sebelum Autentikasi Windows jika server tidak dikonfigurasi untuk mengizinkan akses anonim. Untuk mendukung skenario ini, modul IIS CORS perlu diinstal dan dikonfigurasi untuk aplikasi.

Uji CORS

Unduhan sampel memiliki kode untuk menguji CORS. Lihat cara mengunduh. Sampel adalah proyek API dengan Razor Pages ditambahkan:

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

Peringatan

WithOrigins("https://localhost:<port>");hanya boleh digunakan untuk menguji aplikasi sampel yang mirip dengan kode sampel unduhan.

Berikut ini ValuesController menyediakan titik akhir untuk pengujian:

[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 disediakan oleh paket Rick.Docs.Samples.RouteInfo NuGet dan menampilkan informasi rute.

Uji kode sampel sebelumnya dengan menggunakan salah satu pendekatan berikut:

  • Gunakan aplikasi sampel yang disebarkan di https://cors3.azurewebsites.net/. Tidak perlu mengunduh sampel.
  • Jalankan sampel dengan dotnet run menggunakan URL https://localhost:5001default .
  • Jalankan sampel dari Visual Studio dengan port diatur ke 44398 untuk URL https://localhost:44398.

Menggunakan browser dengan alat F12:

  • Pilih tombol Nilai dan tinjau header di tab Jaringan .

  • Pilih tombol uji PUT. Lihat Menampilkan permintaan OPTIONS untuk instruksi tentang menampilkan permintaan OPTIONS. Pengujian PUT membuat dua permintaan, permintaan preflight OPTIONS dan permintaan PUT.

  • Pilih tombol GetValues2 [DisableCors] untuk memicu permintaan CORS yang gagal. Seperti disebutkan dalam dokumen, respons mengembalikan 200 keberhasilan, tetapi permintaan CORS tidak dibuat. Pilih tab Konsol untuk melihat kesalahan CORS. Bergantung pada browser, kesalahan yang mirip dengan yang berikut ini ditampilkan:

    Akses untuk mengambil dari asal 'https://cors3.azurewebsites.net' telah diblokir 'https://cors1.azurewebsites.net/api/values/GetValues2' oleh kebijakan CORS: Tidak ada header 'Access-Control-Allow-Origin' yang ada di sumber daya yang diminta. Jika respons buram melayani kebutuhan Anda, atur mode permintaan ke 'tanpa cor' untuk mengambil sumber daya dengan CORS dinonaktifkan.

Titik akhir dengan dukungan CORS dapat diuji dengan alat, seperti curl atau Fiddler. Saat menggunakan alat, asal permintaan yang ditentukan oleh Origin header harus berbeda dari host yang menerima permintaan. Jika permintaan tidak berasal dari silang berdasarkan nilai Origin header:

  • Cors Middleware tidak perlu memproses permintaan.
  • Header CORS tidak dikembalikan dalam respons.

Perintah berikut menggunakan curl untuk mengeluarkan permintaan OPTIONS dengan informasi:

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

Uji CORS dengan atribut [EnableCors] dan metode RequireCors

Pertimbangkan kode berikut yang menggunakan perutean titik akhir untuk mengaktifkan CORS berdasarkan per titik akhir menggunakan 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();

Perhatikan bahwa hanya /echo titik akhir yang RequireCors menggunakan untuk mengizinkan permintaan lintas asal menggunakan kebijakan yang ditentukan. Pengontrol di bawah ini mengaktifkan CORS menggunakan atribut [EnableCors].

Berikut ini TodoItems1Controller menyediakan titik akhir untuk pengujian:

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

Uji kode sebelumnya dari halaman pengujian sampel yang disebarkan.

Tombol Hapus [EnableCors] dan GET [EnableCors] berhasil, karena titik akhir memiliki [EnableCors] dan merespons permintaan preflight. Titik akhir lainnya gagal. Tombol GET gagal, karena JavaScript mengirimkan:

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

Berikut ini TodoItems2Controller menyediakan titik akhir serupa, tetapi menyertakan kode eksplisit untuk merespons permintaan OPTIONS:

[Route("api/[controller]")]
[ApiController]
public class TodoItems2Controller : ControllerBase
{
    // OPTIONS: api/TodoItems2/5
    [HttpOptions("{id}")]
    public IActionResult PreflightRoute(int id)
    {
        return NoContent();
    }

    // OPTIONS: api/TodoItems2 
    [HttpOptions]
    public IActionResult PreflightRoute()
    {
        return NoContent();
    }

    [HttpPut("{id}")]
    public IActionResult PutTodoItem(int id)
    {
        if (id < 1)
        {
            return BadRequest();
        }

        return ControllerContext.MyDisplayRouteInfo(id);
    }

    // [EnableCors] // Not needed as OPTIONS path provided.
    [HttpDelete("{id}")]
    public IActionResult MyDelete(int id) =>
        ControllerContext.MyDisplayRouteInfo(id);

    // [EnableCors] //  Warning ASP0023 Route '{id}' conflicts with another action route.
    //                  An HTTP request that matches multiple routes results in an ambiguous
    //                  match error.
    [EnableCors("MyPolicy")] // Required for this path.
    [HttpGet]
    public IActionResult GetTodoItems() =>
        ControllerContext.MyDisplayRouteInfo();

    [HttpGet("{action}")]
    public IActionResult GetTodoItems2() =>
        ControllerContext.MyDisplayRouteInfo();

    [EnableCors("MyPolicy")]  // Required for this path.
    [HttpDelete("{action}/{id}")]
    public IActionResult MyDelete2(int id) =>
        ControllerContext.MyDisplayRouteInfo(id);
}

Uji kode sebelumnya dari halaman pengujian sampel yang disebarkan. Di daftar drop-down Pengontrol, pilih Preflight lalu Atur Pengontrol. Semua panggilan CORS ke TodoItems2Controller titik akhir berhasil.

Sumber Daya Tambahan:

Oleh Rick Anderson dan Kirk Larkin

Artikel ini memperlihatkan cara mengaktifkan CORS di aplikasi ASP.NET Core.

Keamanan browser mencegah halaman web membuat permintaan ke domain yang berbeda dari yang melayani halaman web. Pembatasan ini disebut kebijakan asal yang sama. Pembatasan ini disebut kebijakan asal yang sama, dan mencegah situs yang berbahaya membaca data yang bersifat sensitif dari situs lain. Terkadang, Anda mungkin ingin mengizinkan situs lain membuat permintaan lintas asal ke aplikasi Anda. Untuk informasi selengkapnya, lihat artikel Mozilla CORS.

Berbagi Sumber Daya Lintas Asal (CORS):

  • Adalah standar W3C yang memungkinkan server untuk melonggarkan kebijakan asal yang sama.
  • Bukan fitur keamanan, CORS melonggarkan keamanan. API tidak lebih aman dengan mengizinkan CORS. Untuk informasi selengkapnya, lihat Cara kerja CORS.
  • Memungkinkan server untuk secara eksplisit mengizinkan beberapa permintaan lintas asal sambil menolak yang lain.
  • Lebih aman dan fleksibel daripada teknik sebelumnya, seperti JSONP.

Melihat atau mengunduh kode sampel (cara mengunduh)

Asal yang sama

Dua URL memiliki asal yang sama jika memiliki skema, host, dan port yang identik (RFC 6454).

Kedua URL ini memiliki asal yang sama:

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

URL ini memiliki asal yang berbeda dari dua URL sebelumnya:

  • https://example.net: Domain yang berbeda
  • https://www.example.com/foo.html: Subdomain yang berbeda
  • http://example.com/foo.html: Skema yang berbeda
  • https://example.com:9000/foo.html: Port yang berbeda

Mengaktifkan CORS

Ada tiga cara untuk mengaktifkan CORS:

Menggunakan atribut [EnableCors] dengan kebijakan bernama memberikan kontrol terbaik dalam membatasi titik akhir yang mendukung CORS.

Peringatan

UseCors harus dipanggil dalam urutan yang benar. Untuk informasi selengkapnya, lihat Pesanan Middleware. Misalnya, UseCors harus dipanggil sebelumnya UseResponseCaching saat menggunakan UseResponseCaching.

Setiap pendekatan dirinci di bagian berikut.

CORS dengan kebijakan dan middleware bernama

CORS Middleware menangani permintaan lintas asal. Kode berikut menerapkan kebijakan CORS ke semua titik akhir aplikasi dengan asal yang ditentukan:

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

Kode sebelumnya:

  • Mengatur nama kebijakan ke _myAllowSpecificOrigins. Nama kebijakan bersifat arbitrer.
  • UseCors Memanggil metode ekstensi dan menentukan _myAllowSpecificOrigins kebijakan CORS. UseCors menambahkan middleware CORS. Panggilan ke UseCors harus ditempatkan setelah UseRouting, tetapi sebelum UseAuthorization. Untuk informasi selengkapnya, lihat Pesanan Middleware.
  • AddCors Panggilan dengan ekspresi lambda. Lambda mengambil CorsPolicyBuilder objek. Opsi konfigurasi, seperti WithOrigins, dijelaskan nanti dalam artikel ini.
  • _myAllowSpecificOrigins Mengaktifkan kebijakan CORS untuk semua titik akhir pengontrol. Lihat perutean titik akhir untuk menerapkan kebijakan CORS ke titik akhir tertentu.
  • Saat menggunakan Middleware Penembolokan Respons, hubungi UseCors sebelum UseResponseCaching.

Dengan perutean titik akhir, middleware CORS harus dikonfigurasi untuk dijalankan antara panggilan ke UseRouting dan UseEndpoints.

Lihat Menguji CORS untuk petunjuk tentang kode pengujian yang mirip dengan kode sebelumnya.

Panggilan AddCors metode menambahkan layanan CORS ke kontainer layanan aplikasi:

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

Untuk informasi selengkapnya, lihat opsi kebijakan CORS dalam dokumen ini.

Metode CorsPolicyBuilder dapat ditautkan, seperti yang ditunjukkan dalam kode berikut:

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

Catatan: URL yang ditentukan tidak boleh berisi garis miring berikutnya (/). Jika URL berakhir dengan /, perbandingan false akan kembali dan tidak ada header yang dikembalikan.

Peringatan

UseCors harus ditempatkan setelah UseRouting dan sebelum UseAuthorization. Ini untuk memastikan bahwa header CORS disertakan dalam respons untuk panggilan resmi dan tidak sah.

Urutan UseCors dan UseStaticFiles

Biasanya, UseStaticFiles dipanggil sebelum UseCors. Aplikasi yang menggunakan JavaScript untuk mengambil file statis lintas situs harus memanggil UseCors sebelum UseStaticFiles.

CORS dengan kebijakan default dan middleware

Kode yang disorot berikut memungkinkan kebijakan CORS default:

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

Kode sebelumnya menerapkan kebijakan CORS default ke semua titik akhir pengontrol.

Mengaktifkan Cors dengan perutean titik akhir

Dengan perutean titik akhir, CORS dapat diaktifkan berdasarkan per titik akhir menggunakan RequireCors serangkaian metode ekstensi:

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

Dalam kode sebelumnya:

  • app.UseCors mengaktifkan middleware CORS. Karena kebijakan default belum dikonfigurasi, app.UseCors() saja tidak mengaktifkan CORS.
  • /echo Titik akhir pengontrol dan memungkinkan permintaan lintas asal menggunakan kebijakan yang ditentukan.
  • /echo2 Titik akhir Halaman dan Razor tidak mengizinkan permintaan lintas asal karena tidak ada kebijakan default yang ditentukan.

Atribut [DisableCors] tidak menonaktifkan CORS yang telah diaktifkan oleh perutean titik akhir dengan RequireCors.

Dalam ASP.NET Core 7.0, [EnableCors] atribut harus melewati parameter atau Peringatan ASP0023 dihasilkan dari kecocokan ambigu pada rute. ASP.NET Core 8.0 dan yang lebih baru tidak menghasilkan ASP0023 peringatan.

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

Lihat Menguji CORS dengan atribut [EnableCors] dan metode RequireCors untuk petunjuk tentang kode pengujian yang mirip dengan sebelumnya.

Mengaktifkan CORS dengan atribut

Mengaktifkan CORS dengan atribut [EnableCors] dan menerapkan kebijakan bernama hanya ke titik akhir yang memerlukan CORS memberikan kontrol terbaik.

Atribut [EnableCors] menyediakan alternatif untuk menerapkan CORS secara global. Atribut [EnableCors] ini memungkinkan CORS untuk titik akhir yang dipilih, bukan semua titik akhir:

  • [EnableCors] menentukan kebijakan default.
  • [EnableCors("{Policy String}")] menentukan kebijakan bernama.

Atribut [EnableCors] dapat diterapkan ke:

  • Razor Halaman PageModel
  • Pengontrol
  • Metode tindakan pengontrol

Kebijakan yang berbeda dapat diterapkan ke pengontrol, model halaman, atau metode tindakan dengan [EnableCors] atribut . [EnableCors] Saat atribut diterapkan ke pengontrol, model halaman, atau metode tindakan, dan CORS diaktifkan di middleware, kedua kebijakan diterapkan. Sebaiknya jangan menggabungkan kebijakan. Gunakan [EnableCors]atribut atau middleware, bukan keduanya di aplikasi yang sama.

Kode berikut menerapkan kebijakan yang berbeda untuk setiap metode:

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

Kode berikut membuat dua kebijakan CORS:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy("Policy1",
        policy =>
        {
            policy.WithOrigins("http://example.com",
                                "http://www.contoso.com");
        });

    options.AddPolicy("AnotherPolicy",
        policy =>
        {
            policy.WithOrigins("http://www.contoso.com")
                                .AllowAnyHeader()
                                .AllowAnyMethod();
        });
});

builder.Services.AddControllers();

var app = builder.Build();

app.UseHttpsRedirection();

app.UseRouting();

app.UseCors();

app.UseAuthorization();

app.MapControllers();

app.Run();

Untuk kontrol terbaik membatasi permintaan CORS:

  • Gunakan [EnableCors("MyPolicy")] dengan kebijakan bernama.
  • Jangan tentukan kebijakan default.
  • Jangan gunakan perutean titik akhir.

Kode di bagian berikutnya memenuhi daftar sebelumnya.

Lihat Menguji CORS untuk petunjuk tentang kode pengujian yang mirip dengan kode sebelumnya.

Menonaktifkan CORS

Atribut [DisableCors] tidak menonaktifkan CORS yang telah diaktifkan oleh perutean titik akhir.

Kode berikut mendefinisikan kebijakan "MyPolicy"CORS :

var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy(name: "MyPolicy",
        policy =>
        {
            policy.WithOrigins("http://example.com",
                                "http://www.contoso.com")
                    .WithMethods("PUT", "DELETE", "GET");
        });
});

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

var app = builder.Build();

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

app.UseCors();

app.UseAuthorization();

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

app.Run();

Kode berikut menonaktifkan CORS untuk tindakan:GetValues2

[EnableCors("MyPolicy")]
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
    // GET api/values
    [HttpGet]
    public IActionResult Get() =>
        ControllerContext.MyDisplayRouteInfo();

    // GET api/values/5
    [HttpGet("{id}")]
    public IActionResult Get(int id) =>
        ControllerContext.MyDisplayRouteInfo(id);

    // PUT api/values/5
    [HttpPut("{id}")]
    public IActionResult Put(int id) =>
        ControllerContext.MyDisplayRouteInfo(id);


    // GET: api/values/GetValues2
    [DisableCors]
    [HttpGet("{action}")]
    public IActionResult GetValues2() =>
        ControllerContext.MyDisplayRouteInfo();

}

Kode sebelumnya:

Lihat Menguji CORS untuk petunjuk tentang menguji kode sebelumnya.

Opsi kebijakan CORS

Bagian ini menjelaskan berbagai opsi yang dapat diatur dalam kebijakan CORS:

AddPolicy dipanggil dalam Program.cs. Untuk beberapa opsi, mungkin berguna untuk membaca bagian Cara kerja CORS terlebih dahulu.

Mengatur asal yang diizinkan

AllowAnyOrigin: Memungkinkan permintaan CORS dari semua asal dengan skema apa pun (http atau https). AllowAnyOrigin tidak aman karena situs web apa pun dapat membuat permintaan lintas asal ke aplikasi.

Catatan

Menentukan AllowAnyOrigin dan AllowCredentials adalah konfigurasi tidak aman dan dapat mengakibatkan pemalsuan permintaan antarsitus. Layanan CORS mengembalikan respons CORS yang tidak valid saat aplikasi dikonfigurasi dengan kedua metode.

AllowAnyOrigin mempengaruhi permintaan preflight dan Access-Control-Allow-Origin header. Untuk informasi selengkapnya, lihat bagian Permintaan preflight.

SetIsOriginAllowedToAllowWildcardSubdomains: Mengatur IsOriginAllowed properti kebijakan menjadi fungsi yang memungkinkan asal untuk mencocokkan domain wildcard yang dikonfigurasi saat mengevaluasi apakah asal diizinkan.

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

Mengatur metode HTTP yang diizinkan

AllowAnyMethod:

  • Mengizinkan metode HTTP apa pun:
  • Mempengaruhi permintaan preflight dan Access-Control-Allow-Methods header. Untuk informasi selengkapnya, lihat bagian Permintaan preflight.

Mengatur header permintaan yang diizinkan

Untuk mengizinkan header tertentu dikirim dalam permintaan CORS, yang disebut header permintaan penulis, panggil WithHeaders dan tentukan header yang diizinkan:

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

Untuk mengizinkan semua header permintaan penulis, panggil AllowAnyHeader:

var MyAllowSpecificOrigins = "_MyAllowSubdomainPolicy";

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy(name: MyAllowSpecificOrigins,
        policy =>
        {
            policy.WithOrigins("https://*.example.com")
                   .AllowAnyHeader();
        });
});

builder.Services.AddControllers();

var app = builder.Build();

AllowAnyHeader memengaruhi permintaan preflight dan header Access-Control-Request-Headers . Untuk informasi selengkapnya, lihat bagian Permintaan preflight.

Kebijakan MIDDLEware CORS cocok dengan WithHeaders header tertentu yang ditentukan hanya dimungkinkan ketika header yang dikirim Access-Control-Request-Headers sama persis dengan header yang dinyatakan dalam WithHeaders.

Misalnya, pertimbangkan aplikasi yang dikonfigurasi sebagai berikut:

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

CORS Middleware menolak permintaan preflight dengan header permintaan berikut karena Content-Language (HeaderNames.ContentLanguage) tidak tercantum dalam WithHeaders:

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

Aplikasi mengembalikan respons 200 OK tetapi tidak mengirim header CORS kembali. Oleh karena itu, browser tidak mencoba permintaan lintas asal.

Mengatur header respons yang diekspos

Secara default, browser tidak mengekspos semua header respons ke aplikasi. Untuk informasi selengkapnya, lihat Berbagi Sumber Daya Lintas Asal W3C (Terminologi): Header Respons Sederhana.

Header respons yang tersedia secara default adalah:

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

Spesifikasi CORS memanggil header ini header respons sederhana. Untuk membuat header lain tersedia untuk aplikasi, panggil WithExposedHeaders:

var builder = WebApplication.CreateBuilder(args);

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

builder.Services.AddControllers();

var app = builder.Build();

Kredensial dalam permintaan lintas asal

Kredensial memerlukan penanganan khusus dalam permintaan CORS. Secara default, browser tidak mengirim kredensial dengan permintaan lintas asal. Kredensial termasuk cookies dan skema autentikasi HTTP. Untuk mengirim kredensial dengan permintaan lintas asal, klien harus mengatur XMLHttpRequest.withCredentials ke true.

Menggunakan XMLHttpRequest secara langsung:

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

Menggunakan jQuery:

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

Menggunakan Fetch API:

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

Server harus memperbolehkan kredensial. Untuk mengizinkan kredensial lintas asal, panggil AllowCredentials:

var builder = WebApplication.CreateBuilder(args);

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

builder.Services.AddControllers();

var app = builder.Build();

Respons HTTP menyertakan Access-Control-Allow-Credentials header, yang memberi tahu browser bahwa server mengizinkan kredensial untuk permintaan lintas asal.

Jika browser mengirim kredensial tetapi respons tidak menyertakan header yang valid Access-Control-Allow-Credentials , browser tidak mengekspos respons ke aplikasi, dan permintaan lintas asal gagal.

Mengizinkan kredensial lintas asal adalah risiko keamanan. Situs web di domain lain dapat mengirim kredensial pengguna yang masuk ke aplikasi atas nama pengguna tanpa sepengetahuan pengguna.

Spesifikasi CORS juga menyatakan bahwa pengaturan asal ke "*" (semua asal) tidak valid jika Access-Control-Allow-Credentials header ada.

Permintaan preflight

Untuk beberapa permintaan CORS, browser mengirimkan permintaan OPTIONS tambahan sebelum membuat permintaan aktual. Permintaan ini disebut permintaan preflight. Browser dapat melewati permintaan preflight jika semua kondisi berikut ini benar:

  • Metode permintaan adalah GET, HEAD, atau POST.
  • Aplikasi ini tidak mengatur header permintaan selain Accept, , Accept-Language, Content-LanguageContent-Type, atau Last-Event-ID.
  • Header Content-Type , jika diatur, memiliki salah satu nilai berikut:
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

Aturan pada header permintaan yang ditetapkan untuk permintaan klien berlaku untuk header yang ditetapkan aplikasi dengan memanggil setRequestHeaderXMLHttpRequest objek. Spesifikasi CORS memanggil header ini menulis header permintaan header. Aturan tidak berlaku untuk header yang dapat diatur browser, seperti User-Agent, , Hostatau Content-Length.

Berikut ini adalah contoh respons yang mirip dengan permintaan preflight yang dibuat dari tombol [Letakkan uji] di bagian Uji CORS dari dokumen ini.

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

Permintaan preflight menggunakan metode HTTP OPTIONS . Ini mungkin termasuk header berikut:

Jika permintaan preflight ditolak, aplikasi mengembalikan 200 OK respons tetapi tidak mengatur header CORS. Oleh karena itu, browser tidak mencoba permintaan lintas asal. Untuk contoh permintaan preflight yang ditolak, lihat bagian Uji CORS dari dokumen ini.

Dengan menggunakan alat F12, aplikasi konsol menampilkan kesalahan yang mirip dengan salah satu hal berikut, tergantung pada browser:

  • Firefox: Permintaan Lintas Asal Diblokir: Kebijakan Asal yang Sama melarang membaca sumber daya jarak jauh di https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5. (Alasan: Permintaan CORS tidak berhasil). Pelajari Selengkapnya
  • Berbasis Chromium: Akses untuk mengambil di 'https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5' dari asal 'https://cors3.azurewebsites.net' telah diblokir oleh kebijakan CORS: Respons terhadap permintaan preflight tidak melewati pemeriksaan kontrol akses: Tidak ada header 'Access-Control-Allow-Origin' yang ada di sumber daya yang diminta. Jika respons buram melayani kebutuhan Anda, atur mode permintaan ke 'tanpa cor' untuk mengambil sumber daya dengan CORS dinonaktifkan.

Untuk mengizinkan header tertentu, panggil 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();

Untuk mengizinkan semua header permintaan penulis, panggil AllowAnyHeader:

using Microsoft.Net.Http.Headers;

var builder = WebApplication.CreateBuilder(args);

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

builder.Services.AddControllers();

var app = builder.Build();

Browser tidak konsisten dalam cara mereka mengatur Access-Control-Request-Headers. Jika:

  • Header diatur ke apa pun selain "*"
  • AllowAnyHeader dipanggil: Sertakan setidaknya Accept, , Content-Typedan Origin, ditambah header kustom apa pun yang ingin Anda dukung.

Kode permintaan preflight otomatis

Ketika kebijakan CORS diterapkan:

  • Secara global dengan memanggil app.UseCors di Program.cs.
  • [EnableCors] Menggunakan atribut .

ASP.NET Core merespons permintaan OPTIONS preflight.

Bagian Uji CORS dari dokumen ini menunjukkan perilaku ini.

Atribut [HttpOptions] untuk permintaan preflight

Ketika CORS diaktifkan dengan kebijakan yang sesuai, ASP.NET Core umumnya merespons permintaan preflight CORS secara otomatis.

Kode berikut menggunakan atribut [HttpOptions] untuk membuat titik akhir untuk permintaan OPTIONS:

[Route("api/[controller]")]
[ApiController]
public class TodoItems2Controller : ControllerBase
{
    // OPTIONS: api/TodoItems2/5
    [HttpOptions("{id}")]
    public IActionResult PreflightRoute(int id)
    {
        return NoContent();
    }

    // OPTIONS: api/TodoItems2 
    [HttpOptions]
    public IActionResult PreflightRoute()
    {
        return NoContent();
    }

    [HttpPut("{id}")]
    public IActionResult PutTodoItem(int id)
    {
        if (id < 1)
        {
            return BadRequest();
        }

        return ControllerContext.MyDisplayRouteInfo(id);
    }

Lihat Menguji CORS dengan atribut [EnableCors] dan metode RequireCors untuk petunjuk tentang menguji kode sebelumnya.

Mengatur waktu kedaluwarsa preflight

Header Access-Control-Max-Age menentukan berapa lama respons terhadap permintaan preflight dapat di-cache. Untuk mengatur header ini, panggil SetPreflightMaxAge:

var builder = WebApplication.CreateBuilder(args);

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

builder.Services.AddControllers();

var app = builder.Build();

Mengaktifkan CORS pada titik akhir

Cara kerja CORS

Bagian ini menjelaskan apa yang terjadi dalam permintaan CORS di tingkat pesan HTTP.

  • CORS bukan fitur keamanan. CORS adalah standar W3C yang memungkinkan server untuk melonggarkan kebijakan asal yang sama.
    • Misalnya, aktor jahat dapat menggunakan Scripting Lintas Situs (XSS) terhadap situs Anda dan menjalankan permintaan lintas situs ke situs cors yang diaktifkan untuk mencuri informasi.
  • API tidak lebih aman dengan mengizinkan CORS.
    • Terserah klien (browser) untuk memberlakukan CORS. Server menjalankan permintaan dan mengembalikan respons, itu adalah klien yang mengembalikan kesalahan dan memblokir respons. Misalnya, salah satu alat berikut akan menampilkan respons server:
  • Ini adalah cara bagi server untuk memungkinkan browser menjalankan permintaan XHR lintas asal atau Fetch API yang jika tidak akan dilarang.
    • Browser tanpa CORS tidak dapat melakukan permintaan lintas asal. Sebelum CORS, JSONP digunakan untuk menghindari pembatasan ini. JSONP tidak menggunakan XHR, menggunakan <script> tag untuk menerima respons. Skrip diizinkan untuk dimuat lintas asal.

Spesifikasi CORS memperkenalkan beberapa header HTTP baru yang mengaktifkan permintaan lintas asal. Jika browser mendukung CORS, ia mengatur header ini secara otomatis untuk permintaan lintas asal. Kode JavaScript kustom tidak diperlukan untuk mengaktifkan CORS.

Tombol uji PUT pada sampel yang disebarkan

Berikut ini adalah contoh permintaan lintas asal dari tombol Uji nilai ke https://cors1.azurewebsites.net/api/values. Header Origin :

  • Menyediakan domain situs yang membuat permintaan.
  • Diperlukan dan harus berbeda dari host.

Header umum

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

Header respons

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

Header permintaan

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

Dalam OPTIONS permintaan, server mengatur header ResponsAccess-Control-Allow-Origin: {allowed origin} dalam respons. Misalnya, sampel yang disebarkan, Permintaan tombol OPTIONS Hapus [EnableCors] berisi header berikut:

Header umum

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

Header respons

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

Header permintaan

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

Di header Respons sebelumnya, server mengatur header Access-Control-Allow-Origin dalam respons. Nilai https://cors1.azurewebsites.net header ini cocok dengan Origin header dari permintaan.

Jika AllowAnyOrigin dipanggil, Access-Control-Allow-Origin: *nilai kartubebas, dikembalikan. AllowAnyOrigin memungkinkan asal apa pun.

Jika respons tidak menyertakan Access-Control-Allow-Origin header, permintaan lintas asal gagal. Secara khusus, browser melarang permintaan. Bahkan jika server mengembalikan respons yang berhasil, browser tidak membuat respons tersedia untuk aplikasi klien.

Pengalihan HTTP ke HTTPS menyebabkan ERR_INVALID_REDIRECT pada permintaan preflight CORS

Permintaan ke titik akhir menggunakan HTTP yang dialihkan ke HTTPS dengan UseHttpsRedirection gagal dengan ERR_INVALID_REDIRECT on the CORS preflight request.

Proyek API dapat menolak permintaan HTTP daripada menggunakan UseHttpsRedirection untuk mengalihkan permintaan ke HTTPS.

CORS di IIS

Saat menyebarkan ke IIS, CORS harus berjalan sebelum Autentikasi Windows jika server tidak dikonfigurasi untuk mengizinkan akses anonim. Untuk mendukung skenario ini, modul IIS CORS perlu diinstal dan dikonfigurasi untuk aplikasi.

Uji CORS

Unduhan sampel memiliki kode untuk menguji CORS. Lihat cara mengunduh. Sampel adalah proyek API dengan Razor Pages ditambahkan:

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

Peringatan

WithOrigins("https://localhost:<port>");hanya boleh digunakan untuk menguji aplikasi sampel yang mirip dengan kode sampel unduhan.

Berikut ini ValuesController menyediakan titik akhir untuk pengujian:

[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 disediakan oleh paket Rick.Docs.Samples.RouteInfo NuGet dan menampilkan informasi rute.

Uji kode sampel sebelumnya dengan menggunakan salah satu pendekatan berikut:

  • Gunakan aplikasi sampel yang disebarkan di https://cors3.azurewebsites.net/. Tidak perlu mengunduh sampel.
  • Jalankan sampel dengan dotnet run menggunakan URL https://localhost:5001default .
  • Jalankan sampel dari Visual Studio dengan port diatur ke 44398 untuk URL https://localhost:44398.

Menggunakan browser dengan alat F12:

  • Pilih tombol Nilai dan tinjau header di tab Jaringan .

  • Pilih tombol uji PUT. Lihat Menampilkan permintaan OPTIONS untuk instruksi tentang menampilkan permintaan OPTIONS. Pengujian PUT membuat dua permintaan, permintaan preflight OPTIONS dan permintaan PUT.

  • Pilih tombol GetValues2 [DisableCors] untuk memicu permintaan CORS yang gagal. Seperti disebutkan dalam dokumen, respons mengembalikan 200 keberhasilan, tetapi permintaan CORS tidak dibuat. Pilih tab Konsol untuk melihat kesalahan CORS. Bergantung pada browser, kesalahan yang mirip dengan yang berikut ini ditampilkan:

    Akses untuk mengambil dari asal 'https://cors3.azurewebsites.net' telah diblokir 'https://cors1.azurewebsites.net/api/values/GetValues2' oleh kebijakan CORS: Tidak ada header 'Access-Control-Allow-Origin' yang ada di sumber daya yang diminta. Jika respons buram melayani kebutuhan Anda, atur mode permintaan ke 'tanpa cor' untuk mengambil sumber daya dengan CORS dinonaktifkan.

Titik akhir dengan dukungan CORS dapat diuji dengan alat, seperti curl atau Fiddler. Saat menggunakan alat, asal permintaan yang ditentukan oleh Origin header harus berbeda dari host yang menerima permintaan. Jika permintaan tidak berasal dari silang berdasarkan nilai Origin header:

  • Cors Middleware tidak perlu memproses permintaan.
  • Header CORS tidak dikembalikan dalam respons.

Perintah berikut menggunakan curl untuk mengeluarkan permintaan OPTIONS dengan informasi:

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

Uji CORS dengan atribut [EnableCors] dan metode RequireCors

Pertimbangkan kode berikut yang menggunakan perutean titik akhir untuk mengaktifkan CORS berdasarkan per titik akhir menggunakan 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();

Perhatikan bahwa hanya /echo titik akhir yang RequireCors menggunakan untuk mengizinkan permintaan lintas asal menggunakan kebijakan yang ditentukan. Pengontrol di bawah ini mengaktifkan CORS menggunakan atribut [EnableCors].

Berikut ini TodoItems1Controller menyediakan titik akhir untuk pengujian:

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

Uji kode sebelumnya dari halaman pengujian sampel yang disebarkan.

Tombol Hapus [EnableCors] dan GET [EnableCors] berhasil, karena titik akhir memiliki [EnableCors] dan merespons permintaan preflight. Titik akhir lainnya gagal. Tombol GET gagal, karena JavaScript mengirimkan:

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

Berikut ini TodoItems2Controller menyediakan titik akhir serupa, tetapi menyertakan kode eksplisit untuk merespons permintaan OPTIONS:

[Route("api/[controller]")]
[ApiController]
public class TodoItems2Controller : ControllerBase
{
    // OPTIONS: api/TodoItems2/5
    [HttpOptions("{id}")]
    public IActionResult PreflightRoute(int id)
    {
        return NoContent();
    }

    // OPTIONS: api/TodoItems2 
    [HttpOptions]
    public IActionResult PreflightRoute()
    {
        return NoContent();
    }

    [HttpPut("{id}")]
    public IActionResult PutTodoItem(int id)
    {
        if (id < 1)
        {
            return BadRequest();
        }

        return ControllerContext.MyDisplayRouteInfo(id);
    }

    // [EnableCors] // Not needed as OPTIONS path provided.
    [HttpDelete("{id}")]
    public IActionResult MyDelete(int id) =>
        ControllerContext.MyDisplayRouteInfo(id);

    // [EnableCors] //  Warning ASP0023 Route '{id}' conflicts with another action route.
    //                  An HTTP request that matches multiple routes results in an ambiguous
    //                  match error.
    [EnableCors("MyPolicy")] // Required for this path.
    [HttpGet]
    public IActionResult GetTodoItems() =>
        ControllerContext.MyDisplayRouteInfo();

    [HttpGet("{action}")]
    public IActionResult GetTodoItems2() =>
        ControllerContext.MyDisplayRouteInfo();

    [EnableCors("MyPolicy")]  // Required for this path.
    [HttpDelete("{action}/{id}")]
    public IActionResult MyDelete2(int id) =>
        ControllerContext.MyDisplayRouteInfo(id);
}

Uji kode sebelumnya dari halaman pengujian sampel yang disebarkan. Di daftar drop-down Pengontrol, pilih Preflight lalu Atur Pengontrol. Semua panggilan CORS ke TodoItems2Controller titik akhir berhasil.

Sumber Daya Tambahan:

Oleh Rick Anderson dan Kirk Larkin

Artikel ini memperlihatkan cara mengaktifkan CORS di aplikasi ASP.NET Core.

Keamanan browser mencegah halaman web membuat permintaan ke domain yang berbeda dari yang melayani halaman web. Pembatasan ini disebut kebijakan asal yang sama. Pembatasan ini disebut kebijakan asal yang sama, dan mencegah situs yang berbahaya membaca data yang bersifat sensitif dari situs lain. Terkadang, Anda mungkin ingin mengizinkan situs lain membuat permintaan lintas asal ke aplikasi Anda. Untuk informasi selengkapnya, lihat artikel Mozilla CORS.

Berbagi Sumber Daya Lintas Asal (CORS):

  • Adalah standar W3C yang memungkinkan server untuk melonggarkan kebijakan asal yang sama.
  • Bukan fitur keamanan, CORS melonggarkan keamanan. API tidak lebih aman dengan mengizinkan CORS. Untuk informasi selengkapnya, lihat Cara kerja CORS.
  • Memungkinkan server untuk secara eksplisit mengizinkan beberapa permintaan lintas asal sambil menolak yang lain.
  • Lebih aman dan fleksibel daripada teknik sebelumnya, seperti JSONP.

Melihat atau mengunduh kode sampel (cara mengunduh)

Asal yang sama

Dua URL memiliki asal yang sama jika memiliki skema, host, dan port yang identik (RFC 6454).

Kedua URL ini memiliki asal yang sama:

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

URL ini memiliki asal yang berbeda dari dua URL sebelumnya:

  • https://example.net: Domain yang berbeda
  • https://www.example.com/foo.html: Subdomain yang berbeda
  • http://example.com/foo.html: Skema yang berbeda
  • https://example.com:9000/foo.html: Port yang berbeda

Mengaktifkan CORS

Ada tiga cara untuk mengaktifkan CORS:

Menggunakan atribut [EnableCors] dengan kebijakan bernama memberikan kontrol terbaik dalam membatasi titik akhir yang mendukung CORS.

Peringatan

UseCors harus dipanggil dalam urutan yang benar. Untuk informasi selengkapnya, lihat Pesanan Middleware. Misalnya, UseCors harus dipanggil sebelumnya UseResponseCaching saat menggunakan UseResponseCaching.

Setiap pendekatan dirinci di bagian berikut.

CORS dengan kebijakan dan middleware bernama

CORS Middleware menangani permintaan lintas asal. Kode berikut menerapkan kebijakan CORS ke semua titik akhir aplikasi dengan asal yang ditentukan:

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

Kode sebelumnya:

  • Mengatur nama kebijakan ke _myAllowSpecificOrigins. Nama kebijakan bersifat arbitrer.
  • UseCors Memanggil metode ekstensi dan menentukan _myAllowSpecificOrigins kebijakan CORS. UseCors menambahkan middleware CORS. Panggilan ke UseCors harus ditempatkan setelah UseRouting, tetapi sebelum UseAuthorization. Untuk informasi selengkapnya, lihat Pesanan Middleware.
  • AddCors Panggilan dengan ekspresi lambda. Lambda mengambil CorsPolicyBuilder objek. Opsi konfigurasi, seperti WithOrigins, dijelaskan nanti dalam artikel ini.
  • _myAllowSpecificOrigins Mengaktifkan kebijakan CORS untuk semua titik akhir pengontrol. Lihat perutean titik akhir untuk menerapkan kebijakan CORS ke titik akhir tertentu.
  • Saat menggunakan Middleware Penembolokan Respons, hubungi UseCors sebelum UseResponseCaching.

Dengan perutean titik akhir, middleware CORS harus dikonfigurasi untuk dijalankan antara panggilan ke UseRouting dan UseEndpoints.

Lihat Menguji CORS untuk petunjuk tentang kode pengujian yang mirip dengan kode sebelumnya.

Panggilan AddCors metode menambahkan layanan CORS ke kontainer layanan aplikasi:

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

Untuk informasi selengkapnya, lihat opsi kebijakan CORS dalam dokumen ini.

Metode CorsPolicyBuilder dapat ditautkan, seperti yang ditunjukkan dalam kode berikut:

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

Catatan: URL yang ditentukan tidak boleh berisi garis miring berikutnya (/). Jika URL berakhir dengan /, perbandingan false akan kembali dan tidak ada header yang dikembalikan.

Peringatan

UseCors harus ditempatkan setelah UseRouting dan sebelum UseAuthorization. Ini untuk memastikan bahwa header CORS disertakan dalam respons untuk panggilan resmi dan tidak sah.

Urutan UseCors dan UseStaticFiles

Biasanya, UseStaticFiles dipanggil sebelum UseCors. Aplikasi yang menggunakan JavaScript untuk mengambil file statis lintas situs harus memanggil UseCors sebelum UseStaticFiles.

CORS dengan kebijakan default dan middleware

Kode yang disorot berikut memungkinkan kebijakan CORS default:

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

Kode sebelumnya menerapkan kebijakan CORS default ke semua titik akhir pengontrol.

Mengaktifkan Cors dengan perutean titik akhir

Mengaktifkan CORS berdasarkan per titik akhir menggunakan RequireCorstidak mendukung permintaan preflight otomatis. Untuk informasi selengkapnya, lihat masalah GitHub ini dan Uji CORS dengan perutean titik akhir dan [HttpOptions].

Dengan perutean titik akhir, CORS dapat diaktifkan berdasarkan per titik akhir menggunakan RequireCors serangkaian metode ekstensi:

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

Dalam kode sebelumnya:

  • app.UseCors mengaktifkan middleware CORS. Karena kebijakan default belum dikonfigurasi, app.UseCors() saja tidak mengaktifkan CORS.
  • /echo Titik akhir pengontrol dan memungkinkan permintaan lintas asal menggunakan kebijakan yang ditentukan.
  • /echo2 Titik akhir Halaman dan Razor tidak mengizinkan permintaan lintas asal karena tidak ada kebijakan default yang ditentukan.

Atribut [DisableCors] tidak menonaktifkan CORS yang telah diaktifkan oleh perutean titik akhir dengan RequireCors.

Lihat Menguji CORS dengan perutean titik akhir dan [HttpOptions] untuk petunjuk tentang kode pengujian yang mirip dengan sebelumnya.

Mengaktifkan CORS dengan atribut

Mengaktifkan CORS dengan atribut [EnableCors] dan menerapkan kebijakan bernama hanya ke titik akhir yang memerlukan CORS memberikan kontrol terbaik.

Atribut [EnableCors] menyediakan alternatif untuk menerapkan CORS secara global. Atribut [EnableCors] ini memungkinkan CORS untuk titik akhir yang dipilih, bukan semua titik akhir:

  • [EnableCors] menentukan kebijakan default.
  • [EnableCors("{Policy String}")] menentukan kebijakan bernama.

Atribut [EnableCors] dapat diterapkan ke:

  • Razor Halaman PageModel
  • Pengontrol
  • Metode tindakan pengontrol

Kebijakan yang berbeda dapat diterapkan ke pengontrol, model halaman, atau metode tindakan dengan [EnableCors] atribut . [EnableCors] Saat atribut diterapkan ke pengontrol, model halaman, atau metode tindakan, dan CORS diaktifkan di middleware, kedua kebijakan diterapkan. Sebaiknya jangan menggabungkan kebijakan. Gunakan [EnableCors]atribut atau middleware, bukan keduanya di aplikasi yang sama.

Kode berikut menerapkan kebijakan yang berbeda untuk setiap metode:

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

Kode berikut membuat dua kebijakan CORS:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy("Policy1",
        policy =>
        {
            policy.WithOrigins("http://example.com",
                                "http://www.contoso.com");
        });

    options.AddPolicy("AnotherPolicy",
        policy =>
        {
            policy.WithOrigins("http://www.contoso.com")
                                .AllowAnyHeader()
                                .AllowAnyMethod();
        });
});

builder.Services.AddControllers();

var app = builder.Build();

app.UseHttpsRedirection();

app.UseRouting();

app.UseCors();

app.UseAuthorization();

app.MapControllers();

app.Run();

Untuk kontrol terbaik membatasi permintaan CORS:

  • Gunakan [EnableCors("MyPolicy")] dengan kebijakan bernama.
  • Jangan tentukan kebijakan default.
  • Jangan gunakan perutean titik akhir.

Kode di bagian berikutnya memenuhi daftar sebelumnya.

Lihat Menguji CORS untuk petunjuk tentang kode pengujian yang mirip dengan kode sebelumnya.

Menonaktifkan CORS

Atribut [DisableCors] tidak menonaktifkan CORS yang telah diaktifkan oleh perutean titik akhir.

Kode berikut mendefinisikan kebijakan "MyPolicy"CORS :

var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy(name: "MyPolicy",
        policy =>
        {
            policy.WithOrigins("http://example.com",
                                "http://www.contoso.com")
                    .WithMethods("PUT", "DELETE", "GET");
        });
});

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

var app = builder.Build();

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

app.UseCors();

app.UseAuthorization();

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

app.Run();

Kode berikut menonaktifkan CORS untuk tindakan:GetValues2

[EnableCors("MyPolicy")]
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
    // GET api/values
    [HttpGet]
    public IActionResult Get() =>
        ControllerContext.MyDisplayRouteInfo();

    // GET api/values/5
    [HttpGet("{id}")]
    public IActionResult Get(int id) =>
        ControllerContext.MyDisplayRouteInfo(id);

    // PUT api/values/5
    [HttpPut("{id}")]
    public IActionResult Put(int id) =>
        ControllerContext.MyDisplayRouteInfo(id);


    // GET: api/values/GetValues2
    [DisableCors]
    [HttpGet("{action}")]
    public IActionResult GetValues2() =>
        ControllerContext.MyDisplayRouteInfo();

}

Kode sebelumnya:

Lihat Menguji CORS untuk petunjuk tentang menguji kode sebelumnya.

Opsi kebijakan CORS

Bagian ini menjelaskan berbagai opsi yang dapat diatur dalam kebijakan CORS:

AddPolicy dipanggil dalam Program.cs. Untuk beberapa opsi, mungkin berguna untuk membaca bagian Cara kerja CORS terlebih dahulu.

Mengatur asal yang diizinkan

AllowAnyOrigin: Memungkinkan permintaan CORS dari semua asal dengan skema apa pun (http atau https). AllowAnyOrigin tidak aman karena situs web apa pun dapat membuat permintaan lintas asal ke aplikasi.

Catatan

Menentukan AllowAnyOrigin dan AllowCredentials adalah konfigurasi tidak aman dan dapat mengakibatkan pemalsuan permintaan antarsitus. Layanan CORS mengembalikan respons CORS yang tidak valid saat aplikasi dikonfigurasi dengan kedua metode.

AllowAnyOrigin mempengaruhi permintaan preflight dan Access-Control-Allow-Origin header. Untuk informasi selengkapnya, lihat bagian Permintaan preflight.

SetIsOriginAllowedToAllowWildcardSubdomains: Mengatur IsOriginAllowed properti kebijakan menjadi fungsi yang memungkinkan asal untuk mencocokkan domain wildcard yang dikonfigurasi saat mengevaluasi apakah asal diizinkan.

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

Mengatur metode HTTP yang diizinkan

AllowAnyMethod:

  • Mengizinkan metode HTTP apa pun:
  • Mempengaruhi permintaan preflight dan Access-Control-Allow-Methods header. Untuk informasi selengkapnya, lihat bagian Permintaan preflight.

Mengatur header permintaan yang diizinkan

Untuk mengizinkan header tertentu dikirim dalam permintaan CORS, yang disebut header permintaan penulis, panggil WithHeaders dan tentukan header yang diizinkan:

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

Untuk mengizinkan semua header permintaan penulis, panggil AllowAnyHeader:

var MyAllowSpecificOrigins = "_MyAllowSubdomainPolicy";

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy(name: MyAllowSpecificOrigins,
        policy =>
        {
            policy.WithOrigins("https://*.example.com")
                   .AllowAnyHeader();
        });
});

builder.Services.AddControllers();

var app = builder.Build();

AllowAnyHeader memengaruhi permintaan preflight dan header Access-Control-Request-Headers . Untuk informasi selengkapnya, lihat bagian Permintaan preflight.

Kebijakan MIDDLEware CORS cocok dengan WithHeaders header tertentu yang ditentukan hanya dimungkinkan ketika header yang dikirim Access-Control-Request-Headers sama persis dengan header yang dinyatakan dalam WithHeaders.

Misalnya, pertimbangkan aplikasi yang dikonfigurasi sebagai berikut:

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

CORS Middleware menolak permintaan preflight dengan header permintaan berikut karena Content-Language (HeaderNames.ContentLanguage) tidak tercantum dalam WithHeaders:

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

Aplikasi mengembalikan respons 200 OK tetapi tidak mengirim header CORS kembali. Oleh karena itu, browser tidak mencoba permintaan lintas asal.

Mengatur header respons yang diekspos

Secara default, browser tidak mengekspos semua header respons ke aplikasi. Untuk informasi selengkapnya, lihat Berbagi Sumber Daya Lintas Asal W3C (Terminologi): Header Respons Sederhana.

Header respons yang tersedia secara default adalah:

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

Spesifikasi CORS memanggil header ini header respons sederhana. Untuk membuat header lain tersedia untuk aplikasi, panggil WithExposedHeaders:

var builder = WebApplication.CreateBuilder(args);

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

builder.Services.AddControllers();

var app = builder.Build();

Kredensial dalam permintaan lintas asal

Kredensial memerlukan penanganan khusus dalam permintaan CORS. Secara default, browser tidak mengirim kredensial dengan permintaan lintas asal. Kredensial termasuk cookies dan skema autentikasi HTTP. Untuk mengirim kredensial dengan permintaan lintas asal, klien harus mengatur XMLHttpRequest.withCredentials ke true.

Menggunakan XMLHttpRequest secara langsung:

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

Menggunakan jQuery:

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

Menggunakan Fetch API:

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

Server harus memperbolehkan kredensial. Untuk mengizinkan kredensial lintas asal, panggil AllowCredentials:

var builder = WebApplication.CreateBuilder(args);

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

builder.Services.AddControllers();

var app = builder.Build();

Respons HTTP menyertakan Access-Control-Allow-Credentials header, yang memberi tahu browser bahwa server mengizinkan kredensial untuk permintaan lintas asal.

Jika browser mengirim kredensial tetapi respons tidak menyertakan header yang valid Access-Control-Allow-Credentials , browser tidak mengekspos respons ke aplikasi, dan permintaan lintas asal gagal.

Mengizinkan kredensial lintas asal adalah risiko keamanan. Situs web di domain lain dapat mengirim kredensial pengguna yang masuk ke aplikasi atas nama pengguna tanpa sepengetahuan pengguna.

Spesifikasi CORS juga menyatakan bahwa pengaturan asal ke "*" (semua asal) tidak valid jika Access-Control-Allow-Credentials header ada.

Permintaan preflight

Untuk beberapa permintaan CORS, browser mengirimkan permintaan OPTIONS tambahan sebelum membuat permintaan aktual. Permintaan ini disebut permintaan preflight. Browser dapat melewati permintaan preflight jika semua kondisi berikut ini benar:

  • Metode permintaan adalah GET, HEAD, atau POST.
  • Aplikasi ini tidak mengatur header permintaan selain Accept, , Accept-Language, Content-LanguageContent-Type, atau Last-Event-ID.
  • Header Content-Type , jika diatur, memiliki salah satu nilai berikut:
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

Aturan pada header permintaan yang ditetapkan untuk permintaan klien berlaku untuk header yang ditetapkan aplikasi dengan memanggil setRequestHeaderXMLHttpRequest objek. Spesifikasi CORS memanggil header ini menulis header permintaan header. Aturan tidak berlaku untuk header yang dapat diatur browser, seperti User-Agent, , Hostatau Content-Length.

Berikut ini adalah contoh respons yang mirip dengan permintaan preflight yang dibuat dari tombol [Letakkan uji] di bagian Uji CORS dari dokumen ini.

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

Permintaan preflight menggunakan metode HTTP OPTIONS . Ini mungkin termasuk header berikut:

Jika permintaan preflight ditolak, aplikasi mengembalikan 200 OK respons tetapi tidak mengatur header CORS. Oleh karena itu, browser tidak mencoba permintaan lintas asal. Untuk contoh permintaan preflight yang ditolak, lihat bagian Uji CORS dari dokumen ini.

Dengan menggunakan alat F12, aplikasi konsol menampilkan kesalahan yang mirip dengan salah satu hal berikut, tergantung pada browser:

  • Firefox: Permintaan Lintas Asal Diblokir: Kebijakan Asal yang Sama melarang membaca sumber daya jarak jauh di https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5. (Alasan: Permintaan CORS tidak berhasil). Pelajari Selengkapnya
  • Berbasis Chromium: Akses untuk mengambil di 'https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5' dari asal 'https://cors3.azurewebsites.net' telah diblokir oleh kebijakan CORS: Respons terhadap permintaan preflight tidak melewati pemeriksaan kontrol akses: Tidak ada header 'Access-Control-Allow-Origin' yang ada di sumber daya yang diminta. Jika respons buram melayani kebutuhan Anda, atur mode permintaan ke 'tanpa cor' untuk mengambil sumber daya dengan CORS dinonaktifkan.

Untuk mengizinkan header tertentu, panggil 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();

Untuk mengizinkan semua header permintaan penulis, panggil AllowAnyHeader:

using Microsoft.Net.Http.Headers;

var builder = WebApplication.CreateBuilder(args);

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

builder.Services.AddControllers();

var app = builder.Build();

Browser tidak konsisten dalam cara mereka mengatur Access-Control-Request-Headers. Jika:

  • Header diatur ke apa pun selain "*"
  • AllowAnyHeader dipanggil: Sertakan setidaknya Accept, , Content-Typedan Origin, ditambah header kustom apa pun yang ingin Anda dukung.

Kode permintaan preflight otomatis

Ketika kebijakan CORS diterapkan:

  • Secara global dengan memanggil app.UseCors di Program.cs.
  • [EnableCors] Menggunakan atribut .

ASP.NET Core merespons permintaan OPTIONS preflight.

Mengaktifkan CORS per titik akhir menggunakan RequireCors saat ini tidak mendukung permintaan preflight otomatis.

Bagian Uji CORS dari dokumen ini menunjukkan perilaku ini.

Atribut [HttpOptions] untuk permintaan preflight

Ketika CORS diaktifkan dengan kebijakan yang sesuai, ASP.NET Core umumnya merespons permintaan preflight CORS secara otomatis. Dalam beberapa skenario, ini mungkin tidak terjadi. Misalnya, menggunakan CORS dengan perutean titik akhir.

Kode berikut menggunakan atribut [HttpOptions] untuk membuat titik akhir untuk permintaan OPTIONS:

[Route("api/[controller]")]
[ApiController]
public class TodoItems2Controller : ControllerBase
{
    // OPTIONS: api/TodoItems2/5
    [HttpOptions("{id}")]
    public IActionResult PreflightRoute(int id)
    {
        return NoContent();
    }

    // OPTIONS: api/TodoItems2 
    [HttpOptions]
    public IActionResult PreflightRoute()
    {
        return NoContent();
    }

    [HttpPut("{id}")]
    public IActionResult PutTodoItem(int id)
    {
        if (id < 1)
        {
            return BadRequest();
        }

        return ControllerContext.MyDisplayRouteInfo(id);
    }

Lihat Menguji CORS dengan perutean titik akhir dan [HttpOptions] untuk petunjuk tentang menguji kode sebelumnya.

Mengatur waktu kedaluwarsa preflight

Header Access-Control-Max-Age menentukan berapa lama respons terhadap permintaan preflight dapat di-cache. Untuk mengatur header ini, panggil SetPreflightMaxAge:

var builder = WebApplication.CreateBuilder(args);

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

builder.Services.AddControllers();

var app = builder.Build();

Cara kerja CORS

Bagian ini menjelaskan apa yang terjadi dalam permintaan CORS di tingkat pesan HTTP.

  • CORS bukan fitur keamanan. CORS adalah standar W3C yang memungkinkan server untuk melonggarkan kebijakan asal yang sama.
    • Misalnya, aktor jahat dapat menggunakan Scripting Lintas Situs (XSS) terhadap situs Anda dan menjalankan permintaan lintas situs ke situs cors yang diaktifkan untuk mencuri informasi.
  • API tidak lebih aman dengan mengizinkan CORS.
    • Terserah klien (browser) untuk memberlakukan CORS. Server menjalankan permintaan dan mengembalikan respons, itu adalah klien yang mengembalikan kesalahan dan memblokir respons. Misalnya, salah satu alat berikut akan menampilkan respons server:
  • Ini adalah cara bagi server untuk memungkinkan browser menjalankan permintaan XHR lintas asal atau Fetch API yang jika tidak akan dilarang.
    • Browser tanpa CORS tidak dapat melakukan permintaan lintas asal. Sebelum CORS, JSONP digunakan untuk menghindari pembatasan ini. JSONP tidak menggunakan XHR, menggunakan <script> tag untuk menerima respons. Skrip diizinkan untuk dimuat lintas asal.

Spesifikasi CORS memperkenalkan beberapa header HTTP baru yang mengaktifkan permintaan lintas asal. Jika browser mendukung CORS, ia mengatur header ini secara otomatis untuk permintaan lintas asal. Kode JavaScript kustom tidak diperlukan untuk mengaktifkan CORS.

Tombol uji PUT pada sampel yang disebarkan

Berikut ini adalah contoh permintaan lintas asal dari tombol Uji nilai ke https://cors1.azurewebsites.net/api/values. Header Origin :

  • Menyediakan domain situs yang membuat permintaan.
  • Diperlukan dan harus berbeda dari host.

Header umum

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

Header respons

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

Header permintaan

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

Dalam OPTIONS permintaan, server mengatur header ResponsAccess-Control-Allow-Origin: {allowed origin} dalam respons. Misalnya, sampel yang disebarkan, Permintaan tombol OPTIONS Hapus [EnableCors] berisi header berikut:

Header umum

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

Header respons

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

Header permintaan

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

Di header Respons sebelumnya, server mengatur header Access-Control-Allow-Origin dalam respons. Nilai https://cors1.azurewebsites.net header ini cocok dengan Origin header dari permintaan.

Jika AllowAnyOrigin dipanggil, Access-Control-Allow-Origin: *nilai kartubebas, dikembalikan. AllowAnyOrigin memungkinkan asal apa pun.

Jika respons tidak menyertakan Access-Control-Allow-Origin header, permintaan lintas asal gagal. Secara khusus, browser melarang permintaan. Bahkan jika server mengembalikan respons yang berhasil, browser tidak membuat respons tersedia untuk aplikasi klien.

Pengalihan HTTP ke HTTPS menyebabkan ERR_INVALID_REDIRECT pada permintaan preflight CORS

Permintaan ke titik akhir menggunakan HTTP yang dialihkan ke HTTPS dengan UseHttpsRedirection gagal dengan ERR_INVALID_REDIRECT on the CORS preflight request.

Proyek API dapat menolak permintaan HTTP daripada menggunakan UseHttpsRedirection untuk mengalihkan permintaan ke HTTPS.

Tampilkan permintaan OPTIONS

Secara default, browser Chrome dan Edge tidak menampilkan permintaan OPTIONS di tab jaringan alat F12. Untuk menampilkan permintaan OPTIONS di browser ini:

  • chrome://flags/#out-of-blink-cors atau edge://flags/#out-of-blink-cors
  • nonaktifkan bendera.
  • Restart.

Firefox memperlihatkan permintaan OPTIONS secara default.

CORS di IIS

Saat menyebarkan ke IIS, CORS harus berjalan sebelum Autentikasi Windows jika server tidak dikonfigurasi untuk mengizinkan akses anonim. Untuk mendukung skenario ini, modul IIS CORS perlu diinstal dan dikonfigurasi untuk aplikasi.

Uji CORS

Unduhan sampel memiliki kode untuk menguji CORS. Lihat cara mengunduh. Sampel adalah proyek API dengan Razor Pages ditambahkan:

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

Peringatan

WithOrigins("https://localhost:<port>");hanya boleh digunakan untuk menguji aplikasi sampel yang mirip dengan kode sampel unduhan.

Berikut ini ValuesController menyediakan titik akhir untuk pengujian:

[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 disediakan oleh paket Rick.Docs.Samples.RouteInfo NuGet dan menampilkan informasi rute.

Uji kode sampel sebelumnya dengan menggunakan salah satu pendekatan berikut:

  • Gunakan aplikasi sampel yang disebarkan di https://cors3.azurewebsites.net/. Tidak perlu mengunduh sampel.
  • Jalankan sampel dengan dotnet run menggunakan URL https://localhost:5001default .
  • Jalankan sampel dari Visual Studio dengan port diatur ke 44398 untuk URL https://localhost:44398.

Menggunakan browser dengan alat F12:

  • Pilih tombol Nilai dan tinjau header di tab Jaringan .

  • Pilih tombol uji PUT. Lihat Menampilkan permintaan OPTIONS untuk instruksi tentang menampilkan permintaan OPTIONS. Pengujian PUT membuat dua permintaan, permintaan preflight OPTIONS dan permintaan PUT.

  • Pilih tombol GetValues2 [DisableCors] untuk memicu permintaan CORS yang gagal. Seperti disebutkan dalam dokumen, respons mengembalikan 200 keberhasilan, tetapi permintaan CORS tidak dibuat. Pilih tab Konsol untuk melihat kesalahan CORS. Bergantung pada browser, kesalahan yang mirip dengan yang berikut ini ditampilkan:

    Akses untuk mengambil dari asal 'https://cors3.azurewebsites.net' telah diblokir 'https://cors1.azurewebsites.net/api/values/GetValues2' oleh kebijakan CORS: Tidak ada header 'Access-Control-Allow-Origin' yang ada di sumber daya yang diminta. Jika respons buram melayani kebutuhan Anda, atur mode permintaan ke 'tanpa cor' untuk mengambil sumber daya dengan CORS dinonaktifkan.

Titik akhir dengan dukungan CORS dapat diuji dengan alat, seperti curl atau Fiddler. Saat menggunakan alat, asal permintaan yang ditentukan oleh Origin header harus berbeda dari host yang menerima permintaan. Jika permintaan tidak berasal dari silang berdasarkan nilai Origin header:

  • Cors Middleware tidak perlu memproses permintaan.
  • Header CORS tidak dikembalikan dalam respons.

Perintah berikut menggunakan curl untuk mengeluarkan permintaan OPTIONS dengan informasi:

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

Uji CORS dengan perutean titik akhir dan [HttpOptions]

Mengaktifkan CORS per titik akhir menggunakan RequireCors saat ini tidak mendukung permintaan preflight otomatis. Pertimbangkan kode berikut yang menggunakan perutean titik akhir untuk mengaktifkan CORS:

var builder = WebApplication.CreateBuilder(args);

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

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

var app = builder.Build();

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

app.UseCors();

app.UseAuthorization();

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

app.Run();

Berikut ini TodoItems1Controller menyediakan titik akhir untuk pengujian:

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

Uji kode sebelumnya dari halaman pengujian sampel yang disebarkan.

Tombol Hapus [EnableCors] dan GET [EnableCors] berhasil, karena titik akhir memiliki [EnableCors] dan merespons permintaan preflight. Titik akhir lainnya gagal. Tombol GET gagal, karena JavaScript mengirimkan:

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

Berikut ini TodoItems2Controller menyediakan titik akhir serupa, tetapi menyertakan kode eksplisit untuk merespons permintaan OPTIONS:

[Route("api/[controller]")]
[ApiController]
public class TodoItems2Controller : ControllerBase
{
    // OPTIONS: api/TodoItems2/5
    [HttpOptions("{id}")]
    public IActionResult PreflightRoute(int id)
    {
        return NoContent();
    }

    // OPTIONS: api/TodoItems2 
    [HttpOptions]
    public IActionResult PreflightRoute()
    {
        return NoContent();
    }

    [HttpPut("{id}")]
    public IActionResult PutTodoItem(int id)
    {
        if (id < 1)
        {
            return BadRequest();
        }

        return ControllerContext.MyDisplayRouteInfo(id);
    }

    // [EnableCors] // Not needed as OPTIONS path provided
    [HttpDelete("{id}")]
    public IActionResult MyDelete(int id) =>
        ControllerContext.MyDisplayRouteInfo(id);

    [EnableCors]  // Rquired for this path
    [HttpGet]
    public IActionResult GetTodoItems() =>
        ControllerContext.MyDisplayRouteInfo();

    [HttpGet("{action}")]
    public IActionResult GetTodoItems2() =>
        ControllerContext.MyDisplayRouteInfo();

    [EnableCors]  // Rquired for this path
    [HttpDelete("{action}/{id}")]
    public IActionResult MyDelete2(int id) =>
        ControllerContext.MyDisplayRouteInfo(id);
}

Uji kode sebelumnya dari halaman pengujian sampel yang disebarkan. Di daftar drop-down Pengontrol, pilih Preflight lalu Atur Pengontrol. Semua panggilan CORS ke TodoItems2Controller titik akhir berhasil.

Sumber Daya Tambahan:

Oleh Rick Anderson dan Kirk Larkin

Artikel ini memperlihatkan cara mengaktifkan CORS di aplikasi ASP.NET Core.

Keamanan browser mencegah halaman web membuat permintaan ke domain yang berbeda dari yang melayani halaman web. Pembatasan ini disebut kebijakan asal yang sama. Pembatasan ini disebut kebijakan asal yang sama, dan mencegah situs yang berbahaya membaca data yang bersifat sensitif dari situs lain. Terkadang, Anda mungkin ingin mengizinkan situs lain membuat permintaan lintas asal ke aplikasi Anda. Untuk informasi selengkapnya, lihat artikel Mozilla CORS.

Berbagi Sumber Daya Lintas Asal (CORS):

  • Adalah standar W3C yang memungkinkan server untuk melonggarkan kebijakan asal yang sama.
  • Bukan fitur keamanan, CORS melonggarkan keamanan. API tidak lebih aman dengan mengizinkan CORS. Untuk informasi selengkapnya, lihat Cara kerja CORS.
  • Memungkinkan server untuk secara eksplisit mengizinkan beberapa permintaan lintas asal sambil menolak yang lain.
  • Lebih aman dan fleksibel daripada teknik sebelumnya, seperti JSONP.

Melihat atau mengunduh kode sampel (cara mengunduh)

Asal yang sama

Dua URL memiliki asal yang sama jika memiliki skema, host, dan port yang identik (RFC 6454).

Kedua URL ini memiliki asal yang sama:

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

URL ini memiliki asal yang berbeda dari dua URL sebelumnya:

  • https://example.net: Domain yang berbeda
  • https://www.example.com/foo.html: Subdomain yang berbeda
  • http://example.com/foo.html: Skema yang berbeda
  • https://example.com:9000/foo.html: Port yang berbeda

Mengaktifkan CORS

Ada tiga cara untuk mengaktifkan CORS:

Menggunakan atribut [EnableCors] dengan kebijakan bernama memberikan kontrol terbaik dalam membatasi titik akhir yang mendukung CORS.

Peringatan

UseCors harus dipanggil dalam urutan yang benar. Untuk informasi selengkapnya, lihat Pesanan Middleware. Misalnya, UseCors harus dipanggil sebelumnya UseResponseCaching saat menggunakan UseResponseCaching.

Setiap pendekatan dirinci di bagian berikut.

CORS dengan kebijakan dan middleware bernama

CORS Middleware menangani permintaan lintas asal. Kode berikut menerapkan kebijakan CORS ke semua titik akhir aplikasi dengan asal yang ditentukan:

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

Kode sebelumnya:

  • Mengatur nama kebijakan ke _myAllowSpecificOrigins. Nama kebijakan bersifat arbitrer.
  • UseCors Memanggil metode ekstensi dan menentukan _myAllowSpecificOrigins kebijakan CORS. UseCors menambahkan middleware CORS. Panggilan ke UseCors harus ditempatkan setelah UseRouting, tetapi sebelum UseAuthorization. Untuk informasi selengkapnya, lihat Pesanan Middleware.
  • AddCors Panggilan dengan ekspresi lambda. Lambda mengambil CorsPolicyBuilder objek. Opsi konfigurasi, seperti WithOrigins, dijelaskan nanti dalam artikel ini.
  • _myAllowSpecificOrigins Mengaktifkan kebijakan CORS untuk semua titik akhir pengontrol. Lihat perutean titik akhir untuk menerapkan kebijakan CORS ke titik akhir tertentu.
  • Saat menggunakan Middleware Penembolokan Respons, hubungi UseCors sebelum UseResponseCaching.

Dengan perutean titik akhir, middleware CORS harus dikonfigurasi untuk dijalankan antara panggilan ke UseRouting dan UseEndpoints.

Lihat Menguji CORS untuk petunjuk tentang kode pengujian yang mirip dengan kode sebelumnya.

Panggilan AddCors metode menambahkan layanan CORS ke kontainer layanan aplikasi:

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

Untuk informasi selengkapnya, lihat opsi kebijakan CORS dalam dokumen ini.

Metode CorsPolicyBuilder dapat ditautkan, seperti yang ditunjukkan dalam kode berikut:

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

Catatan: URL yang ditentukan tidak boleh berisi garis miring berikutnya (/). Jika URL berakhir dengan /, perbandingan false akan kembali dan tidak ada header yang dikembalikan.

CORS dengan kebijakan default dan middleware

Kode yang disorot berikut memungkinkan kebijakan CORS default:

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

Kode sebelumnya menerapkan kebijakan CORS default ke semua titik akhir pengontrol.

Mengaktifkan Cors dengan perutean titik akhir

Mengaktifkan CORS berdasarkan per titik akhir menggunakan RequireCorstidak mendukung permintaan preflight otomatis. Untuk informasi selengkapnya, lihat masalah GitHub ini dan Uji CORS dengan perutean titik akhir dan [HttpOptions].

Dengan perutean titik akhir, CORS dapat diaktifkan berdasarkan per titik akhir menggunakan RequireCors serangkaian metode ekstensi:

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

Dalam kode sebelumnya:

  • app.UseCors mengaktifkan middleware CORS. Karena kebijakan default belum dikonfigurasi, app.UseCors() saja tidak mengaktifkan CORS.
  • /echo Titik akhir pengontrol dan memungkinkan permintaan lintas asal menggunakan kebijakan yang ditentukan.
  • /echo2 Titik akhir Halaman dan Razor tidak mengizinkan permintaan lintas asal karena tidak ada kebijakan default yang ditentukan.

Atribut [DisableCors] tidak menonaktifkan CORS yang telah diaktifkan oleh perutean titik akhir dengan RequireCors.

Lihat Menguji CORS dengan perutean titik akhir dan [HttpOptions] untuk petunjuk tentang kode pengujian yang mirip dengan sebelumnya.

Mengaktifkan CORS dengan atribut

Mengaktifkan CORS dengan atribut [EnableCors] dan menerapkan kebijakan bernama hanya ke titik akhir yang memerlukan CORS memberikan kontrol terbaik.

Atribut [EnableCors] menyediakan alternatif untuk menerapkan CORS secara global. Atribut [EnableCors] ini memungkinkan CORS untuk titik akhir yang dipilih, bukan semua titik akhir:

  • [EnableCors] menentukan kebijakan default.
  • [EnableCors("{Policy String}")] menentukan kebijakan bernama.

Atribut [EnableCors] dapat diterapkan ke:

  • Razor Halaman PageModel
  • Pengontrol
  • Metode tindakan pengontrol

Kebijakan yang berbeda dapat diterapkan ke pengontrol, model halaman, atau metode tindakan dengan [EnableCors] atribut . [EnableCors] Saat atribut diterapkan ke pengontrol, model halaman, atau metode tindakan, dan CORS diaktifkan di middleware, kedua kebijakan diterapkan. Sebaiknya jangan menggabungkan kebijakan. Gunakan [EnableCors]atribut atau middleware, bukan keduanya di aplikasi yang sama.

Kode berikut menerapkan kebijakan yang berbeda untuk setiap metode:

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

Kode berikut membuat dua kebijakan CORS:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddCors(options =>
        {
            options.AddPolicy("Policy1",
                policy =>
                {
                    policy.WithOrigins("http://example.com",
                                        "http://www.contoso.com");
                });

            options.AddPolicy("AnotherPolicy",
                policy =>
                {
                    policy.WithOrigins("http://www.contoso.com")
                                        .AllowAnyHeader()
                                        .AllowAnyMethod();
                });
        });

        services.AddControllers();
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseHttpsRedirection();

        app.UseRouting();

        app.UseCors();

        app.UseAuthorization();

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

Untuk kontrol terbaik membatasi permintaan CORS:

  • Gunakan [EnableCors("MyPolicy")] dengan kebijakan bernama.
  • Jangan tentukan kebijakan default.
  • Jangan gunakan perutean titik akhir.

Kode di bagian berikutnya memenuhi daftar sebelumnya.

Lihat Menguji CORS untuk petunjuk tentang kode pengujian yang mirip dengan kode sebelumnya.

Menonaktifkan CORS

Atribut [DisableCors] tidak menonaktifkan CORS yang telah diaktifkan oleh perutean titik akhir.

Kode berikut mendefinisikan kebijakan "MyPolicy"CORS :

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddCors(options =>
        {
            options.AddPolicy(name: "MyPolicy",
                policy =>
                {
                    policy.WithOrigins("http://example.com",
                                        "http://www.contoso.com")
                            .WithMethods("PUT", "DELETE", "GET");
                });
        });

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

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

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

        app.UseCors();

        app.UseAuthorization();

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

Kode berikut menonaktifkan CORS untuk tindakan:GetValues2

[EnableCors("MyPolicy")]
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
    // GET api/values
    [HttpGet]
    public IActionResult Get() =>
        ControllerContext.MyDisplayRouteInfo();

    // GET api/values/5
    [HttpGet("{id}")]
    public IActionResult Get(int id) =>
        ControllerContext.MyDisplayRouteInfo(id);

    // PUT api/values/5
    [HttpPut("{id}")]
    public IActionResult Put(int id) =>
        ControllerContext.MyDisplayRouteInfo(id);


    // GET: api/values/GetValues2
    [DisableCors]
    [HttpGet("{action}")]
    public IActionResult GetValues2() =>
        ControllerContext.MyDisplayRouteInfo();

}

Kode sebelumnya:

Lihat Menguji CORS untuk petunjuk tentang menguji kode sebelumnya.

Opsi kebijakan CORS

Bagian ini menjelaskan berbagai opsi yang dapat diatur dalam kebijakan CORS:

AddPolicy dipanggil dalam Startup.ConfigureServices. Untuk beberapa opsi, mungkin berguna untuk membaca bagian Cara kerja CORS terlebih dahulu.

Mengatur asal yang diizinkan

AllowAnyOrigin: Memungkinkan permintaan CORS dari semua asal dengan skema apa pun (http atau https). AllowAnyOrigin tidak aman karena situs web apa pun dapat membuat permintaan lintas asal ke aplikasi.

Catatan

Menentukan AllowAnyOrigin dan AllowCredentials adalah konfigurasi tidak aman dan dapat mengakibatkan pemalsuan permintaan antarsitus. Layanan CORS mengembalikan respons CORS yang tidak valid saat aplikasi dikonfigurasi dengan kedua metode.

AllowAnyOrigin mempengaruhi permintaan preflight dan Access-Control-Allow-Origin header. Untuk informasi selengkapnya, lihat bagian Permintaan preflight.

SetIsOriginAllowedToAllowWildcardSubdomains: Mengatur IsOriginAllowed properti kebijakan menjadi fungsi yang memungkinkan asal untuk mencocokkan domain wildcard yang dikonfigurasi saat mengevaluasi apakah asal diizinkan.

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

Mengatur metode HTTP yang diizinkan

AllowAnyMethod:

  • Mengizinkan metode HTTP apa pun:
  • Mempengaruhi permintaan preflight dan Access-Control-Allow-Methods header. Untuk informasi selengkapnya, lihat bagian Permintaan preflight.

Mengatur header permintaan yang diizinkan

Untuk mengizinkan header tertentu dikirim dalam permintaan CORS, yang disebut header permintaan penulis, panggil WithHeaders dan tentukan header yang diizinkan:

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

Untuk mengizinkan semua header permintaan penulis, panggil AllowAnyHeader:

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

AllowAnyHeader memengaruhi permintaan preflight dan header Access-Control-Request-Headers . Untuk informasi selengkapnya, lihat bagian Permintaan preflight.

Kebijakan MIDDLEware CORS cocok dengan WithHeaders header tertentu yang ditentukan hanya dimungkinkan ketika header yang dikirim Access-Control-Request-Headers sama persis dengan header yang dinyatakan dalam WithHeaders.

Misalnya, pertimbangkan aplikasi yang dikonfigurasi sebagai berikut:

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

CORS Middleware menolak permintaan preflight dengan header permintaan berikut karena Content-Language (HeaderNames.ContentLanguage) tidak tercantum dalam WithHeaders:

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

Aplikasi mengembalikan respons 200 OK tetapi tidak mengirim header CORS kembali. Oleh karena itu, browser tidak mencoba permintaan lintas asal.

Mengatur header respons yang diekspos

Secara default, browser tidak mengekspos semua header respons ke aplikasi. Untuk informasi selengkapnya, lihat Berbagi Sumber Daya Lintas Asal W3C (Terminologi): Header Respons Sederhana.

Header respons yang tersedia secara default adalah:

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

Spesifikasi CORS memanggil header ini header respons sederhana. Untuk membuat header lain tersedia untuk aplikasi, panggil WithExposedHeaders:

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

Kredensial dalam permintaan lintas asal

Kredensial memerlukan penanganan khusus dalam permintaan CORS. Secara default, browser tidak mengirim kredensial dengan permintaan lintas asal. Kredensial termasuk cookies dan skema autentikasi HTTP. Untuk mengirim kredensial dengan permintaan lintas asal, klien harus mengatur XMLHttpRequest.withCredentials ke true.

Menggunakan XMLHttpRequest secara langsung:

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

Menggunakan jQuery:

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

Menggunakan Fetch API:

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

Server harus memperbolehkan kredensial. Untuk mengizinkan kredensial lintas asal, panggil AllowCredentials:

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

Respons HTTP menyertakan Access-Control-Allow-Credentials header, yang memberi tahu browser bahwa server mengizinkan kredensial untuk permintaan lintas asal.

Jika browser mengirim kredensial tetapi respons tidak menyertakan header yang valid Access-Control-Allow-Credentials , browser tidak mengekspos respons ke aplikasi, dan permintaan lintas asal gagal.

Mengizinkan kredensial lintas asal adalah risiko keamanan. Situs web di domain lain dapat mengirim kredensial pengguna yang masuk ke aplikasi atas nama pengguna tanpa sepengetahuan pengguna.

Spesifikasi CORS juga menyatakan bahwa pengaturan asal ke "*" (semua asal) tidak valid jika Access-Control-Allow-Credentials header ada.

Permintaan preflight

Untuk beberapa permintaan CORS, browser mengirimkan permintaan OPTIONS tambahan sebelum membuat permintaan aktual. Permintaan ini disebut permintaan preflight. Browser dapat melewati permintaan preflight jika semua kondisi berikut ini benar:

  • Metode permintaan adalah GET, HEAD, atau POST.
  • Aplikasi ini tidak mengatur header permintaan selain Accept, , Accept-Language, Content-LanguageContent-Type, atau Last-Event-ID.
  • Header Content-Type , jika diatur, memiliki salah satu nilai berikut:
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

Aturan pada header permintaan yang ditetapkan untuk permintaan klien berlaku untuk header yang ditetapkan aplikasi dengan memanggil setRequestHeaderXMLHttpRequest objek. Spesifikasi CORS memanggil header ini menulis header permintaan header. Aturan tidak berlaku untuk header yang dapat diatur browser, seperti User-Agent, , Hostatau Content-Length.

Berikut ini adalah contoh respons yang mirip dengan permintaan preflight yang dibuat dari tombol [Letakkan uji] di bagian Uji CORS dari dokumen ini.

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

Permintaan preflight menggunakan metode HTTP OPTIONS . Ini mungkin termasuk header berikut:

Jika permintaan preflight ditolak, aplikasi mengembalikan 200 OK respons tetapi tidak mengatur header CORS. Oleh karena itu, browser tidak mencoba permintaan lintas asal. Untuk contoh permintaan preflight yang ditolak, lihat bagian Uji CORS dari dokumen ini.

Dengan menggunakan alat F12, aplikasi konsol menampilkan kesalahan yang mirip dengan salah satu hal berikut, tergantung pada browser:

  • Firefox: Permintaan Lintas Asal Diblokir: Kebijakan Asal yang Sama melarang membaca sumber daya jarak jauh di https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5. (Alasan: Permintaan CORS tidak berhasil). Pelajari Selengkapnya
  • Berbasis Chromium: Akses untuk mengambil di 'https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5' dari asal 'https://cors3.azurewebsites.net' telah diblokir oleh kebijakan CORS: Respons terhadap permintaan preflight tidak melewati pemeriksaan kontrol akses: Tidak ada header 'Access-Control-Allow-Origin' yang ada di sumber daya yang diminta. Jika respons buram melayani kebutuhan Anda, atur mode permintaan ke 'tanpa cor' untuk mengambil sumber daya dengan CORS dinonaktifkan.

Untuk mengizinkan header tertentu, panggil WithHeaders:

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

Untuk mengizinkan semua header permintaan penulis, panggil AllowAnyHeader:

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

Browser tidak konsisten dalam cara mereka mengatur Access-Control-Request-Headers. Jika:

  • Header diatur ke apa pun selain "*"
  • AllowAnyHeader dipanggil: Sertakan setidaknya Accept, , Content-Typedan Origin, ditambah header kustom apa pun yang ingin Anda dukung.

Kode permintaan preflight otomatis

Ketika kebijakan CORS diterapkan:

  • Secara global dengan memanggil app.UseCors di Startup.Configure.
  • [EnableCors] Menggunakan atribut .

ASP.NET Core merespons permintaan OPTIONS preflight.

Mengaktifkan CORS per titik akhir menggunakan RequireCors saat ini tidak mendukung permintaan preflight otomatis.

Bagian Uji CORS dari dokumen ini menunjukkan perilaku ini.

Atribut [HttpOptions] untuk permintaan preflight

Ketika CORS diaktifkan dengan kebijakan yang sesuai, ASP.NET Core umumnya merespons permintaan preflight CORS secara otomatis. Dalam beberapa skenario, ini mungkin tidak terjadi. Misalnya, menggunakan CORS dengan perutean titik akhir.

Kode berikut menggunakan atribut [HttpOptions] untuk membuat titik akhir untuk permintaan OPTIONS:

[Route("api/[controller]")]
[ApiController]
public class TodoItems2Controller : ControllerBase
{
    // OPTIONS: api/TodoItems2/5
    [HttpOptions("{id}")]
    public IActionResult PreflightRoute(int id)
    {
        return NoContent();
    }

    // OPTIONS: api/TodoItems2 
    [HttpOptions]
    public IActionResult PreflightRoute()
    {
        return NoContent();
    }

    [HttpPut("{id}")]
    public IActionResult PutTodoItem(int id)
    {
        if (id < 1)
        {
            return BadRequest();
        }

        return ControllerContext.MyDisplayRouteInfo(id);
    }

Lihat Menguji CORS dengan perutean titik akhir dan [HttpOptions] untuk petunjuk tentang menguji kode sebelumnya.

Mengatur waktu kedaluwarsa preflight

Header Access-Control-Max-Age menentukan berapa lama respons terhadap permintaan preflight dapat di-cache. Untuk mengatur header ini, panggil SetPreflightMaxAge:

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

Cara kerja CORS

Bagian ini menjelaskan apa yang terjadi dalam permintaan CORS di tingkat pesan HTTP.

  • CORS bukan fitur keamanan. CORS adalah standar W3C yang memungkinkan server untuk melonggarkan kebijakan asal yang sama.
    • Misalnya, aktor jahat dapat menggunakan Scripting Lintas Situs (XSS) terhadap situs Anda dan menjalankan permintaan lintas situs ke situs cors yang diaktifkan untuk mencuri informasi.
  • API tidak lebih aman dengan mengizinkan CORS.
    • Terserah klien (browser) untuk memberlakukan CORS. Server menjalankan permintaan dan mengembalikan respons, itu adalah klien yang mengembalikan kesalahan dan memblokir respons. Misalnya, salah satu alat berikut akan menampilkan respons server:
  • Ini adalah cara bagi server untuk memungkinkan browser menjalankan permintaan XHR lintas asal atau Fetch API yang jika tidak akan dilarang.
    • Browser tanpa CORS tidak dapat melakukan permintaan lintas asal. Sebelum CORS, JSONP digunakan untuk menghindari pembatasan ini. JSONP tidak menggunakan XHR, menggunakan <script> tag untuk menerima respons. Skrip diizinkan untuk dimuat lintas asal.

Spesifikasi CORS memperkenalkan beberapa header HTTP baru yang mengaktifkan permintaan lintas asal. Jika browser mendukung CORS, ia mengatur header ini secara otomatis untuk permintaan lintas asal. Kode JavaScript kustom tidak diperlukan untuk mengaktifkan CORS.

Tombol uji PUT pada sampel yang disebarkan

Berikut ini adalah contoh permintaan lintas asal dari tombol Uji nilai ke https://cors1.azurewebsites.net/api/values. Header Origin :

  • Menyediakan domain situs yang membuat permintaan.
  • Diperlukan dan harus berbeda dari host.

Header umum

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

Header respons

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

Header permintaan

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

Dalam OPTIONS permintaan, server mengatur header ResponsAccess-Control-Allow-Origin: {allowed origin} dalam respons. Misalnya, sampel yang disebarkan, Permintaan tombol OPTIONS Hapus [EnableCors] berisi header berikut:

Header umum

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

Header respons

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

Header permintaan

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

Di header Respons sebelumnya, server mengatur header Access-Control-Allow-Origin dalam respons. Nilai https://cors1.azurewebsites.net header ini cocok dengan Origin header dari permintaan.

Jika AllowAnyOrigin dipanggil, Access-Control-Allow-Origin: *nilai kartubebas, dikembalikan. AllowAnyOrigin memungkinkan asal apa pun.

Jika respons tidak menyertakan Access-Control-Allow-Origin header, permintaan lintas asal gagal. Secara khusus, browser melarang permintaan. Bahkan jika server mengembalikan respons yang berhasil, browser tidak membuat respons tersedia untuk aplikasi klien.

Tampilkan permintaan OPTIONS

Secara default, browser Chrome dan Edge tidak menampilkan permintaan OPTIONS di tab jaringan alat F12. Untuk menampilkan permintaan OPTIONS di browser ini:

  • chrome://flags/#out-of-blink-cors atau edge://flags/#out-of-blink-cors
  • nonaktifkan bendera.
  • Restart.

Firefox memperlihatkan permintaan OPTIONS secara default.

CORS di IIS

Saat menyebarkan ke IIS, CORS harus berjalan sebelum Autentikasi Windows jika server tidak dikonfigurasi untuk mengizinkan akses anonim. Untuk mendukung skenario ini, modul IIS CORS perlu diinstal dan dikonfigurasi untuk aplikasi.

Uji CORS

Unduhan sampel memiliki kode untuk menguji CORS. Lihat cara mengunduh. Sampel adalah proyek API dengan Razor Pages ditambahkan:

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

Peringatan

WithOrigins("https://localhost:<port>");hanya boleh digunakan untuk menguji aplikasi sampel yang mirip dengan kode sampel unduhan.

Berikut ini ValuesController menyediakan titik akhir untuk pengujian:

[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 disediakan oleh paket Rick.Docs.Samples.RouteInfo NuGet dan menampilkan informasi rute.

Uji kode sampel sebelumnya dengan menggunakan salah satu pendekatan berikut:

  • Gunakan aplikasi sampel yang disebarkan di https://cors3.azurewebsites.net/. Tidak perlu mengunduh sampel.
  • Jalankan sampel dengan dotnet run menggunakan URL https://localhost:5001default .
  • Jalankan sampel dari Visual Studio dengan port diatur ke 44398 untuk URL https://localhost:44398.

Menggunakan browser dengan alat F12:

  • Pilih tombol Nilai dan tinjau header di tab Jaringan .

  • Pilih tombol uji PUT. Lihat Menampilkan permintaan OPTIONS untuk instruksi tentang menampilkan permintaan OPTIONS. Pengujian PUT membuat dua permintaan, permintaan preflight OPTIONS dan permintaan PUT.

  • Pilih tombol GetValues2 [DisableCors] untuk memicu permintaan CORS yang gagal. Seperti disebutkan dalam dokumen, respons mengembalikan 200 keberhasilan, tetapi permintaan CORS tidak dibuat. Pilih tab Konsol untuk melihat kesalahan CORS. Bergantung pada browser, kesalahan yang mirip dengan yang berikut ini ditampilkan:

    Akses untuk mengambil dari asal 'https://cors3.azurewebsites.net' telah diblokir 'https://cors1.azurewebsites.net/api/values/GetValues2' oleh kebijakan CORS: Tidak ada header 'Access-Control-Allow-Origin' yang ada di sumber daya yang diminta. Jika respons buram melayani kebutuhan Anda, atur mode permintaan ke 'tanpa cor' untuk mengambil sumber daya dengan CORS dinonaktifkan.

Titik akhir dengan dukungan CORS dapat diuji dengan alat, seperti curl atau Fiddler. Saat menggunakan alat, asal permintaan yang ditentukan oleh Origin header harus berbeda dari host yang menerima permintaan. Jika permintaan tidak berasal dari silang berdasarkan nilai Origin header:

  • Cors Middleware tidak perlu memproses permintaan.
  • Header CORS tidak dikembalikan dalam respons.

Perintah berikut menggunakan curl untuk mengeluarkan permintaan OPTIONS dengan informasi:

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

Uji CORS dengan perutean titik akhir dan [HttpOptions]

Mengaktifkan CORS per titik akhir menggunakan RequireCors saat ini tidak mendukung permintaan preflight otomatis. Pertimbangkan kode berikut yang menggunakan perutean titik akhir untuk mengaktifkan CORS:

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

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

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

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

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

        app.UseCors();

        app.UseAuthorization();

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

Berikut ini TodoItems1Controller menyediakan titik akhir untuk pengujian:

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

Uji kode sebelumnya dari halaman pengujian sampel yang disebarkan.

Tombol Hapus [EnableCors] dan GET [EnableCors] berhasil, karena titik akhir memiliki [EnableCors] dan merespons permintaan preflight. Titik akhir lainnya gagal. Tombol GET gagal, karena JavaScript mengirimkan:

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

Berikut ini TodoItems2Controller menyediakan titik akhir serupa, tetapi menyertakan kode eksplisit untuk merespons permintaan OPTIONS:

[Route("api/[controller]")]
[ApiController]
public class TodoItems2Controller : ControllerBase
{
    // OPTIONS: api/TodoItems2/5
    [HttpOptions("{id}")]
    public IActionResult PreflightRoute(int id)
    {
        return NoContent();
    }

    // OPTIONS: api/TodoItems2 
    [HttpOptions]
    public IActionResult PreflightRoute()
    {
        return NoContent();
    }

    [HttpPut("{id}")]
    public IActionResult PutTodoItem(int id)
    {
        if (id < 1)
        {
            return BadRequest();
        }

        return ControllerContext.MyDisplayRouteInfo(id);
    }

    // [EnableCors] // Not needed as OPTIONS path provided
    [HttpDelete("{id}")]
    public IActionResult MyDelete(int id) =>
        ControllerContext.MyDisplayRouteInfo(id);

    [EnableCors]  // Rquired for this path
    [HttpGet]
    public IActionResult GetTodoItems() =>
        ControllerContext.MyDisplayRouteInfo();

    [HttpGet("{action}")]
    public IActionResult GetTodoItems2() =>
        ControllerContext.MyDisplayRouteInfo();

    [EnableCors]  // Rquired for this path
    [HttpDelete("{action}/{id}")]
    public IActionResult MyDelete2(int id) =>
        ControllerContext.MyDisplayRouteInfo(id);
}

Uji kode sebelumnya dari halaman pengujian sampel yang disebarkan. Di daftar drop-down Pengontrol, pilih Preflight lalu Atur Pengontrol. Semua panggilan CORS ke TodoItems2Controller titik akhir berhasil.

Sumber Daya Tambahan: