Access-Control-Allow-Origin nasıl atlanır?


198

Ayarladığım bir platformda kendi sunucuma ajax çağrısı yapıyorum, bu ajax çağrılarını engelliyorlar (ancak sunucumun veritabanından alınan verileri görüntülemek için sunucumdan veri almam gerekiyor). Ajax betiğim çalışıyor, işlemek için sunucumun php betiğine veri gönderebilir. Ancak, işlenen verileri engellediği için geri alamaz"Access-Control-Allow-Origin"

Bu platformun kaynağına / çekirdeğine erişimim yok. bu yüzden senaryoyu kaldıramam ve bunu yapmama izin vermedi. (P / SI, Google Chrome Konsolu'nu kullandı ve bu hatayı buldu)

Aşağıda gösterildiği gibi Ajax kodu:

 $.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);

      } 
  });

veya JSONyukarıdaki ajax betiğine eşdeğer bir kod var mı? Bence JSONizin veriliyor.

Umarım birisi bana yardım edebilir.


şu ana kadar sorunuzun tüm yanıtları, sunucu kodunuzu yeniden yazmanın bir yolunu açıkladı, böylece ajax çalışacak. Sorunuzda özellikle sorduğunuz gibi, hiçbiri bypass ile ilgili değildir. Bu başlığı gerçekten atlamak için yine de buldunuz mu? Gerçekten olacağından şüpheliyim.
Moradnejad

onu atlatmanın bir yolu yok. ancak arka ucunuza isteği gerçekleştiren bir dosya koyabilirsiniz. Böylece ajax başına dosyayı kendi sunucunuzda çağırırsınız, bu dosya retrieve.php'deki verileri yükler ve bunları javascriptinize geri gönderir. Bu durumda sizi engelleyen CORS kuralları yoktur.
Jona Paulus

Yanıtlar:


367

Bunu retrieve.php dosyasının üstüne koyun:

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

Bunun CORS korumasını etkin bir şekilde devre dışı bıraktığını ve kullanıcılarınızı saldırıya maruz bıraktığını unutmayın. Tüm kökenlere izin vermeniz gerektiğinden tam olarak emin değilseniz , bunu daha belirli bir kökene kilitlemelisiniz:

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

Daha iyi anlamak için lütfen aşağıdaki yığın cevabına bakın Access-Control-Allow-Origin

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


54
Bu oldukça güvensiz. Cevabımı en altta kontrol et.
Rob

3
tnx, ancak @RobQuist tarafından yorumunda belirtildiği gibi tüm kökenlere erişime izin vermemelisiniz ve cevabında daha iyi bir yaklaşım sağlandı
Rafay

2
Bu yüzden bu sayfayı buldum çünkü erişim kontrolünü bir sunucuda 'baypas etmem' gerekti. Buradaki çözüm hiçbir şeyi atlamak değil, Erişim Kontrolünü kendi sunucusunda düzgün bir şekilde yapılandırmaktır. Orada kimse gerçekten bunu atlamak gerekiyorsa onlar PHP'nin file_get_contents ($ remote_url); kullanabilirsiniz. Bunu yapmanın pek çok yolu var ama ben böyle yaptım.
Shawn Whinnery

1
@ShawnWhinnery temelde "vekil" eylemidir. Gerçekten kontrolünüz olmayan başka bir web sitesinden dinamik olarak veri yüklemek istiyorsanız iyi bir çözüm.
Rob

1
PHP betiğini dotnet core'dan çalıştırmak istedim - php betiğini diğer URL'ye taşıdı ama siteler arası betik hatası alıyordu. gösterdiğiniz kodu PHP'nin üstüne ekledi ve mükemmel çalıştı. Teşekkürler!
raddevus

291

Tamam, ama hepiniz * bir joker karakter olduğunu ve her alandan siteler arası komut dosyası oluşturmaya izin verdiğini biliyor musunuz?

Access-Control-Allow-Originİzin verilen her site için birden fazla başlık göndermek istiyorsunuz - ancak maalesef resmi olarak birden fazla Access-Control-Allow-Originbaşlık göndermek veya birden çok köken koymak için desteklenmiyor .

Kökeni kontrol ederek ve izin veriliyorsa başlıkta geri göndererek bunu çözebilirsiniz:

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

Bu çok daha güvenli. Eşleştirmeyi düzenlemek ve bir miktar normal ifadeyle manuel bir işleve veya bunun gibi bir şeye değiştirmek isteyebilirsiniz. En azından bu sadece 1 üstbilgiyi geri gönderecek ve sizden istek geldiğinden emin olacaksınız. Lütfen tüm HTTP başlıklarının sahte olabileceğini unutmayın , ancak bu başlık istemcinin koruması içindir. Kendi verilerinizi bu değerlerle korumayın. Daha fazla bilgi edinmek istiyorsanız, CORS ve CSRF'de biraz okuyun.

Neden daha güvenli?

Kendi güvenilir sitenizden başka konumlardan erişime izin vermek, oturumun üstesinden gelmeye izin verir. Küçük bir örnekle gideceğim - image Facebook joker karakterli bir kökene izin veriyor - bu, kendi web sitenizi bir yerde yapabileceğiniz ve AJAX çağrılarını (veya iframe'leri açabileceğiniz) facebook'a gönderebileceğiniz anlamına geliyor. Bu, web sitenizin bir ziyaretçisinin facebookunun giriş bilgilerini alabileceğiniz anlamına gelir. Daha da kötüsü POST, web sitenize göz atarken istedikleri komutları yazabilir ve birinin facebook'una veri gönderebilirsiniz.

ACAOBaşlıkları kullanırken çok dikkatli olun !


12
Listedeki her öğenin önüne http: // koymanız gerektiğini düşünüyorum. En azından üzerinde çalıştığım bir site için yaptım.
blak3r

2
Ne yazık ki, bu işe yaramıyor gibi görünüyor. Header () çağrısı başına yalnızca bir istisna sağlanabileceğine inanıyorum.
lewsid

5
@Shanimal & lewsid -> Ayrılmış virgül gerçekten işe yaramaz sanırım. Referans: w3.org/TR/cors
Rob

3
Alan

13
Bu, böyle 4 başlık eklemek anlamsızdır, çünkü her çağrı header()aynı türdeki önceki başlığın yerini alır. Gerçekten yaptığınız tek şey son başlığı ayarlamak. Elle giriş ait ikinci bir parametreyi ayarlayabilirsiniz belirtiyor falseönceki başlık üstüne kaydetmeden önlemek için.
BadHorsie

31

Uyarı , Chrome (ve diğer tarayıcılar), diğer yanıtlardan bazılarını izlerseniz birden fazla ACAO üstbilgisinin ayarlandığından şikayet edecektir.

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

Bunu dene:

$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");
}

6
Bu benim gönderdiğimden daha iyi bir çözüm.
Rob

7

Bir MVC3 Denetleyicisi çağırırken bu sorunu giderdim. Ekledim:

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

benden önce

return Json(model, JsonRequestBehavior.AllowGet);

Ve ayrıca benim ajax çağrımda İçerik türü üstbilgiyi $.ajaxkabul etmediğinden şikayet ediyordum , bu yüzden JSON'un Eylem'e geçtiğini bildiğim için yorum yaptım.

Umarım yardımcı olur.


2

Kullanmak gerçekten kötü bir fikir *, bu da siteler arası komut dosyası oluşturmaya açık kalmanızı sağlar. Temel olarak her zaman kendi alan adınızı, mevcut SSL ayarlarınızı ve isteğe bağlı olarak ek alan adlarını kapsamayı istersiniz. Ayrıca hepsinin tek bir başlık olarak gönderilmesini de istersiniz. Aşağıdakiler her zaman kendi alan adınızı geçerli sayfayla aynı SSL kapsamında yetkilendirir ve isteğe bağlı olarak herhangi bir sayıda ek alan içerebilir. Hepsini tek bir başlık olarak gönderir ve tarayıcının birden fazla erişim denetim başlığı hakkında homurdanma olasılığını önlemek için başka bir şey zaten gönderdiyse bir öncekinin üzerine yazar.

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

Kullanımı:

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

Kaptın bu işi.


1

Sunucunuzdan gönderilen yanıta gerçekten Access-Control-Allow-Origin üstbilgisini eklemeyi denediniz mi? Gibi Access-Control-Allow-Origin: *?


1
Komut dosyasının başlangıç ​​etki alanının sunucunun etki alanıyla eşleşmese de, sunucuyu tarayıcıya sonucu göstermenin uygun olduğunu tarayıcıya bildirmek için gönderdiği bir HTTP üst bilgisidir. Kaynaklar Arası Kaynak Paylaşımı konusunu okuyun !
Daniel Brockman
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.