XMLHttpRequest tidak dapat memuat XXX No header 'Access-Control-Allow-Origin'
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 mulai menampilkan 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 resource yang diminta. Oleh karena itu, asal ' http: // localhost: 4300 ' tidak diizinkan untuk diakses.
Apa yang menghentikan saya mengakses halaman ini?
Jawaban
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:4300
dalam 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 XMLHttpRequest
dan membaca responseText
.
Kebijakan Asal yang Sama dari 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 asal 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 jika 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-Origin
HTTP 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 mengizinkan situs tertentu untuk mengaksesnya, dan Bob dapat secara dinamis membuat 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 membantu.
NB: Beberapa permintaan rumit dan mengirimkan 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-Origin
ke 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 untuk 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 melakukan sesuatu dengan benar 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
, POST
atau apa pun yang Anda coba kirim) dan menanggapinya dengan benar. Access-Control-Allow-Origin
header tetapi juga Access-Control-Allow-Methods
dan Access-Control-Allow-Headers
untuk 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-Origin
dan header tanggapan CORS lainnya atas permintaan tersebut. Ini bukan milik atas permintaan, tidak 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/json
header pada permintaan GET yang tidak memiliki isi permintaan untuk mendeskripsikan konten (biasanya ketika penulis bingungContent-Type
danAccept
).
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 fetch
API (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 fetch
dan 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 adaAccess-Control-Allow-Origin
header ' ' 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 lintas asal Ajax sebelum CORS datang.
Ini 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 dikirimkan 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
- ubah respons menjadi 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 dapat memasukkan header CORS dalam respons 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 mengontrolnya: 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 di 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.
- Baca dokumentasi API mereka untuk mengetahui apa yang mereka katakan tentang mengaksesnya dengan JavaScript sisi klien:
- Jika tidak ada satu pun 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).
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);
});
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
, GET
dan HEAD
metode, 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 tetap 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.
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
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 header ini tidak tercermin dengan benar (di mana saya terus menganggapnya demikian). localhost (front end) -> panggil ke http tidak aman (seharusnya https), pastikan titik akhir API dari ujung depan mengarah ke protokol yang benar.
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
.
Bug ini menghabiskan biaya 2 hari. Saya memeriksa log Server saya, permintaan / respons Opsi Preflight antara browser Chrome / Edge dan Server baik-baik saja. Alasan utamanya adalah respons server GET / POST / PUT / DELETE untuk XHTMLRequest juga harus memiliki tajuk berikut:
access-control-allow-origin: origin
"origin" ada di header permintaan (Browser akan menambahkannya untuk meminta Anda). sebagai contoh:
Origin: http://localhost:4221
Anda dapat menambahkan tajuk tanggapan seperti berikut untuk menerima semua:
access-control-allow-origin: *
atau header respons untuk permintaan khusus seperti:
access-control-allow-origin: http://localhost:4221
Pesan di browser tidak jelas untuk dipahami: "... Sumber daya yang diminta"
perhatikan bahwa: CORS berfungsi dengan baik untuk localhost. port berbeda berarti Domain berbeda. jika Anda mendapatkan pesan kesalahan, periksa konfigurasi CORS di sisi server.