إمكانية التحكم-السماح بالسماح المجالات الأصلية الأصلية؟

StackOverflow https://stackoverflow.com/questions/1653308

سؤال

هل هناك طريقة للسماح للمجالات عبر متعددة باستخدام Access-Control-Allow-Origin رأس؟

أنا على علم *, ، لكنها منفتحة جدا. أريد حقا السماح فقط بزوجين مجالات.

كمثال، شيء مثل هذا:

Access-Control-Allow-Origin: http://domain1.example, http://domain2.example

لقد جربت الرمز أعلاه ولكن لا يبدو أنه يعمل في فايرفوكس.

هل من الممكن تحديد مجالات متعددة أو أنا عالق مع واحد فقط؟

هل كانت مفيدة؟

المحلول

يبدو أن الطريقة الموصى بها للقيام بذلك هي أن يكون الخادم الخاص بك يقرأ رأس الأصل من العميل، وقارن ذلك إلى قائمة المجالات التي ترغب في السماح بها، وإذا تطابق، صدى قيمة Origin رأس العودة إلى العميل كما Access-Control-Allow-Origin رأس في الاستجابة.

مع .htaccess يمكنك أن تفعل ذلك مثل هذا:

# ----------------------------------------------------------------------
# Allow loading of external fonts
# ----------------------------------------------------------------------
<FilesMatch "\.(ttf|otf|eot|woff|woff2)$">
    <IfModule mod_headers.c>
        SetEnvIf Origin "http(s)?://(www\.)?(google.com|staging.google.com|development.google.com|otherdomain.example|dev02.otherdomain.example)$" AccessControlAllowOrigin=$0
        Header add Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
        Header merge Vary Origin
    </IfModule>
</FilesMatch>

نصائح أخرى

حل آخر أستخدمه في PHP:

$http_origin = $_SERVER['HTTP_ORIGIN'];

if ($http_origin == "http://www.domain1.com" || $http_origin == "http://www.domain2.com" || $http_origin == "http://www.domain3.com")
{  
    header("Access-Control-Allow-Origin: $http_origin");
}

هذا عملت بالنسبة لي:

SetEnvIf Origin "^http(s)?://(.+\.)?(domain\.example|domain2\.example)$" origin_is=$0 
Header always set Access-Control-Allow-Origin %{origin_is}e env=origin_is

عند وضعها في .htaccess, ، سوف تعمل بالتأكيد.

كان لدي نفس المشكلة مع خطوط Woff- خطوط فرعية متعددة يمكن الوصول إليها. للسماح للنفط الفرعية أضفت شيئا مثل هذا إلى httpd.conf:

SetEnvIf Origin "^(.*\.example\.com)$" ORIGIN_SUB_DOMAIN=$1
<FilesMatch "\.woff$">
    Header set Access-Control-Allow-Origin "%{ORIGIN_SUB_DOMAIN}e" env=ORIGIN_SUB_DOMAIN
</FilesMatch>

لمجالات متعددة يمكنك فقط تغيير Regex في SetEnvIf.

إليك كيفية صدى رأس المنشأ مرة أخرى إذا تطابق مجالك باستخدام Nginx، فهذا مفيد إذا كنت ترغب في تقديم خطط متعددة الخطيات:

location /fonts {
    # this will echo back the origin header
    if ($http_origin ~ "example.org$") {
        add_header "Access-Control-Allow-Origin" $http_origin;
    }
}

إليك ما فعلته للحصول على تطبيق PHP الذي يتم طلبه بواسطة AJAX

$request_headers        = apache_request_headers();
$http_origin            = $request_headers['Origin'];
$allowed_http_origins   = array(
                            "http://myDumbDomain.example"   ,
                            "http://anotherDumbDomain.example"  ,
                            "http://localhost"  ,
                          );
if (in_array($http_origin, $allowed_http_origins)){  
    @header("Access-Control-Allow-Origin: " . $http_origin);
}

إذا سمح الأصل الطالب بالخادم الخاص بي، فأعد $http_origin نفسها كقيمة Access-Control-Allow-Origin رأس بدلا من العودة * البدل.

هناك عيوب واحدة يجب أن تكون على دراية بها: بمجرد الخروج من الملفات الخارجية إلى CDN (أو أي خادم آخر لا يسمح بالبرمجة النصية) أو إذا تم تخزين ملفاتك مؤقتا على وكيل وتغيير الاستجابة بناء على "أصل" عنوان الطلب لن يعمل.

لمجالات متعددة، في الخاص بك .htaccess:

<IfModule mod_headers.c>
    SetEnvIf Origin "http(s)?://(www\.)?(domain1.example|domain2.example)$" AccessControlAllowOrigin=$0$1
    Header add Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
    Header set Access-Control-Allow-Credentials true
</IfModule>

بالنسبة لمستخدمي Nginx للسماح ل Cors لمجالات متعددة. أنا أحب مثال @ مارشال على الرغم من أن مشاحناته يطابقون فقط مجال واحد. لتتناسب مع قائمة المجال والنفم الفرعي، فإن هذا Regex يجعله سهلا للعمل مع الخطوط:

location ~* \.(?:ttf|ttc|otf|eot|woff|woff2)$ {
   if ( $http_origin ~* (https?://(.+\.)?(domain1|domain2|domain3)\.(?:me|co|com)$) ) {
      add_header "Access-Control-Allow-Origin" "$http_origin";
   }
}

سيؤدي هذا إلى صدى فقط رؤوس "التحكم في الوصول إلى الأصل" الذي يطابق مع قائمة المجالات المحددة.

بالنسبة إلى IIS 7.5+ مع وحدة URL Rewite 2.0 مثبتة، يرجى الاطلاع هذا حتى الإجابة

إليك حلا ل Java Web App، بناء على إجابة من yesthatguy.

أنا أستخدم جيرسي راحة 1.x

قم بتكوين Web.xml ليكون على دراية بقية جيرسي والجزر

 <!-- Jersey REST config -->
  <servlet>    
    <servlet-name>JAX-RS Servlet</servlet-name>
    <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
    <init-param> 
        <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
        <param-value>true</param-value>
    </init-param>
    <init-param>
      <param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
      <param-value>com.your.package.CORSResponseFilter</param-value>
    </init-param>   
    <init-param>
        <param-name>com.sun.jersey.config.property.packages</param-name>
        <param-value>com.your.package</param-value>
    </init-param>        
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>JAX-RS Servlet</servlet-name>
    <url-pattern>/ws/*</url-pattern>
  </servlet-mapping>

إليك رمز CorsResponseFilter

import com.sun.jersey.spi.container.ContainerRequest;
import com.sun.jersey.spi.container.ContainerResponse;
import com.sun.jersey.spi.container.ContainerResponseFilter;


public class CORSResponseFilter implements ContainerResponseFilter{

@Override
public ContainerResponse filter(ContainerRequest request,
        ContainerResponse response) {

    String[] allowDomain = {"http://localhost:9000","https://my.domain.example"};
    Set<String> allowedOrigins = new HashSet<String>(Arrays.asList (allowDomain));                  

    String originHeader = request.getHeaderValue("Origin");

    if(allowedOrigins.contains(originHeader)) {
        response.getHttpHeaders().add("Access-Control-Allow-Origin", originHeader);

        response.getHttpHeaders().add("Access-Control-Allow-Headers",
                "origin, content-type, accept, authorization");
        response.getHttpHeaders().add("Access-Control-Allow-Credentials", "true");
        response.getHttpHeaders().add("Access-Control-Allow-Methods",
                "GET, POST, PUT, DELETE, OPTIONS, HEAD");
    }

    return response;
}

}

كما ذكر أعلاه، Access-Control-Allow-Origin يجب أن تكون فريدة من نوعها و Vary يجب تعيين ل Origin إذا كنت وراء CDN (شبكة تسليم المحتوى).

جزء ذي الصلة من تكوين Nginx الخاص بي:

if ($http_origin ~* (https?://.*\.mydomain.example(:[0-9]+)?)) {
  set $cors "true";
}
if ($cors = "true") {
  add_header 'Access-Control-Allow-Origin' "$http_origin";
  add_header 'X-Frame-Options' "ALLOW FROM $http_origin";
  add_header 'Access-Control-Allow-Credentials' 'true';
  add_header 'Vary' 'Origin';
}

ربما أنا مخطئ، ولكن بقدر ما أستطيع أن أرى Access-Control-Allow-Origin لديه "origin-list" كمعلمة.

بواسطة تعريف أ origin-list يكون:

origin            = "origin" ":" 1*WSP [ "null" / origin-list ]
origin-list       = serialized-origin *( 1*WSP serialized-origin )
serialized-origin = scheme "://" host [ ":" port ]
                  ; <scheme>, <host>, <port> productions from RFC3986

ومن هذا، أجادل أصول مختلفة ويجب أن تكون الفضاء مفصولة.

كافحت لتعيين هذا الأمر للحصول على مجال تشغيل HTTPS، لذلك احسب أنني سأشارك الحل. لقد استخدمت التوجيه التالي في بلدي httpd.conf. ملف:

    <FilesMatch "\.(ttf|otf|eot|woff)$">
            SetEnvIf Origin "^http(s)?://(.+\.)?example\.com$" AccessControlAllowOrigin=$0
            Header set Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
    </FilesMatch>

يتغيرون example.com إلى اسم المجال الخاص بك. أضف هذا في الداخل <VirtualHost x.x.x.x:xx> في الخاص بك httpd.conf. ملف. لاحظ أنه إذا كان لديك VirtualHost لديه لاحقة ميناء (على سبيل المثال :80) ثم لن ينطبق هذا التوجيه على HTTPS، لذلك سوف تحتاج إلى الذهاب أيضا / ETC / Apache2 / المواقع المتاحة / الافتراضي SSL وإضافة نفس التوجيه في هذا الملف، داخل <VirtualHost _default_:443> الجزء.

بمجرد تحديث ملفات التكوين، ستحتاج إلى تشغيل الأوامر التالية في المحطة:

a2enmod headers
sudo service apache2 reload

إذا كنت تواجه مشكلة في الخطوط، فاستخدم:

<FilesMatch "\.(ttf|ttc|otf|eot|woff)$">
    <IfModule mod_headers>
        Header set Access-Control-Allow-Origin "*"
    </IfModule>
</FilesMatch>

للحصول على تطبيقات ExpressJs التي يمكنك استخدامها:

app.use((req, res, next) => {
    const corsWhitelist = [
        'https://domain1.example',
        'https://domain2.example',
        'https://domain3.example'
    ];
    if (corsWhitelist.indexOf(req.headers.origin) !== -1) {
        res.header('Access-Control-Allow-Origin', req.headers.origin);
        res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
    }

    next();
});

لا يتم استخدام http_origin من قبل جميع المتصفحات. كم هو آمن http_origin؟ بالنسبة لي يتعلق الأمر فارغا في FF.
لدي المواقع التي تسمح بالوصول إلى موقعي إرسال معرف موقع، ثم تحقق من DB الخاص بي للسجل مع هذا المعرف والحصول على قيمة العمود Site_url (www.yoursite.com).

header('Access-Control-Allow-Origin: http://'.$row['SITE_URL']);

حتى إذا تم إرسال معرف موقع صالح، يجب أن يكون الطلب من المجال المدرج في DB المرتبط بهذا الموقع.

إليك خيار موسع لأباتشي يتضمن بعض تعريفات الخطوط الأخيرة والمخطط لها:

<FilesMatch "\.(ttf|otf|eot|woff|woff2|sfnt|svg)$">
    <IfModule mod_headers.c>
        SetEnvIf Origin "^http(s)?://(.+\.)?(domainname1|domainname2|domainname3)\.(?:com|net|org)$" AccessControlAllowOrigin=$0$1$2
        Header add Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
        Header set Access-Control-Allow-Credentials true
    </IfModule>
</FilesMatch>

وجواب آخر آخر في Django. للحصول على عرض واحد، اسمح ل Cors من مجالات متعددة، إليك الرمز الخاص بي:

def my_view(request):
    if 'HTTP_ORIGIN' in request.META.keys() and request.META['HTTP_ORIGIN'] in ['http://allowed-unsecure-domain.com', 'https://allowed-secure-domain.com', ...]:
        response = my_view_response() # Create your desired response data: JsonResponse, HttpResponse...
        # Then add CORS headers for access from delivery
        response["Access-Control-Allow-Origin"] = request.META['HTTP_ORIGIN']
        response["Access-Control-Allow-Methods"] = "GET" # "GET, POST, PUT, DELETE, OPTIONS, HEAD"
        response["Access-Control-Max-Age"] = "1000"  
        response["Access-Control-Allow-Headers"] = "*"  
        return response

بالنسبة إلى نسخ / لصق سهل إلى حد ما لتطبيقات .NET، كتبت هذا لتمكين Cors من داخل ملف Global.asax. يتبع هذا الرمز النصيحة الواردة في الإجابة التي تم قبولها حاليا، مما يعكس مهما تم تقديم ظهره في الطلب في الاستجابة. هذا يحقق بفعالية "*" دون استخدامه. السبب في ذلك هو أنه يتيح ميزات مزايا أخرى متعددة، بما في ذلك القدرة على إرسال AJAX XMLHTTPRECEST مع سمة "Weatcredentials" تعيين "صحيح".

void Application_BeginRequest(object sender, EventArgs e)
{
    if (Request.HttpMethod == "OPTIONS")
    {
        Response.AddHeader("Access-Control-Allow-Methods", "GET, POST");
        Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
        Response.AddHeader("Access-Control-Max-Age", "1728000");
        Response.End();
    }
    else
    {
        Response.AddHeader("Access-Control-Allow-Credentials", "true");

        if (Request.Headers["Origin"] != null)
            Response.AddHeader("Access-Control-Allow-Origin" , Request.Headers["Origin"]);
        else
            Response.AddHeader("Access-Control-Allow-Origin" , "*");
    }
}

لتسهيل الوصول إلى مجال متعددة لخدمة ASMX، قمت بإنشاء هذه الوظيفة في ملف Global.asax:

protected void Application_BeginRequest(object sender, EventArgs e)
{
    string CORSServices = "/account.asmx|/account2.asmx";
    if (CORSServices.IndexOf(HttpContext.Current.Request.Url.AbsolutePath) > -1)
    {
        string allowedDomains = "http://xxx.yyy.example|http://aaa.bbb.example";

        if(allowedDomains.IndexOf(HttpContext.Current.Request.Headers["Origin"]) > -1)
            HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", HttpContext.Current.Request.Headers["Origin"]);

        if(HttpContext.Current.Request.HttpMethod == "OPTIONS")
            HttpContext.Current.Response.End();
    }
}

هذا يسمح ل cors التعامل مع OPTIONS الفعل أيضا.

مثال رمز PHP لمطابقة المجال الفرعي.

if( preg_match("/http:\/\/(.*?)\.yourdomain.example/", $_SERVER['HTTP_ORIGIN'], $matches )) {
        $theMatch = $matches[0];
        header('Access-Control-Allow-Origin: ' . $theMatch);
}

نهج أكثر مرونة هو استخدام تعبيرات Apache 2.4. يمكنك مطابقات ضد المجالات والمسارات ومتغير كل طلب آخر. على الرغم من الاستجابة * للجميع، فإن المقاعدين الوحيدين الذين يتلقون هذا الاستجابة هم تلك التي تلبي المتطلبات على أي حال.

<IfModule mod_headers.c>
    <If "%{HTTP:Host} =~ /\\bcdndomain\\.example$/i && %{HTTP:Origin} =~ /\\bmaindomain\\.example$/i">
        Header set Access-Control-Allow-Origin "*"
    </If>
</IfModule>

إجابة دعم Google تقديم الإعلانات على SSL و ال القواعد في RFC نفسها يبدو أن الإشارة إلى أنه يمكنك مسح المساحة عناوين URL. غير متأكد من مدى دعم جيد هذا في متصفحات مختلفة.

إذا جربت الكثير من أمثلة التعليمات البرمجية مثلي لجعلها تعمل باستخدام Cors، فإن الأمر يستحق الإشارة إلى أنه يجب عليك مسح ذاكرة التخزين المؤقت الخاصة بك أولا في محاولة إذا كان يعمل بالفعل، مشكلات مشابهة مثل الصور القديمة، حتى لو كانت تم حذفها على الخادم (لأنه لا يزال محفظا في ذاكرة التخزين المؤقت الخاصة بك).

علي سبيل المثال CTRL + SHIFT + DEL في Google Chrome لحذف ذاكرة التخزين المؤقت الخاصة بك.

ساعدني هذا في استخدام هذا الرمز بعد محاولة الكثير من النقي .htaccess يبدو الحلول وهذا العمل الوحيد (على الأقل بالنسبة لي):

    Header add Access-Control-Allow-Origin "http://google.com"
    Header add Access-Control-Allow-Headers "authorization, origin, user-token, x-requested-with, content-type"
    Header add Access-Control-Allow-Methods "PUT, GET, POST, DELETE, OPTIONS"

    <FilesMatch "\.(ttf|otf|eot|woff)$">
        <IfModule mod_headers.c>
            SetEnvIf Origin "http(s)?://(www\.)?(google.com|staging.google.com|development.google.com|otherdomain.com|dev02.otherdomain.net)$" AccessControlAllowOrigin=$0
            Header add Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
        </IfModule>
    </FilesMatch>

لاحظ أيضا أنه ينتشر على نطاق واسع أن العديد من الحلول تقول أن لديك لكتابة Header set ... و لكنها Header add .... وبعد آمل أن يساعد هذا شخص ما له نفس المشكلات لبعض ساعات مثلي الآن.

فيما يلي الإجابة محددة ل C #، ولكن يجب أن ينطبق هذا المفهوم على جميع المنصات المختلفة.

للسماح بطلبات الصليب الأصلية من API ويب، تحتاج إلى السماح بطلبات الخيار لتطبيقك وإضاف أدناه التوضيحية على مستوى وحدة التحكم.

enablezors (Urlstring، رأس، الطريقة)] الآن يمكن تمرير الأصول فقط كسلسلة. لذلك إذا كنت ترغب في اجتياز أكثر من عنوان URL في الطلب تمريره كقيمة مفصلة بفاصلة.

Urlstring = "HTTPS: //a.hello.comhtttps: //b.hello.com"

يمكن تحديد أصل واحد فقط لرأس اتصال التحكم في الوصول. ولكن يمكنك ضبط الأصل في ردك وفقا للطلب. أيضا لا تنسى تعيين رأس تختلف. في PHP أود أن أقوم بما يلي:

    /**
     * Enable CORS for the passed origins.
     * Adds the Access-Control-Allow-Origin header to the response with the origin that matched the one in the request.
     * @param array $origins
     * @return string|null returns the matched origin or null
     */
    function allowOrigins($origins)
    {
        $val = $_SERVER['HTTP_ORIGIN'] ?? null;
        if (in_array($val, $origins, true)) {
            header('Access-Control-Allow-Origin: '.$val);
            header('Vary: Origin');

            return $val;
        }

        return null;
    }

  if (allowOrigins(['http://localhost', 'https://localhost'])) {
      echo your response here, e.g. token
  }

يمكننا أيضا تعيين هذا في ملف Global.asax لتطبيق ASP.NET.

protected void Application_BeginRequest(object sender, EventArgs e)
    {

    // enable CORS
    HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "https://www.youtube.com");

    }

يبدو أن الإجابة هي استخدام الرأس أكثر من مرة. وهذا هو، بدلا من الإرسال

Access-Control-Allow-Origin: http://domain1.example, http://domain2.example, http://domain3.example

إرسال

Access-Control-Allow-Origin: http://domain1.example
Access-Control-Allow-Origin: http://domain2.example
Access-Control-Allow-Origin: http://domain3.example

على Apache، يمكنك القيام بذلك في httpd.conf <VirtualHost> القسم أو .htaccess ملف باستخدام mod_headers وهذا بناء الجملة:

Header add Access-Control-Allow-Origin "http://domain1.example"
Header add Access-Control-Allow-Origin "http://domain2.example"
Header add Access-Control-Allow-Origin "http://domain3.example"

الحيلة هي استخدام add بدلا من append كما الحجة الأولى.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top