إمكانية التحكم-السماح بالسماح المجالات الأصلية الأصلية؟
-
11-09-2019 - |
سؤال
هل هناك طريقة للسماح للمجالات عبر متعددة باستخدام 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
كما الحجة الأولى.