cara mem-bypass Access-Control-Allow-Origin?

197

Saya melakukan panggilan ajax ke server saya sendiri pada platform yang mereka tetapkan untuk mencegah panggilan ajax ini (tapi saya membutuhkannya untuk mengambil data dari server saya untuk menampilkan data yang diambil dari database server saya). Skrip ajax saya berfungsi, ia dapat mengirim data ke skrip php server saya untuk memungkinkannya diproses. Namun itu tidak bisa mendapatkan kembali data yang diproses karena diblokir oleh"Access-Control-Allow-Origin"

Saya tidak memiliki akses ke sumber / inti platform itu. jadi saya tidak bisa menghapus skrip yang melarang saya melakukannya. (P / SI menggunakan Google Chrome's Console dan menemukan kesalahan ini)

Kode Ajax seperti yang ditunjukkan di bawah ini:

 $.ajax({
     type: "GET",
     url: "http://example.com/retrieve.php",
     data: "id=" + id + "&url=" + url,
     dataType: 'json',   
     cache: false,
     success: function(data)
      {
        var friend = data[1];              
        var blog = data[2];           
        $('#user').html("<b>Friends: </b>"+friend+"<b><br> Blogs: </b>"+blog);

      } 
  });

atau adakah JSONkode yang setara dengan skrip ajax di atas? Saya pikir JSONdiperbolehkan.

Saya harap seseorang bisa membantu saya.

ETAN
sumber
semua jawaban untuk pertanyaan Anda sejauh ini menjelaskan cara untuk menulis ulang kode server Anda sehingga Anda ajax akan bekerja. Tak satu pun dari mereka tentang memintas, seperti yang Anda tanyakan secara khusus dalam pertanyaan Anda. Apakah Anda tetap benar-benar memintas tajuk ini? Saya benar-benar ragu akan ada satu.
Moradnejad
tidak ada cara untuk melewati itu. tetapi Anda bisa meletakkan file di backend Anda yang melakukan permintaan. Jadi, Anda memanggil per ajax file di server Anda sendiri, file itu memuat data dari recoverve.php dan mengirimkannya kembali ke javascript Anda. Jika demikian, tidak ada aturan CORS yang menghalangi Anda.
Jona Paulus

Jawaban:

367

Letakkan ini di atas recoverve.php:

header('Access-Control-Allow-Origin: *');  

Perhatikan bahwa ini secara efektif menonaktifkan perlindungan CORS, dan membuat pengguna Anda rentan terhadap serangan. Jika Anda tidak sepenuhnya yakin bahwa Anda harus mengizinkan semua asal, Anda harus mengunci ini ke asal yang lebih spesifik:

header('Access-Control-Allow-Origin: https://www.example.com')

Silakan merujuk ke jawaban tumpukan berikut untuk pemahaman lebih baik Access-Control-Allow-Origin

https://stackoverflow.com/a/10636765/413670

Rafay
sumber
54
Itu agak tidak aman. Lihatlah jawaban saya di bagian bawah.
Rob
3
tnx, tetapi Anda tidak boleh mengizinkan akses ke semua asal seperti yang disebutkan oleh @RobQuist dalam komentarnya, dan dalam jawabannya memberikan pendekatan yang lebih baik
Rafay
2
Jadi saya menemukan halaman ini karena saya harus benar-benar 'memotong' Kontrol Akses di server. Solusinya di sini bukan mem-bypass apa pun tetapi cukup mengkonfigurasi Kontrol Akses di servernya sendiri. Jika ada orang di luar sana yang sebenarnya perlu mem-bypass ini, mereka dapat menggunakan file_get_contents PHP ($ remote_url) ;. Jelas ada banyak cara untuk melakukan ini tetapi ini adalah bagaimana saya melakukannya.
Shawn Whinnery
1
@ShawnWhinnery yang pada dasarnya adalah tindakan "proxying". Solusi yang bagus jika Anda benar-benar ingin memuat data secara dinamis dari situs web lain yang tidak dapat Anda kendalikan.
Rob
1
ingin menjalankan skrip PHP dari dotnet core - memindahkan skrip php ke URL saya yang lain tetapi mendapatkan kesalahan skrip lintas situs. menambahkan kode yang Anda perlihatkan ke atas PHP dan bekerja dengan sempurna. Terima kasih!
raddevus
291

Oke, tetapi Anda semua tahu bahwa * adalah wildcard dan memungkinkan skrip lintas situs dari setiap domain?

Anda ingin mengirim beberapa Access-Control-Allow-Origintajuk untuk setiap situs yang diizinkan - tetapi sayangnya secara resmi tidak didukung untuk mengirim Access-Control-Allow-Origintajuk ganda , atau memasukkan banyak asal.

Anda dapat menyelesaikan ini dengan memeriksa asal, dan mengirim kembali yang di header, jika diizinkan:

$origin = $_SERVER['HTTP_ORIGIN'];
$allowed_domains = [
    'http://mysite1.com',
    'https://www.mysite2.com',
    'http://www.mysite2.com',
];

if (in_array($origin, $allowed_domains)) {
    header('Access-Control-Allow-Origin: ' . $origin);
}

Itu jauh lebih aman. Anda mungkin ingin mengedit yang cocok dan mengubahnya ke fungsi manual dengan beberapa regex, atau sesuatu seperti itu. Setidaknya ini hanya akan mengirim kembali 1 header, dan Anda akan yakin itu salah satu yang berasal dari permintaan. Harap perhatikan bahwa semua tajuk HTTP bisa dipalsukan, tetapi tajuk ini untuk perlindungan klien. Jangan lindungi data Anda sendiri dengan nilai-nilai itu. Jika Anda ingin tahu lebih banyak, bacalah sedikit tentang CORS dan CSRF.

Kenapa lebih aman?

Mengizinkan akses dari lokasi lain maka situs tepercaya Anda sendiri memungkinkan untuk melakukan highjacking sesi. Saya akan menggunakan sedikit contoh - gambar Facebook memungkinkan asal wildcard - ini berarti Anda dapat membuat situs web Anda sendiri di suatu tempat, dan menjadikannya memecat panggilan AJAX (atau buka iframe) ke facebook. Ini berarti Anda dapat mengambil info masuk dari facebook dari pengunjung situs web Anda. Lebih buruk lagi - Anda dapat membuat skrip POSTpermintaan dan mengirim data di Facebook seseorang - tepat saat mereka meramban situs web Anda.

Berhati-hatilah saat menggunakan ACAOheader!

rampok
sumber
12
Saya pikir Anda perlu meletakkan http: // di depan setiap item dalam daftar. Setidaknya saya lakukan untuk satu situs yang saya kerjakan.
blak3r
2
Sayangnya, ini sepertinya tidak berhasil. Saya percaya bahwa hanya satu pengecualian yang dapat diberikan per panggilan ke tajuk ().
lewsid
5
@Shanimal & lewsid -> Saya kira koma yang dipisah memang tidak berfungsi. Referensi: w3.org/TR/cors
Rob
3
Untuk berurusan dengan daftar domain, berikut jawaban yang relevan: stackoverflow.com/a/1850482/766177
Valentin Despa
13
Tidak ada gunanya menambahkan 4 header seperti itu karena setiap panggilan untuk header()mengganti header sebelumnya dari jenis yang sama. Jadi sebenarnya yang Anda lakukan adalah mengatur tajuk terakhir. The pengguna entri menyatakan bahwa Anda dapat mengatur parameter kedua falseuntuk mencegah header sebelumnya menjadi ditimpa.
BadHorsie
31

Peringatan , Chrome (dan browser lain) akan mengeluh bahwa beberapa header ACAO disetel jika Anda mengikuti beberapa jawaban lainnya.

Kesalahannya akan seperti XMLHttpRequest cannot load ____. The 'Access-Control-Allow-Origin' header contains multiple values '____, ____, ____', but only one is allowed. Origin '____' is therefore not allowed access.

Coba ini:

$http_origin = $_SERVER['HTTP_ORIGIN'];

$allowed_domains = array(
  'http://domain1.com',
  'http://domain2.com',
);

if (in_array($http_origin, $allowed_domains))
{  
    header("Access-Control-Allow-Origin: $http_origin");
}

sumber
6
Ini adalah solusi yang lebih baik daripada yang saya posting.
Rob
7

Saya telah memperbaiki masalah ini saat memanggil Kontroler MVC3. Saya tambahkan:

Response.AddHeader("Access-Control-Allow-Origin", "*"); 

sebelum saya

return Json(model, JsonRequestBehavior.AllowGet);

Dan saya juga $.ajaxmengeluh bahwa itu tidak menerima header tipe-konten dalam panggilan ajax saya, jadi saya berkomentar karena saya tahu JSON-nya dilewatkan ke Action.

Semoga itu bisa membantu.

Atif Rehman
sumber
2

Ini adalah ide yang sangat buruk untuk digunakan *, yang membuat Anda terbuka lebar untuk cross scripting situs. Pada dasarnya Anda ingin domain Anda sendiri sepanjang waktu, mencakup pengaturan SSL Anda saat ini, dan opsional domain tambahan. Anda juga ingin semuanya dikirim sebagai satu tajuk. Berikut ini akan selalu mengesahkan domain Anda sendiri dalam lingkup SSL yang sama dengan halaman saat ini, dan secara opsional juga dapat menyertakan sejumlah domain tambahan. Ini akan mengirim mereka semua sebagai satu tajuk, dan menimpa yang sebelumnya jika ada sesuatu yang sudah dikirim mereka untuk menghindari kemungkinan browser menggerutu tentang beberapa tajuk kontrol akses yang dikirim.

class CorsAccessControl
{
    private $allowed = array();

    /**
     * Always adds your own domain with the current ssl settings.
     */
    public function __construct()
    {
        // Add your own domain, with respect to the current SSL settings.
        $this->allowed[] = 'http'
            . ( ( array_key_exists( 'HTTPS', $_SERVER )
                && $_SERVER['HTTPS'] 
                && strtolower( $_SERVER['HTTPS'] ) !== 'off' ) 
                    ? 's' 
                    : null )
            . '://' . $_SERVER['HTTP_HOST'];
    }

    /**
     * Optionally add additional domains. Each is only added one time.
     */
    public function add($domain)
    {
        if ( !in_array( $domain, $this->allowed )
        {
            $this->allowed[] = $domain;
        }
    /**
     * Send 'em all as one header so no browsers grumble about it.
     */
    public function send()
    {
        $domains = implode( ', ', $this->allowed );
        header( 'Access-Control-Allow-Origin: ' . $domains, true ); // We want to send them all as one shot, so replace should be true here.
    }
}

Pemakaian:

$cors = new CorsAccessControl();

// If you are only authorizing your own domain:
$cors->send();

// If you are authorizing multiple domains:
foreach ($domains as $domain)
{
    $cors->add($domain);
}
$cors->send();

Anda mendapatkan idenya.

mopsyd
sumber
1

Sudahkah Anda mencoba menambahkan tajuk Akses-Kontrol-Bolehkan-Asal ke respons yang dikirim dari server Anda? Seperti Access-Control-Allow-Origin: *,?

Daniel Brockman
sumber
1
Ini adalah tajuk HTTP yang dikirim oleh server Anda untuk memberi tahu browser bahwa boleh saja mengungkapkan hasilnya ke skrip panggilan meskipun faktanya domain asal skrip tidak cocok dengan domain server. Baca tentang Berbagi Sumber Daya Lintas-Asal !
Daniel Brockman