javascript - لا يمكن لـ XMLHttpRequest تحميل رأس XXX "الوصول إلى التحكم-السماح-الأصل"




node.js cors (4)

ليرة تركية، والدكتور. حول سياسة الأصل نفسه

لدي عملية Grunt التي تبدأ مثيل خادم Express.js. كان هذا جيدًا تمامًا حتى الآن عندما بدأت في تقديم صفحة فارغة مع ظهور التالي في سجل الأخطاء في وحدة تحكم المطور في Chrome (الإصدار الأحدث):

يتعذر على XMLHttpRequest تحميل https://www.example.com/ لا يوجد رأس "Access-Control-Allow-Origin" موجود على المورد المطلوب. الأصل ' http: // localhost: 4300 ' غير مسموح بالوصول إليه.

ما الذي يمنعني من الوصول إلى الصفحة؟


حول سياسة الأصل نفسه

هذه هي نفس السياسة الأصلية . إنها ميزة أمان تنفذها المتصفحات.

توضح حالتك الخاصة كيفية تنفيذها لـ XMLHttpRequest (وستحصل على نتائج مماثلة إذا كنت تريد استخدام الجلب) ، ولكنها تنطبق أيضًا على أشياء أخرى (مثل الصور التي تم تحميلها على <canvas> أو المستندات التي تم تحميلها في <iframe> ) ، فقط مع تطبيقات مختلفة قليلا.

(من الغريب ، أنه ينطبق أيضًا على خطوط CSS ، ولكن هذا بسبب أن المسابك التي تم العثور عليها أصرت على إدارة الحقوق الرقمية وليس على مشكلات الأمان التي تغطيها عادة سياسة المنشأ الأصلية).

يمكن إظهار السيناريو القياسي الذي يوضح الحاجة إلى SOP بثلاثة أحرف :

  • أليس شخص لديه متصفح ويب
  • يقوم Bob بإدارة موقع ويب ( https://www.[website].com/ في مثالك)
  • تدير Mallory موقع ويب ( http://localhost:4300 في http://localhost:4300 )

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

تزور Alice موقع Mallory الذي يحتوي على بعض جافا سكريبت والذي يتسبب في قيام متصفح Alice بتقديم طلب HTTP إلى موقع Bob على الويب (من عنوان IP الخاص بها مع ملفات تعريف الارتباط ، وما إلى ذلك). قد يكون هذا بسيطًا مثل استخدام XMLHttpRequest وقراءة responseText .

تمنع سياسة "نفس الأصل" في المتصفح JavaScript من قراءة البيانات التي يتم إرجاعها بواسطة موقع Bob (لا يريد Bob and Alice الوصول إلى Mallory). (لاحظ أنه يمكنك ، على سبيل المثال ، عرض صورة باستخدام عنصر <img> عبر الأصول لأن محتوى الصورة لا يتعرض لجافا سكريبت (أو Mallory) ... إلا إذا رميت قماشًا في المزيج وفي هذه الحالة ستقوم بإنشاء خطأ انتهاك نفس الأصل).

لماذا تنطبق نفس السياسة الأصلية عندما لا تظن أن عليها ذلك

بالنسبة لأي عنوان URL معين ، من الممكن ألا تكون SOP ضرورية. اثنين من السيناريوهات الشائعة حيث هذه هي الحالة:

  • أليس وبوب ومالي هما نفس الشخص.
  • يوفر بوب معلومات عامة تمامًا

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

لماذا تنطبق نفس السياسة الأصلية على جافا سكريبت في صفحة ويب فقط

تم تثبيت ملحقات المستعرض ، علامة تبويب الشبكة في أدوات مطور المستعرض وتطبيقاته مثل Postman. إنهم لا يقومون بتمرير البيانات من موقع ويب واحد إلى JavaScript التي تنتمي إلى موقع ويب مختلف لمجرد قيامك بزيارة موقع الويب المختلف هذا . عادة ما يستغرق تثبيت البرنامج اختيارًا أكثر وعياً.

لا يوجد طرف ثالث (Mallory) يعتبر مخاطرة.

لماذا يمكنك عرض البيانات في الصفحة دون قراءتها باستخدام JS

هناك عدد من الحالات التي يمكن أن يؤدي فيها موقع Mallory إلى إحضار المستعرض لجلب البيانات من جهة خارجية وعرضها (على سبيل المثال عن طريق إضافة عنصر <img> لعرض صورة). لا يمكن لجافا سكريبت Mallory قراءة البيانات الموجودة في هذا المورد ، مع ذلك ، يمكن لمتصفح Alice وخادم Bob فقط القيام بذلك ، لذلك لا يزال الوضع آمنًا.

CORS

يعد Access-Control-Allow-Origin المشار إليه في رسالة الخطأ جزءًا من معيار CORS الذي يسمح لـ Bob بمنح إذن صريح لموقع Mallory للوصول إلى البيانات عبر متصفح Alice.

سيتضمن التنفيذ الأساسي ما يلي:

Access-Control-Allow-Origin: *

... للسماح لأي موقع بقراءة البيانات.

Access-Control-Allow-Origin: http://example.com/

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

تعتمد تفاصيل كيفية تعيين رأس الاستجابة على خادم HTTP الخاص بـ Bob و / أو لغة البرمجة من جانب الخادم. هناك مجموعة من الأدلة لمختلف التكوينات الشائعة التي قد تساعد.

ملحوظة: بعض الطلبات معقدة وترسل طلبًا preflight المبدئية يطلب من الخادم أن يرد عليه قبل أن يرسل المتصفح GET / POST / PUT / مهما كان طلب JS الذي يريده. غالبًا ما تتعطل تطبيقات CORS التي تضيف فقط Access-Control-Allow-Origin لعناوين URL محددة.

من الواضح أن منح الإذن عبر CORS أمر لن يفعله بوب إلا إذا:

  • البيانات لم تكن خاصة أو
  • وكان مالوري موثوق

إذا كنت أيضًا Bob في هذا السيناريو ، فستتوقف تفاصيل كيفية إضافة رؤوس أذونات CORS على مزيج من اختيارك لبرنامج خادم HTTP واللغة التي تستخدمها للبرمجة من جانب الخادم (إن وجدت).

لا تستطيع مالوري إضافة هذا العنوان لأنها يجب أن تحصل على إذن من موقع بوب وسيكون من السخف (إلى حد جعل SOP عديمة الفائدة) لها أن تكون قادرة على منح نفسها إذن.

رسائل الخطأ التي تشير إلى "الاستجابة للتجربة المبدئية"

بعض طلبات الأصل المتقاطع preflight .

يحدث هذا عندما تحاول (متحدثًا تقريبًا) تقديم طلب عبر الأصل:

  • يتضمن بيانات الاعتماد مثل ملفات تعريف الارتباط
  • لا يمكن إنشاء نموذج HTML عادي (على سبيل المثال ، يحتوي على رؤوس مخصصة أو نوع محتوى لا يمكنك استخدامه في صيغة النموذج).

إذا كنت تقوم بعمل صحيح يحتاج إلى اختبار مبدئي

في هذه الحالات ، يظل باقي هذه الإجابة ساريًا ولكن عليك أيضًا التأكد من أن الخادم يمكنه الاستماع إلى طلب الاختبار المبدئي (والذي سيكون OPTIONS (وليس GET أو POST أو أي شيء كنت تحاول إرساله) والرد عليه باستخدام رأس Access-Control-Allow-Origin الصحيح ولكن أيضًا Access-Control-Allow-Methods و Access-Control-Allow-Headers للسماح بطرق أو رؤوس HTTP المحددة.

إذا كنت تؤدي الاختبار المبدئي عن طريق الخطأ

أحيانًا يرتكب الأشخاص أخطاء عند محاولة إنشاء طلبات Ajax ، وفي بعض الأحيان تؤدي هذه الحاجة إلى الاختبار المبدئي. إذا كانت واجهة برمجة التطبيقات (API) مصممة للسماح لطلبات الأصل المتقاطع ، ولكنها لا تتطلب أي شيء قد يحتاج إلى اختبار مبدئي ، فإن ذلك قد يؤدي إلى انقطاع الوصول.

تتضمن الأخطاء الشائعة التي تؤدي إلى هذا:

  • محاولة وضع Access-Control-Allow-Origin وغيرها من رؤوس استجابة CORS على الطلب. لا ينتمي هؤلاء إلى الطلب ، ولا يفعلون أي شيء مفيد (ما سيكون نقطة نظام الأذونات حيث يمكنك منح إذن لك؟) ، ويجب أن تظهر فقط في الاستجابة.
  • محاولة وضع رأس Content-Type: application/json header على طلب GET ليس له نص طلب لوصف محتوى (عادةً عندما يخلط المؤلف بين Content-Type و Accept ).

في أي من هاتين الحالتين ، غالبًا ما تكون إزالة رأس الطلب الإضافي كافية لتجنب الحاجة إلى الاختبار المبدئي (مما سيؤدي إلى حل المشكلة عند الاتصال بواجهات برمجة التطبيقات (APIs) التي تدعم الطلبات البسيطة ولكن ليس الطلبات المبدئية).

ردود مبهمة

في بعض الأحيان تحتاج إلى تقديم طلب HTTP ، لكنك لا تحتاج إلى قراءة الرد. على سبيل المثال إذا كنت تنشر رسالة سجل إلى الخادم للتسجيل.

إذا كنت تستخدم fetch API (بدلاً من XMLHttpRequest ) ، فيمكنك تكوينه لعدم محاولة استخدام CORS.

لاحظ أن هذا لن يسمح لك بالقيام بأي شيء تحتاج إلى القيام به CORS. لن تكون قادرًا على قراءة الرد. لن تتمكن من تقديم طلب يتطلب الاختبار المبدئي.

سيتيح لك تقديم طلب بسيط ، وعدم رؤية الاستجابة ، وعدم ملء وحدة تحكم Developer برسائل الخطأ.

يتم توضيح كيفية القيام بذلك من خلال رسالة خطأ Chrome التي تم تقديمها عند تقديم طلب باستخدام fetch ولا تحصل على إذن لعرض الاستجابة مع CORS:

تم حظر الوصول إلى جلب " https://example.com/ " من الأصل " https://example.net " بواسطة سياسة CORS: لا يوجد رأس " Access-Control-Allow-Origin " موجود على المورد المطلوب. إذا كانت الاستجابة غير الشفافة تفي باحتياجاتك ، فاضبط وضع الطلب على "عدم استخدام" لجلب المورد مع تعطيل CORS.

على النحو التالي:

fetch("http://example.com", { mode: "no-cors" });

بدائل كورس

JSONP

يمكن أن يوفر بوب البيانات أيضًا باستخدام أداة اختراق مثل JSONP وهي الطريقة التي فعل بها الأشخاص عبر Ajax قبل ظهور CORS.

وهو يعمل عن طريق تقديم البيانات في شكل برنامج جافا سكريبت الذي يحقن البيانات في صفحة مالوري.

يتطلب أن يثق مالوري بوب في عدم تقديم كود ضار.

لاحظ السمة العامة: يجب على الموقع الذي يوفر البيانات أن يخبر المستعرض أنه لا يمكن لموقع طرف ثالث الوصول إلى البيانات التي يرسلها إلى المستعرض.

نظرًا لأن JSONP يعمل عن طريق إلحاق عنصر <script> لتحميل البيانات في شكل برنامج JavaScript الذي يستدعي وظيفة موجودة بالفعل في الصفحة ، فإن محاولة استخدام تقنية JSONP على عنوان URL الذي يعرض JSON سوف تفشل - عادةً مع وجود خطأ في CORB - لأن JSON ليس JavaScript.

نقل الموارد اثنين إلى أصل واحد

إذا كان مستند HTML الذي يتم تشغيل JS فيه وكان عنوان URL المطلوب متماثلًا في نفس الأصل (مشاركة في نفس المخطط واسم المضيف والمنفذ) ، فستمنح "نفس أصل السياسة" إذنًا افتراضيًا. ليست هناك حاجة كورس.

وكيل

يمكن أن تستخدم Mallory الكود من جانب الخادم لجلب البيانات (والتي يمكن أن تنتقل من خادمها إلى متصفح Alice عبر HTTP كالمعتاد).

سوف إما:

  • إضافة رؤوس كورس
  • تحويل الاستجابة إلى JSONP
  • موجودة على نفس أصل مستند HTML

يمكن كتابة هذا الرمز من جانب الخادم واستضافته بواسطة جهة خارجية (مثل CORS Anywhere). لاحظ تداعيات الخصوصية المترتبة على هذا: يمكن للجهة الخارجية مراقبة من يقوم بالوكلاء على ما عبر خوادمهم.

لن يحتاج بوب إلى منح أي أذونات لذلك.

هذا سيكون على ما يرام لأن هذا هو فقط بين مالوري وبوب. لا توجد طريقة لكي يعتقد بوب أن Mallory هو Alice وأن يزود Mallory بالبيانات التي يجب أن تبقى سرية بين Alice و Bob.

وبالتالي ، يمكن أن يستخدم Mallory هذه التقنية فقط لقراءة البيانات العامة .

كتابة شيء آخر غير تطبيق الويب

كما هو موضح في القسم "لماذا تنطبق نفس السياسة الأصلية فقط على JavaScript في صفحة ويب" ، يمكنك تجنب إجراء SOP بعدم كتابة JavaScript في صفحة ويب.

هذا لا يعني أنه لا يمكنك متابعة استخدام JavaScript و HTML ، ولكن يمكنك توزيعه باستخدام آلية أخرى ، مثل Node-WebKit أو PhoneGap.

ملحقات المتصفح

من الممكن أن يقوم امتداد المتصفح بضخ رؤوس CORS في الاستجابة قبل تطبيق سياسة المنشأ الأصلية.

يمكن أن تكون هذه مفيدة للتطوير ، ولكنها ليست عملية لموقع الإنتاج (مطالبة كل مستخدم في موقعك بتثبيت ملحق مستعرض يعطل ميزة أمان لمتصفحه أمر غير معقول).

كما أنها تميل إلى العمل فقط مع الطلبات البسيطة (الفشل عند معالجة طلبات OPTIONS المبدئية).

عادةً ما يكون وجود بيئة تطوير مناسبة مع خادم تطوير محلي طريقة أفضل.

مخاطر أمنية أخرى

لاحظ أن SOP / CORS لا تخفف من هجمات XSS أو CSRF أو SQL Injection التي يجب معالجتها بشكل مستقل.

ملخص

  • لا يوجد شيء يمكنك القيام به في التعليمات البرمجية من جانب العميل الخاص بك والذي سيمكّن CORS من الوصول إلى خادم شخص آخر .
  • إذا كنت تتحكم في الخادم ، فسيتم تقديم الطلب إلى: إضافة أذونات CORS إليه.
  • إذا كنت صديقًا مع الشخص الذي يتحكم فيه: اجعله يضيف أذونات CORS إليه.
  • إذا كانت خدمة عامة: فاقرأ وثائق واجهة برمجة التطبيقات لمعرفة ما يقولونه حول الوصول إليه باستخدام جافا سكريبت من جانب العميل. قد يطالبونك باستخدام عناوين URL محددة أو استخدام JSONP (أو قد لا يدعمونها على الإطلاق).
  • في حالة عدم تطبيق أي مما ذكر أعلاه: اجعل المتصفح يتحدث إلى الخادم الخاص بك بدلاً من ذلك ، ثم اطلب من الخادم الخاص بك إحضار البيانات من الخادم الآخر ونقلها. (هناك أيضًا خدمات مستضافة تابعة لجهات خارجية تربط رؤوس CORS بالموارد المتاحة للجمهور والتي يمكنك استخدامها).

لأن هذا لم يرد ذكره في الإجابة المقبولة.

  • ليس هذا هو الحال بالنسبة لهذا السؤال بالضبط ، ولكن قد يساعد الآخرين الذين يبحثون عن هذه المشكلة
  • هذا شيء يمكنك القيام به في رمز العميل الخاص بك لمنع أخطاء CORS في بعض الحالات .

يمكنك الاستفادة من الطلبات البسيطة .
من أجل تنفيذ "الطلبات البسيطة" ، يجب أن يفي الطلب بعدة شروط. على سبيل المثال ، لا تسمح إلا بأسلوب POST و GET و HEAD ، بالإضافة إلى السماح فقط برؤوس معينة (يمكنك العثور على جميع الشروط هنا ).

إذا لم يوضح رمز العميل الخاص بك الرؤوس المتأثرة (مثل "قبول") بقيمة إصلاح في الطلب ، فقد يحدث أن يقوم بعض العملاء بتعيين هذه الرؤوس تلقائيًا مع بعض القيم "غير القياسية" مما يؤدي إلى عدم قبول الخادم لها على أنها طلب بسيط - والتي سوف تعطيك خطأ كورس.


يجب أن يسمح الخادم الهدف بطلب الأصل المشترك. للسماح لها بالعبور عبر Express ، ما عليك سوى التعامل مع طلب خيارات http:

app.options('/url...', function(req, res, next){
   res.header('Access-Control-Allow-Origin', "*");
   res.header('Access-Control-Allow-Methods', 'POST');
   res.header("Access-Control-Allow-Headers", "accept, content-type");
   res.header("Access-Control-Max-Age", "1728000");
   return res.sendStatus(200);
});

يجب عليك تمكين CORS لجعلها تعمل.






server