XMLHttpRequest tidak dapat memuat XXX No header 'Access-Control-Allow-Origin'

111

tl; dr; Tentang Kebijakan Asal yang Sama

Saya memiliki proses Grunt yang memulai sebuah instance dari server express.js. Ini bekerja dengan sangat baik sampai sekarang ketika itu mulai menyajikan halaman kosong dengan yang berikut ini muncul di log kesalahan di konsol pengembang di Chrome (versi terbaru):

XMLHttpRequest tidak dapat memuat https://www.example.com/ Tidak ada header 'Access-Control-Allow-Origin' pada sumber yang diminta. Oleh karena itu, asal ' http: // localhost: 4300 ' tidak diizinkan untuk diakses.

Apa yang mencegah saya mengakses halaman ini?

Peter David Carter
sumber
Saya sedang mengerjakan situs web dan itu baik-baik saja lima menit yang lalu.
Peter David Carter
1
apakah itu mengeluarkan header CORS? mungkin jika Anda membagikan beberapa kode, akan lebih mudah untuk melihatnya
Jaromanda X
Masuk akal. Departemen mana yang harus saya tanyakan? Saya hanya melakukan hal-hal backbone.marionette kebanyakan ...
Peter David Carter
Ya. Saya kira organisasi departemen tidak selalu seragam, jadi ini mungkin pertanyaan yang samar-samar, tetapi saya ingin tahu sedikit tentang backend / routing / sys-admin di perusahaan saya dan ini sepertinya alasan yang baik untuk membiasakan diri sendiri jadi jika ada masalah kedepannya saya bisa bantu.
Peter David Carter
Saya akan bertanya kepada seseorang di sisi server dalam operasi Anda. Mereka pasti telah mengubahnya pada Anda jika Anda dapat mengaksesnya sebelumnya.
Larry Lane

Jawaban:

205

tl; dr - Ada ringkasan di akhir dan judul di jawaban untuk memudahkan menemukan bagian yang relevan. Meskipun demikian, membaca semuanya disarankan karena memberikan latar belakang yang berguna untuk memahami mengapa hal itu membuat melihat bagaimana penerapannya dalam keadaan yang berbeda lebih mudah.

Tentang Kebijakan Asal yang Sama

Ini adalah Kebijakan Asal yang Sama . Ini adalah fitur keamanan yang diterapkan oleh browser.

Kasus khusus Anda menunjukkan bagaimana ini diimplementasikan untuk XMLHttpRequest (dan Anda akan mendapatkan hasil yang identik jika Anda menggunakan fetch), tetapi itu juga berlaku untuk hal-hal lain (seperti gambar yang dimuat ke <canvas>atau dokumen yang dimuat ke dalam <iframe>), hanya dengan implementasi yang sedikit berbeda.

(Anehnya, ini juga berlaku untuk font CSS, tetapi itu karena pengecoran yang ditemukan bersikeras pada DRM dan bukan untuk masalah keamanan yang biasanya dicakup oleh Kebijakan Asal yang Sama).

Skenario standar yang menunjukkan perlunya SOP dapat ditunjukkan dengan tiga karakter :

  • Alice adalah orang yang memiliki web browser
  • Bob menjalankan situs web ( https://www.[website].com/dalam contoh Anda)
  • Mallory menjalankan situs web ( http://localhost:4300dalam contoh Anda)

Alice masuk ke situs Bob dan memiliki beberapa data rahasia di sana. Mungkin itu intranet perusahaan (hanya dapat diakses oleh browser di LAN), atau perbankan online-nya (hanya dapat diakses dengan cookie yang Anda dapatkan setelah memasukkan nama pengguna dan kata sandi).

Alice mengunjungi situs Mallory yang memiliki beberapa JavaScript yang menyebabkan browser Alice membuat permintaan HTTP ke situs Bob (dari alamat IP-nya dengan cookie-nya, dll). Ini bisa sesederhana menggunakan XMLHttpRequestdan membaca responseText.

Kebijakan Asal yang Sama pada browser mencegah JavaScript membaca data yang dikembalikan oleh situs web Bob (yang tidak ingin diakses oleh Bob dan Alice oleh Mallory). (Perhatikan bahwa Anda dapat, misalnya, menampilkan gambar menggunakan <img>elemen di seluruh sumber karena konten gambar tidak diekspos ke JavaScript (atau Mallory)… kecuali Anda memasukkan kanvas ke dalam campuran yang dalam hal ini Anda akan menghasilkan sumber yang sama kesalahan pelanggaran).


Mengapa Kebijakan Asal yang Sama berlaku saat menurut Anda tidak seharusnya

Untuk setiap URL tertentu mungkin saja SOP tidak diperlukan. Beberapa skenario umum di mana hal ini terjadi adalah:

  • Alice, Bob dan Mallory adalah orang yang sama.
  • Bob memberikan informasi publik sepenuhnya

… Tetapi browser tidak memiliki cara untuk mengetahui apakah salah satu hal di atas benar, jadi kepercayaan tidak otomatis dan SOP diterapkan. Izin harus diberikan secara eksplisit sebelum browser memberikan data yang diberikan ke situs web lain.


Mengapa Kebijakan Asal yang Sama hanya berlaku untuk JavaScript di halaman web

Ekstensi browser *, tab Jaringan di alat pengembang browser dan aplikasi seperti Postman adalah perangkat lunak yang diinstal. Mereka tidak meneruskan data dari satu situs web ke JavaScript milik situs web lain hanya karena Anda mengunjungi situs web berbeda tersebut . Menginstal perangkat lunak biasanya membutuhkan pilihan yang lebih sadar.

Tidak ada pihak ketiga (Mallory) yang dianggap berisiko.

*Ekstensi browser perlu ditulis dengan hati-hati untuk menghindari masalah lintas sumber. Lihat dokumentasi Chrome misalnya .


Mengapa Anda dapat menampilkan data di halaman tanpa membacanya dengan JS

Ada beberapa keadaan di mana situs Mallory dapat menyebabkan browser mengambil data dari pihak ketiga dan menampilkannya (misalnya dengan menambahkan <img>elemen untuk menampilkan gambar). JavaScript Mallory tidak mungkin membaca data dalam sumber daya itu, hanya browser Alice dan server Bob yang dapat melakukannya, jadi itu masih aman.


CORS

The Access-Control-Allow-OriginHTTP respon header yang dimaksud dalam pesan kesalahan adalah bagian dari CORS standar yang memungkinkan Bob secara eksplisit memberikan izin ke situs Mallory untuk akses data melalui browser Alice.

Implementasi dasar hanya akan mencakup:

Access-Control-Allow-Origin: *

… Di tajuk tanggapan untuk mengizinkan situs web mana pun membaca data.

Access-Control-Allow-Origin: http://example.com/

… Hanya akan mengizinkan situs tertentu untuk mengaksesnya, dan Bob dapat secara dinamis menghasilkan itu berdasarkan header Origin permintaan untuk mengizinkan beberapa, tetapi tidak semua, situs untuk mengaksesnya.

Secara spesifik bagaimana Bob menyetel header respons tersebut bergantung pada server HTTP Bob dan / atau bahasa pemrograman sisi server. Ada kumpulan panduan untuk berbagai konfigurasi umum yang mungkin bisa membantu.

Model tempat aturan CORS diterapkan

NB: Beberapa permintaan rumit dan mengirim permintaan OPTIONS pra - penerbangan yang harus ditanggapi oleh server sebelum browser mengirim permintaan GET / POST / PUT / Apapun yang ingin dibuat JS. Penerapan CORS yang hanya menambahkan Access-Control-Allow-Originke URL tertentu sering kali tersandung oleh hal ini.


Memberikan izin melalui CORS adalah sesuatu yang hanya akan dilakukan Bob jika:

  • Data tidak bersifat pribadi atau
  • Mallory dipercaya

Tapi aku bukan Bob!

Tidak ada mekanisme standar bagi Mallory untuk menambahkan tajuk ini karena harus berasal dari situs web Bob, yang tidak dikontrolnya.

Jika Bob menjalankan API publik, mungkin ada mekanisme untuk mengaktifkan CORS (mungkin dengan memformat permintaan dengan cara tertentu, atau opsi konfigurasi setelah masuk ke situs Portal Pengembang untuk situs Bob). Ini harus menjadi mekanisme yang diterapkan oleh Bob. Mallory dapat membaca dokumentasi di situs Bob untuk melihat apakah ada sesuatu yang tersedia, atau dia dapat berbicara dengan Bob dan memintanya untuk menerapkan CORS.


Pesan kesalahan yang menyebutkan "Respon untuk preflight"

Beberapa permintaan lintas asal sudah ditentukan sebelumnya .

Ini terjadi ketika (secara kasar) Anda mencoba membuat permintaan lintas sumber yang:

  • Termasuk kredensial seperti cookie
  • Tidak dapat dibuat dengan formulir HTML biasa (mis. Memiliki tajuk khusus atau Jenis Konten yang tidak dapat Anda gunakan dalam formulir enctype).

Jika Anda benar melakukan sesuatu yang membutuhkan penerbangan sebelumnya

Dalam kasus ini , sisa dari jawaban ini masih berlaku tetapi Anda juga perlu memastikan bahwa server dapat mendengarkan permintaan preflight (yang akan OPTIONS(dan bukan GET, POSTatau apa pun yang Anda coba kirim) dan menanggapinya dengan benar. Access-Control-Allow-Originheader tetapi juga Access-Control-Allow-Methodsdan Access-Control-Allow-Headersuntuk mengizinkan metode atau header HTTP spesifik Anda.

Jika Anda memicu preflight karena kesalahan

Terkadang orang membuat kesalahan saat mencoba membuat permintaan Ajax, dan terkadang hal ini memicu kebutuhan akan penerbangan sebelumnya. Jika API dirancang untuk mengizinkan permintaan lintas sumber, tetapi tidak memerlukan apa pun yang memerlukan penerbangan sebelumnya, hal ini dapat merusak akses.

Kesalahan umum yang memicu hal ini meliputi:

  • mencoba untuk menempatkan Access-Control-Allow-Origindan header tanggapan CORS lainnya atas permintaan tersebut. Ini bukan milik atas permintaan, jangan melakukan apa pun yang membantu (apa gunanya sistem perizinan di mana Anda dapat memberikan izin kepada diri sendiri?), Dan harus muncul hanya pada tanggapan.
  • mencoba meletakkan Content-Type: application/jsonheader pada permintaan GET yang tidak memiliki isi permintaan untuk mendeskripsikan konten (biasanya ketika penulis bingung Content-Typedan Accept).

Dalam salah satu kasus ini, menghapus header permintaan tambahan sering kali cukup untuk menghindari perlunya preflight (yang akan menyelesaikan masalah saat berkomunikasi dengan API yang mendukung permintaan sederhana tetapi bukan permintaan preflighted).


Tanggapan buram

Terkadang Anda perlu membuat permintaan HTTP, tetapi Anda tidak perlu membaca responsnya. misalnya jika Anda memposting pesan log ke server untuk direkam.

Jika Anda menggunakan satu fetchAPI (bukan XMLHttpRequest), maka Anda bisa mengkonfigurasinya untuk tidak mencoba untuk menggunakan CORS.

Perhatikan bahwa ini tidak akan membiarkan Anda melakukan apa pun yang Anda perlukan untuk dilakukan CORS. Anda tidak akan dapat membaca tanggapannya. Anda tidak akan dapat membuat permintaan yang membutuhkan penerbangan sebelumnya.

Ini akan memungkinkan Anda membuat permintaan sederhana, tidak melihat respons, dan tidak mengisi Konsol Pengembang dengan pesan kesalahan.

Bagaimana melakukannya dijelaskan oleh pesan kesalahan Chrome yang diberikan saat Anda membuat permintaan menggunakan fetchdan tidak mendapatkan izin untuk melihat tanggapan dengan CORS:

Akses untuk mengambil di ' https://example.com/' dari asal ' https://example.net' telah diblokir oleh kebijakan CORS: Tidak ada Access-Control-Allow-Originheader ' ' pada sumber daya yang diminta. Jika respons buram memenuhi kebutuhan Anda, setel mode permintaan ke 'tanpa cors' untuk mengambil sumber daya dengan CORS dinonaktifkan.

Jadi:

fetch("http://example.com", { mode: "no-cors" });

Alternatif untuk CORS

JSONP

Bob juga dapat memberikan data menggunakan peretasan seperti JSONP yang merupakan cara orang melakukan Ajax lintas asal sebelum CORS datang.

Ia bekerja dengan menyajikan data dalam bentuk program JavaScript yang memasukkan data ke halaman Mallory.

Itu mengharuskan Mallory mempercayai Bob untuk tidak memberikan kode berbahaya.

Perhatikan tema umum: Situs yang menyediakan data harus memberi tahu browser bahwa tidak masalah bagi situs pihak ketiga untuk mengakses data yang dikirim ke browser.

Karena JSONP bekerja dengan menambahkan <script>elemen untuk memuat data dalam bentuk program JavaScript yang memanggil fungsi yang sudah ada di halaman, mencoba menggunakan teknik JSONP pada URL yang menampilkan JSON akan gagal - biasanya dengan error CORB - karena JSON bukan JavaScript.

Pindahkan dua sumber daya ke satu Asal

Jika dokumen HTML tempat JS berjalan dan URL yang diminta berada pada asal yang sama (berbagi skema, nama host, dan port yang sama) maka Kebijakan Asal yang Sama memberikan izin secara default. CORS tidak diperlukan.

Proxy

Mallory dapat menggunakan kode sisi server untuk mengambil data (yang kemudian dapat diteruskan dari servernya ke browser Alice melalui HTTP seperti biasa).

Ini akan:

  • tambahkan header CORS
  • konversikan tanggapan ke JSONP
  • ada di tempat asal yang sama dengan dokumen HTML

Kode sisi server tersebut dapat ditulis & dihosting oleh pihak ketiga (seperti CORS Anywhere). Perhatikan implikasi privasi dari ini: Pihak ketiga dapat memantau siapa yang membuat proxy apa di server mereka.

Bob tidak perlu memberikan izin apa pun agar hal itu terjadi.

Tidak ada implikasi keamanan di sini karena itu hanya antara Mallory dan Bob. Tidak ada cara bagi Bob untuk berpikir bahwa Mallory adalah Alice dan memberikan Mallory data yang harus dirahasiakan antara Alice dan Bob.

Akibatnya, Mallory hanya bisa menggunakan teknik ini untuk membaca data publik .

Namun, perhatikan bahwa mengambil konten dari situs web orang lain dan menampilkannya sendiri mungkin merupakan pelanggaran hak cipta dan membuat Anda terbuka untuk tindakan hukum.

Menulis sesuatu selain aplikasi web

Seperti disebutkan di bagian "Mengapa Kebijakan Asal yang Sama hanya berlaku untuk JavaScript di halaman web", Anda dapat menghindari SOP dengan tidak menulis JavaScript di halaman web.

Itu tidak berarti Anda tidak dapat terus menggunakan JavaScript dan HTML, tetapi Anda dapat mendistribusikannya menggunakan mekanisme lain, seperti Node-WebKit atau PhoneGap.

Ekstensi browser

Ekstensi browser mungkin saja memasukkan header CORS dalam tanggapan sebelum Kebijakan Asal yang Sama diterapkan.

Ini dapat berguna untuk pengembangan, tetapi tidak praktis untuk situs produksi (tidak masuk akal meminta setiap pengguna situs Anda untuk memasang ekstensi browser yang menonaktifkan fitur keamanan browser mereka).

Mereka juga cenderung bekerja hanya dengan permintaan sederhana (gagal saat menangani permintaan OPTIONS preflight).

Memiliki lingkungan pengembangan yang tepat dengan server pengembangan lokal biasanya merupakan pendekatan yang lebih baik.


Risiko keamanan lainnya

Perhatikan bahwa SOP / CORS tidak mengurangi serangan XSS , CSRF , atau SQL Injection yang perlu ditangani secara independen.


Ringkasan

  • Tidak ada yang dapat Anda lakukan dalam kode sisi klien Anda yang akan mengaktifkan akses CORS ke server orang lain .
  • Jika Anda mengontrol server, permintaan dibuat untuk: Tambahkan izin CORS ke sana.
  • Jika Anda bersahabat dengan orang yang mengendalikannya: Minta mereka untuk menambahkan izin CORS padanya.
  • Jika ini adalah layanan publik:
    • Baca dokumentasi API mereka untuk mengetahui apa yang mereka katakan tentang mengaksesnya dengan JavaScript sisi klien:
      • Mereka mungkin memberitahu Anda untuk menggunakan URL tertentu
      • Mereka mungkin mendukung JSONP
      • Mereka mungkin sama sekali tidak mendukung akses lintas sumber dari kode sisi klien (ini mungkin merupakan keputusan yang disengaja atas dasar keamanan, terutama jika Anda harus meneruskan Kunci API yang dipersonalisasi dalam setiap permintaan).
    • Pastikan Anda tidak memicu permintaan preflight yang tidak Anda butuhkan. API mungkin memberikan izin untuk permintaan sederhana tetapi tidak untuk permintaan pra-penerbangan.
  • Jika tidak ada hal di atas yang berlaku: Alih-alih, biarkan browser berbicara dengan server Anda , lalu minta server Anda mengambil data dari server lain dan menyebarkannya. (Ada juga layanan yang dihosting pihak ketiga yang melampirkan header CORS ke sumber daya yang dapat diakses publik yang dapat Anda gunakan).
Quentin
sumber
Jika saya menjalankan LAN lokal server web dan mencoba melakukan pemuatan ajax dari IP / URL apakah itu akan berfungsi? Saya belum mencobanya. karena server web saya yang mengambil data json akan menjadi MCU
Ciasto piekarz
@Ciastopiekarz - Aturan asal sama / asal berbeda berlaku. Aturan perutean jaringan normal berlaku.
Quentin
25
Jawaban terlengkap yang pernah saya baca, bukan hanya link tentang cors ..
pungggi
@Quentin - Wow! +1! Jadi yang saya pahami adalah jika Alice menggunakan ekstensi CORS, server mengira bahwa panggilan http-nya bukan dari javascript tetapi dari ekstensi browser dan memperlakukannya seperti permintaan asal yang sama?
snippetkid
@snippetkid - Tidak. Dalam kasus biasa, server akan mengirim header CORS dalam setiap respons dan tidak peduli dari mana asal permintaan. Browser bertanggung jawab untuk mengizinkan atau menolak akses ke data ke JS berdasarkan header CORS pada respons. (Hal-hal menjadi / sedikit / lebih kompleks di server saat berhubungan dengan permintaan preflight)
Quentin
3

Server target harus mengizinkan permintaan lintas sumber. Untuk mengizinkannya melalui express, cukup tangani permintaan opsi http:

app.options('/url...', function(req, res, next){
   res.header('Access-Control-Allow-Origin', "*");
   res.header('Access-Control-Allow-Methods', 'POST');
   res.header("Access-Control-Allow-Headers", "accept, content-type");
   res.header("Access-Control-Max-Age", "1728000");
   return res.sendStatus(200);
});
Daphoque
sumber
3

Karena ini tidak disebutkan dalam jawaban yang diterima.

  • Ini bukan kasus untuk pertanyaan persis seperti ini, tetapi mungkin membantu orang lain yang mencari masalah itu
  • Ini adalah sesuatu yang dapat Anda lakukan di kode klien Anda untuk mencegah kesalahan CORS dalam beberapa kasus .

Anda dapat menggunakan Permintaan Sederhana .
Untuk melakukan 'Permintaan Sederhana', permintaan harus memenuhi beberapa ketentuan. Misalnya hanya mengizinkan POST, GETdan HEADmetode, serta hanya mengizinkan beberapa Header tertentu (Anda dapat menemukan semua ketentuan di sini ).

Jika kode klien Anda tidak secara eksplisit mengatur Header yang terpengaruh (misalnya, "Terima") dengan nilai perbaikan dalam permintaan, mungkin terjadi bahwa beberapa klien menyetel Header ini secara otomatis dengan beberapa nilai "non-standar" yang menyebabkan server tidak menerimanya sebagai Permintaan Sederhana - yang akan memberi Anda kesalahan CORS.

zwif
sumber
2

Ini terjadi karena kesalahan CORS. CORS adalah singkatan dari Cross Origin Resource Sharing. Dengan kata sederhana, kesalahan ini terjadi ketika kami mencoba mengakses domain / sumber daya dari domain lain.

Baca Selengkapnya tentang itu di sini: Kesalahan CORS dengan jquery

Untuk memperbaikinya, jika Anda memiliki akses ke domain lain, Anda harus mengizinkan Access-Control-Allow-Origin di server. Ini dapat ditambahkan di header. Anda dapat mengaktifkan ini untuk semua permintaan / domain atau domain tertentu.

Cara membuat permintaan posting berbagi sumber daya lintas sumber (CORS) berfungsi

Tautan ini mungkin membantu

Wisnu
sumber
0

Masalah CORS ini tidak dijelaskan lebih lanjut (untuk penyebab lain).

Saya mengalami masalah ini saat ini karena alasan yang berbeda. Bagian depan saya juga mengembalikan kesalahan header 'Access-Control-Allow-Origin'.

Hanya saja saya telah mengarahkan URL yang salah sehingga tajuk ini tidak tercermin dengan benar (di mana saya terus menganggapnya demikian). localhost (front end) -> panggilan ke http tidak aman (seharusnya https), pastikan titik akhir API dari ujung depan mengarah ke protokol yang benar.

morph85
sumber
0

Saya mendapat kesalahan yang sama di konsol Chrome.

Masalah saya adalah, saya mencoba untuk pergi ke situs menggunakan http://bukan https://. Jadi tidak ada yang perlu diperbaiki, hanya harus pergi ke situs yang sama menggunakan https.

Subhashi
sumber
-1

Permintaan "Dapatkan" dengan menambahkan header yang diubah menjadi permintaan "Opsi". Jadi masalah kebijakan Cors terjadi. Anda harus menerapkan permintaan "Opsi" ke server Anda.

kira
sumber
-6

Anda harus mengaktifkan CORS agar berfungsi.

Perostek Balveda
sumber