Access-Control-Allow-Origin joker karakter alt alanları, bağlantı noktaları ve protokolleri


312

Tüm alt etki alanları, bağlantı noktaları ve protokol için CORS etkinleştirmeye çalışıyorum.

Örneğin, bir XHR isteği çalıştırmak mümkün istiyorum http://sub.mywebsite.com:8080/ için https://www.mywebsite.com/ *

Genellikle, eşleşen (ve sınırlı) kökenlerinden isteği etkinleştirmek istiyorum:

//*.mywebsite.com:*/*

Yanıtlar:


207

DaveRandom en dayanarak cevap , ben de etrafta oynayan ve aynı sonucu (üretir biraz daha basit Apache çözüm bulunmuştur Access-Control-Allow-Originherhangi kuralları yeniden kullanmadan akım belirli protokolü dinamik + domain + liman ayarlanır):

SetEnvIf Origin ^(https?://.+\.mywebsite\.com(?::\d{1,5})?)$   CORS_ALLOW_ORIGIN=$1
Header append Access-Control-Allow-Origin  %{CORS_ALLOW_ORIGIN}e   env=CORS_ALLOW_ORIGIN
Header merge  Vary "Origin"

Ve bu kadar.

Tüm alt etki alanlarına ek olarak ana etki alanında (ör. Mywebsite.com) CORS'yi etkinleştirmek isteyenler, ilk satırdaki normal ifadeyi bununla değiştirebilir:

^(https?://(?:.+\.)?mywebsite\.com(?::\d{1,5})?)$.

Not: Spesifikasyon uyumluluğu ve doğru önbellekleme davranışı Vary: Originiçin, CORS dışı kaynaklar ve izin verilmeyen bir kaynaktan gelenler için bile DAİMA CORS etkin kaynaklar için yanıt üstbilgisi ekleyin ( neden örneğe bakın ).


1
Hemen hemen bu (Vary Origin değil) vardı ve ziyaretçiler aynı yazı tipini kullanarak birden fazla alt alan arasında atladıklarında kötü davranışlar yaşadık. Yazı tipi ve erişim denetimi kökenli üstbilgisi de önbelleğe alındı. Bu konuda küçük bir değişiklik yaptım: İstek bizim izin verilen etki alanlarından birinden ise "Access-Control-Allow-Origin *" kullanın. Belki bu daha önce sahip olmadığımız "Vary Origin" ile çözüldü ... şimdi de ekledik.
Erik Melkersson

2
'Mywebsite.com' ana alanı için çalışmıyor
biology.info

1
@pgmann, //bu bağlamda kaçmaya gerek yoktur , çünkü Apache conf eğik çizgi ile sınırlandırılmış düzenli ifadeler kullanmaz. Regexr şikayet ediyor, çünkü bu bağlamda, eğik çizgiler sınırlayıcı olarak özel bir anlam taşıyor.
Noyo

1
The 'Access-Control-Allow-Origin' header contains multiple values '^(https?://(?:.+.)?aerofotea.com(?::d{1,5})?)$', but only one is allowed. Origin 'http://local.aerofotea.com' is therefore not allowed access.
Aero Wang

3
Bu kodu nereye yerleştiriyorsunuz? .htaccess veya apache sanal ana bilgisayar yapılandırmasında?
Glen

252

CORS spesifikasyonu ya hep ya hiç. Sadece destekler *, nullveya tam protokol + domain + portu: http://www.w3.org/TR/cors/#access-control-allow-origin-response-header

Sunucunuzun, regex'i kullanarak başlangıç ​​başlığını doğrulaması gerekir ve ardından Access-Control-Allow-Origin yanıt üstbilgisinde başlangıç ​​değerini yankılayabilirsiniz.


7
@Dexter "null", bir "null" kaynağına yanıt olarak kullanılabilir; örneğin, bir dosyadan: // şemadan CORS isteği yaparken.
monsur

130
CORS spesifikasyonunun OP'nin tam kullanım durumunu desteklemeyeceği derinden düşünülmektedir .
aroth

6
@aroth: Aslında, özellik uygulamaların istedikleri herhangi bir sözdizimini kullanmasına izin verir ; bu kullanım senaryosunu desteklememesi yalnızca bir uygulama için derinden düşünülebilir . Başka bir deyişle, sunucunuza belirttiğiniz şey ACAO değeri değil, ikincisi sadece bir protokol detayıdır. Benim varsayımım, tekrarlanan menşei gerektiren ya da bundan yararlanan bir güvenlik senaryosu olduğu, ancak saf bir uygulamanın sadece "Tamam" ya da değil diyerek çalıştığıdır.
tne

3
2015'ten Güncelleme: Bu cevap, eksik olduğu ve önbellek sorunlarına yol açabileceği için zararlı olarak kabul edilmelidir. Uygun bir uygulama (Apache için) ve açıklama için lütfen aşağıdaki cevabıma bakın: stackoverflow.com/a/27990162/357774 . Tne işaret olarak da, @aroth, Spec aslında yapar : OP'ın kesin kullanım durumunda izin w3.org/TR/cors/#resource-implementation . Ve bu cevabın işaret ettiği gibi, onu uygulamak sunucuya kalmış. Bu, yukarıda belirtilen cevapta görüldüğü gibi 3 satırda yapılabilir.
Noyo

19
@Hayır - O zaman orijinal anlamımı netleştireceğim. CORS spesifikasyonunun, CORS'yi uygulayan tüm sunucuların OP'nin tam kullanım durumu için otomatik, yerleşik destek sağlamasını kesinlikle gerektirmediği derinden göze çarpmaktadır . Özel PHP kodu, yeniden yazma kuralları veya neye sahip olduğunuzu kullanarak kendi şimlerinizi oluşturması için her bir kullanıcıya bırakmanız, parçalanma, hatalar ve felaket için bir reçetedir. Sunucu geliştiricileri bundan daha iyi bilmelidir; ve eğer yapmazlarsa, CORS spesifikasyonları onları zorlamaya zorlamalıdır.
aroth

59

EDIT : Bunun yerine @ Noyo'nun çözümünü kullanın. Daha basit, daha net ve muhtemelen yük altında çok daha performanslı.

SADECE TARİHİ AMAÇLI ORİJİNAL CEVAP BURADA !!


Bu sorunla uğraştım ve Apache ile çalışan bu yeniden kullanılabilir .htaccess (veya httpd.conf) çözümü ile geldim:

<IfModule mod_rewrite.c>
<IfModule mod_headers.c>
    # Define the root domain that is allowed
    SetEnvIf Origin .+ ACCESS_CONTROL_ROOT=yourdomain.com

    # Check that the Origin: matches the defined root domain and capture it in
    # an environment var if it does
    RewriteEngine On
    RewriteCond %{ENV:ACCESS_CONTROL_ROOT} !=""
    RewriteCond %{ENV:ACCESS_CONTROL_ORIGIN} =""
    RewriteCond %{ENV:ACCESS_CONTROL_ROOT}&%{HTTP:Origin} ^([^&]+)&(https?://(?:.+?\.)?\1(?::\d{1,5})?)$
    RewriteRule .* - [E=ACCESS_CONTROL_ORIGIN:%2]

    # Set the response header to the captured value if there was a match
    Header set Access-Control-Allow-Origin %{ACCESS_CONTROL_ORIGIN}e env=ACCESS_CONTROL_ORIGIN
</IfModule>
</IfModule>

Sadece ACCESS_CONTROL_ROOTbloğun üstündeki değişkeni kök etki alanınıza ayarlayın ve etki alanı ile eşleşiyorsa Origin:istek üstbilgisi değerini Access-Control-Allow-Origin:yanıt üstbilgisi değerinde istemciye geri yansıtacaktır.

Ayrıca sub.mydomain.com, ACCESS_CONTROL_ROOTve olarak kökenleri sub.mydomain.comve *.sub.mydomain.com(yani etki alanı kökü olmak zorunda değildir) ile sınırlayabileceğinizi unutmayın. Değişmesine izin verilen elemanlar (protokol, port) regex'in URI eşleme kısmı değiştirilerek kontrol edilebilir.


22

Bu soruyu cevaplıyorum, çünkü kabul edilen cevap aşağıdakileri yapamaz

  1. regex gruplaması, gerekli olmayan bir performans isabeti .
  2. birincil alanla eşleşemez ve yalnızca alt alan için çalışır.

Örneğin: http://somedomain.mywebsite.com/ için çalışırken http://mywebsite.com için CORS başlıklarını göndermez.

SetEnvIf Origin "http(s)?://(.+\.)?mywebsite\.com(:\d{1,5})?$" CORS=$0

Header set Access-Control-Allow-Origin "%{CORS}e" env=CORS
Header merge  Vary "Origin"

Sitenizi etkinleştirmek için, yukarıdaki Apache Yapılandırmasında sitenizi "sitem.com" yerine koymanız yeterlidir.

Birden çok siteye izin vermek için:

SetEnvIf Origin "http(s)?://(.+\.)?(othersite\.com|mywebsite\.com)(:\d{1,5})?$" CORS=$0

Dağıtımdan sonra test etme:

Aşağıdaki kıvrılma yanıtı, değişiklikten sonra "Access-Control-Allow-Origin" üstbilgisine sahip olmalıdır.

curl -X GET -H "Origin: http://examplesite1.com" --verbose http://examplesite2.com/query

12

Ben sadece PHP de bir çözüm gerekiyordu, bu yüzden sadece birisi de ihtiyaç durumunda. "* .Example.com" gibi izin verilen bir giriş dizesi alır ve giriş eşleşirse istek üstbilgisi sunucu adını döndürür.

function getCORSHeaderOrigin($allowed, $input)
{
    if ($allowed == '*') {
        return '*';
    }

    $allowed = preg_quote($allowed, '/');

    if (($wildcardPos = strpos($allowed, '*')) !== false) {
        $allowed = str_replace('*', '(.*)', $allowed);
    }

    $regexp = '/^' . $allowed . '$/';

    if (!preg_match($regexp, $input, $matches)) {
        return 'none';
    }

    return $input;
}

Ve bir phpunit veri sağlayıcısı için test örnekleri:

//    <description>                            <allowed>          <input>                   <expected>
array('Allow Subdomain',                       'www.example.com', 'www.example.com',        'www.example.com'),
array('Disallow wrong Subdomain',              'www.example.com', 'ws.example.com',         'none'),
array('Allow All',                             '*',               'ws.example.com',         '*'),
array('Allow Subdomain Wildcard',              '*.example.com',   'ws.example.com',         'ws.example.com'),
array('Disallow Wrong Subdomain no Wildcard',  '*.example.com',   'example.com',            'none'),
array('Allow Double Subdomain for Wildcard',   '*.example.com',   'a.b.example.com',        'a.b.example.com'),
array('Don\'t fall for incorrect position',    '*.example.com',   'a.example.com.evil.com', 'none'),
array('Allow Subdomain in the middle',         'a.*.example.com', 'a.bc.example.com',       'a.bc.example.com'),
array('Disallow wrong Subdomain',              'a.*.example.com', 'b.bc.example.com',       'none'),
array('Correctly handle dots in allowed',      'example.com',     'exampleXcom',            'none'),

1
+1, kullanmak preg_quote()için düzenlendi, çünkü bunu yapmanın doğru yolu budur ( .DNS adında geçerli olan tek regexp meta char olsa da preg_quote(), amaçlanan işlemi daha iyi açıklar)
DaveRandom

1
noneSpesifikasyona göre başlık için anlamsal olarak geçerli bir değer olmadığı (veya en azından ima ettiği şeyi yapmadığı) açıklığa kavuşturulmalıdır . Bu nedenle, return null;bu dal için daha anlamlı olabilir ve bu durumda istemciye hiçbir başlık gönderilmemelidir, bu nedenle arayan tarafından kontrol edilmelidir.
DaveRandom

preg_quote()* işaretini koyar ve böylece str_replace()öksüz bırakılmış bir "\" bırakır.
Christoffer Bubach

1
bu yararlıdır, sitemin ajax'ta "www" olduğunu ancak kalıcı bağlantı yapısında olmadığını anlayana kadar CORS sorununda zaman geçirdim - çözümünüz sorunun nerede olduğunu anlamama yardımcı oldu ve bunu benim için çözdü.
Sol

3

Access-Control-Allow-Origin.Htaccess ayarını yaparken yalnızca aşağıdakiler işe yaradı:

SetEnvIf Origin "http(s)?://(.+\.)?domain\.com(:\d{1,5})?$" CRS=$0
Header always set Access-Control-Allow-Origin "%{CRS}e" env=CRS

Ben birkaç diğer önerilen anahtar çalıştı Header append, Header set, hiçbiri çalıştı bu anahtar kelimeler eski veya geçerli değilse hiçbir fikrim yok gerçi, SO birçok cevapları önerildiği üzere nginx .

İşte benim tam çözümüm:

SetEnvIf Origin "http(s)?://(.+\.)?domain\.com(:\d{1,5})?$" CRS=$0
Header always set Access-Control-Allow-Origin "%{CRS}e" env=CRS
Header merge Vary "Origin"

Header always set Access-Control-Allow-Methods "GET, POST"
Header always set Access-Control-Allow-Headers: *

# Cached for a day
Header always set Access-Control-Max-Age: 86400

RewriteEngine On

# Respond with 200OK for OPTIONS
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule ^(.*)$ $1 [R=200,L]

2

"Çerez alanından" (www.domain.tld) ​​yazı tiplerini okurken Font Awesome ile statik "çerezsiz" bir alanda benzer sorunlar yaşıyorduk ve bu yazı bizim kahramanımızdı. Buraya bakın: 'Eksik Kaynaklar Arası Kaynak Paylaşımı (CORS) Yanıt Başlığı' web yazı tipi sorununu nasıl düzeltebilirim?

Copy / paste-r türleri (ve bazı aksesuarlar vermek için) bunu tüm katkılardan bir araya getirdim ve site kökünün .htaccess dosyasının üstüne ekledim:

<IfModule mod_headers.c>
 <IfModule mod_rewrite.c>
    SetEnvIf Origin "http(s)?://(.+\.)?(othersite\.com|mywebsite\.com)(:\d{1,5})?$" CORS=$0
    Header set Access-Control-Allow-Origin "%{CORS}e" env=CORS
    Header merge  Vary "Origin"
 </IfModule>
</IfModule>

Süper Güvenli, Süper Zarif. Bayılırım: Sunucularınızı bant genişliğini kaynak hırsızları / hot-link-er türlerine açmak zorunda değilsiniz.

Destekleyenler: @Noyo @DaveRandom @ pratap-koritala

(Bunu kabul edilen cevaba bir yorum olarak bırakmaya çalıştım, ancak henüz yapamıyorum)



0

Orijinal cevap Apache 2.4 öncesi için gibi görünüyor. Benim için işe yaramadı. İşte 2.4'te çalışması için değiştirmek zorunda kaldım. Bu, şirketinizin alt etki alanı derinliği için işe yarar .

SetEnvIf Host ^((?:.+\.)*yourcompany\.com?)$    CORS_ALLOW_ORIGIN=$1
Header append Access-Control-Allow-Origin  %{REQUEST_SCHEME}e://%{CORS_ALLOW_ORIGIN}e    env=CORS_ALLOW_ORIGIN
Header merge  Vary "Origin"

0

Lars'ın cevabını, regex'te yetim kalan bir sonuç olarak \, sadece gerçek ana bilgisayarı (protokole veya bağlantı noktasına dikkat etmeyerek) karşılaştırmak için biraz değiştirmek zorunda kaldım ve localhostüretim alanımın yanı sıra etki alanını desteklemek istedim . Böylece $allowedparametreyi bir dizi olarak değiştirdim.

function getCORSHeaderOrigin($allowed, $input)
{
    if ($allowed == '*') {
        return '*';
    }

    if (!is_array($allowed)) {
        $allowed = array($allowed);
    }

    foreach ($allowed as &$value) {
        $value = preg_quote($value, '/');

        if (($wildcardPos = strpos($value, '\*')) !== false) {
            $value = str_replace('\*', '(.*)', $value);
        }
    }

    $regexp = '/^(' . implode('|', $allowed) . ')$/';

    $inputHost = parse_url($input, PHP_URL_HOST);

    if ($inputHost === null || !preg_match($regexp, $inputHost, $matches)) {
        return 'none';
    }

    return $input;
}

Kullanım aşağıdaki gibi:

if (isset($_SERVER['HTTP_ORIGIN'])) {
    header("Access-Control-Allow-Origin: " . getCORSHeaderOrigin(array("*.myproduction.com", "localhost"), $_SERVER['HTTP_ORIGIN']));
}

0

benim durumumda açısal kullanarak

HTTP önleme aracımda

with Credentials: true.

isteğin başlığında

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.