كيف يمكن تمكين CORS باستخدام ملف تعريف الارتباط HTTPOnly لتأمين الرمز المميز؟

نشرت: 2021-12-29

في هذه المقالة ، نرى كيفية تمكين CORS (مشاركة الموارد عبر الأصل) باستخدام ملف تعريف ارتباط HTTPOnly لتأمين رموز الوصول الخاصة بنا.

في الوقت الحاضر ، يتم نشر خوادم الواجهة الخلفية وعملاء الواجهة الأمامية في مجالات مختلفة. لذلك يجب على الخادم تمكين CORS للسماح للعملاء بالاتصال بالخادم على المتصفحات.

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

لماذا يتم حظر طلبات Cross-Origin؟

لنفترض أن تطبيق الواجهة الأمامية الخاص بنا تم نشره على https://app.geekflare.com . يمكن للبرنامج النصي الذي تم تحميله في https://app.geekflare.com طلب موارد من نفس الأصل فقط.

عندما نحاول إرسال طلب عبر الأصل إلى مجال آخر https://api.geekflare.com أو منفذ آخر https://app.geekflare.com:3000 أو مخطط آخر http://app.geekflare.com ، سيتم حظر طلب عبر الأصل بواسطة المتصفح.

ولكن لماذا يتم إرسال نفس الطلب الذي تم حظره بواسطة المتصفح من أي خادم خلفي باستخدام طلب curl أو إرساله باستخدام أدوات مثل ساعي البريد دون أي مشكلة في CORS. إنه في الواقع للأمان حماية المستخدمين من هجمات مثل CSRF (تزوير طلب عبر الموقع).

لنأخذ مثالاً ، لنفترض إذا قام أي مستخدم بتسجيل الدخول إلى حساب PayPal الخاص به في متصفحه. إذا كان بإمكاننا إرسال طلب عبر الأصل إلى paypal.com من نص برمجي تم تحميله على مجال آخر malicious.com دون أي خطأ / حظر CORS مثل إرسال طلب من نفس الأصل.

يمكن للمهاجمين بسهولة إرسال صفحتهم الضارة https://malicious.com/transfer-money-to-attacker-account-from-user-paypal-account عن طريق تحويلها إلى عنوان URL قصير لإخفاء عنوان URL الفعلي. عندما ينقر المستخدم فوق ارتباط ضار ، سيرسل البرنامج النصي الذي تم تحميله في المجال malicious.com طلبًا عبر الأصل إلى PayPal لتحويل مبلغ المستخدم إلى حساب PayPal المهاجم الذي سيتم تنفيذه. سيخسر جميع المستخدمين الذين قاموا بتسجيل الدخول إلى حساب PayPal الخاص بهم ونقروا على هذا الرابط الضار أموالهم. يمكن لأي شخص سرقة الأموال بسهولة دون معرفة مستخدم حساب PayPal.

للسبب أعلاه ، تمنع المتصفحات جميع طلبات المصدر المشترك.

ما هو CORS (تبادل الموارد عبر المنشأ)؟

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

كيف يعمل CORS؟

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

يوجد نوعان من طلبات CORS:

  • طلب بسيط
  • طلب الاختبار المبدئي

طلب بسيط:

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

  • يرسل المستعرض الطلب إلى مجال متعدد المنشأ مع الأصل (https://app.geekflare.com).
  • يرسل الخادم الاستجابة المقابلة بالطرق المسموح بها والأصل المسموح به.
  • بعد تلقي الطلب ، سيتحقق المستعرض من قيمة رأس الأصل المرسل ( https://app.geekflare.com ) وقيمة الوصول إلى التحكم في السماح الأصلية ( https://app.geekflare.com ) هي نفسها أو بدل (*). وإلا ، فسيؤدي ذلك إلى ظهور خطأ CORS.

طلب الرحلة التمهيدية:

CORS-Preflight Request Image which show the flow of cross-origin request with OPTIONS preflight request before sending actual request for verifying headers.

  • اعتمادًا على معلمة الطلب المخصص من الطلب عبر الأصل مثل الطرق (PUT ، DELETE) أو رؤوس مخصصة أو نوع محتوى مختلف ، إلخ. سيقرر المستعرض إرسال طلب OPTIONS للاختبار المبدئي للتحقق مما إذا كان الطلب الفعلي آمنًا للإرسال أم لا.
  • بعد تلقي الاستجابة (رمز الحالة: 204 ، مما يعني عدم وجود محتوى) ، سيتحقق المتصفح من معلمات التحكم في الوصول للطلب الفعلي. إذا سمح الخادم بمعلمات الطلب. تم إرسال الطلب عبر الأصل الفعلي واستلامه

إذا كان access-control-allow-origin: * ، فحينئذٍ يُسمح بالاستجابة لجميع الأصول. لكنها ليست آمنة إلا إذا كنت في حاجة إليها.

كيف يتم تمكين CORS؟

لتمكين CORS لأي مجال ، قم بتمكين رؤوس CORS للسماح بالأصل والأساليب والعناوين المخصصة وبيانات الاعتماد ، إلخ.

يقرأ المتصفح رأس CORS من الخادم ويسمح بالطلبات الفعلية من العميل فقط بعد التحقق من معلمات الطلب.

  • Access-Control-Allow-Origin: لتحديد المجالات الدقيقة (https://app.geekflate.com ، https://lab.geekflare.com) أو wildcard (*)
  • طرق التحكم في الوصول والسماح بالوصول : للسماح بطرق HTTP (GET ، POST ، PUT ، DELETE ، PATCH ، HEAD ، OPTIONS) التي نحتاجها فقط.
  • Access-Control-Allow-Headers: للسماح برؤوس محددة فقط (التفويض ، csrf-token)
  • Access-Control-Allow-Credentials: قيمة منطقية تُستخدم للسماح ببيانات الاعتماد عبر الأصل (ملفات تعريف الارتباط ، رأس التفويض).
  • Access-Control-Max-Age: يخبر المتصفح بتخزين استجابة الاختبار المبدئي لبعض الوقت.
  • Access-Control-Expose-Headers: حدد الرؤوس التي يمكن الوصول إليها بواسطة البرنامج النصي من جانب العميل.

لتمكين CORS في خادم الويب apache و Nginx ، اتبع هذا البرنامج التعليمي.

تمكين CORS في ExpressJS

لنأخذ مثالاً لتطبيق ExpressJS بدون CORS:

 const express = require('express'); const app = express() app.get('/users', function (req, res, next) { res.json({msg: 'user get'}) }); app.post('/users', function (req, res, next) { res.json({msg: 'user create'}) }); app.put('/users', function (req, res, next) { res.json({msg: 'User update'}) }); app.listen(80, function () { console.log('CORS-enabled web server listening on port 80') })

في المثال أعلاه ، قمنا بتمكين نقطة نهاية واجهة برمجة التطبيقات للمستخدمين لطرق POST و PUT و GET ولكن ليس طريقة الحذف.

لتسهيل تمكين CORS في تطبيق ExpressJS ، يمكنك تثبيت الكور

 npm install cors

التحكم في الوصول والسماح بالأصل

تمكين CORS لجميع المجالات

 app.use(cors({ origin: '*' }));

تمكين CORS لمجال واحد

 app.use(cors({ origin: 'https://app.geekflare.com' }));

إذا كنت تريد السماح لـ CORS بالأصل https://app.geekflare.com و https://lab.geekflare.com

 app.use(cors({ origin: [ 'https://app.geekflare.com', 'https://lab.geekflare.com' ] }));

طرق التحكم في الوصول والسماح

لتمكين CORS لجميع الأساليب ، احذف هذا الخيار في وحدة CORS في ExpressJS. ولكن لتمكين طرق محددة (GET ، POST ، PUT).

 app.use(cors({ origin: [ 'https://app.geekflare.com', 'https://lab.geekflare.com' ], methods: ['GET', 'PUT', 'POST'] }));

الوصول والتحكم والسماح الرؤوس

يُستخدم للسماح للرؤوس بخلاف الإعدادات الافتراضية بالإرسال مع الطلبات الفعلية.

 app.use(cors({ origin: [ 'https://app.geekflare.com', 'https://lab.geekflare.com' ], methods: ['GET', 'PUT', 'POST'], allowedHeaders: ['Content-Type', 'Authorization', 'x-csrf-token'] }));

الوصول والتحكم والسماح أوراق الاعتماد

قم بحذف هذا إذا كنت لا تريد إخبار المتصفح بالسماح ببيانات الاعتماد عند الطلب حتى مع تعيين بيانات الاعتماد على "صحيح" .

 app.use(cors({ origin: [ 'https://app.geekflare.com', 'https://lab.geekflare.com' ], methods: ['GET', 'PUT', 'POST'], allowedHeaders: ['Content-Type', 'Authorization', 'x-csrf-token'], credentials: true }));

التحكم في الوصول ، الحد الأقصى للعمر

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

 app.use(cors({ origin: [ 'https://app.geekflare.com', 'https://lab.geekflare.com' ], methods: ['GET', 'PUT', 'POST'], allowedHeaders: ['Content-Type', 'Authorization', 'x-csrf-token'], credentials: true, maxAge: 600 }));

ستكون استجابة الاختبار المبدئي المخبأة متاحة لمدة 10 دقائق في المتصفح.

الوصول والتحكم في كشف الرؤوس

 app.use(cors({ origin: [ 'https://app.geekflare.com', 'https://lab.geekflare.com' ], methods: ['GET', 'PUT', 'POST'], allowedHeaders: ['Content-Type', 'Authorization', 'x-csrf-token'], credentials: true, maxAge: 600, exposedHeaders: ['Content-Range', 'X-Content-Range'] }));

إذا وضعنا حرف البدل (*) في exposedHeaders ، فلن يعرض عنوان التفويض. لذلك علينا أن نكشف صراحة كما هو موضح أدناه

 app.use(cors({ origin: [ 'https://app.geekflare.com', 'https://lab.geekflare.com' ], methods: ['GET', 'PUT', 'POST'], allowedHeaders: ['Content-Type', 'Authorization', 'x-csrf-token'], credentials: true, maxAge: 600, exposedHeaders: ['*', 'Authorization', ] }));

ما سبق سيعرض جميع الرؤوس ورأس التفويض أيضًا.

ما هو ملف تعريف الارتباط HTTP؟

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

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

  • اسم اسم ملف تعريف الارتباط.
  • القيمة: بيانات ملف تعريف الارتباط المتعلقة باسم ملف تعريف الارتباط
  • المجال: سيتم إرسال ملفات تعريف الارتباط فقط إلى المجال المحدد
  • المسار: يتم إرسال ملفات تعريف الارتباط فقط بعد مسار بادئة عنوان URL المحدد. افترض أننا حددنا مسار ملفات تعريف الارتباط مثل المسار = 'admin /'. لم يتم إرسال ملفات تعريف الارتباط لعنوان URL https://geekflare.com/expire/ ولكن تم إرسالها ببادئة عنوان URL https://geekflare.com/admin/
  • Max-Age / Expires (number in second): متى يجب أن تنتهي صلاحية ملف تعريف الارتباط. عمر ملف تعريف الارتباط يجعل ملف تعريف الارتباط غير صالح بعد الوقت المحدد.
  • HTTPOnly (منطقي): يمكن لخادم الواجهة الخلفية الوصول إلى ملف تعريف الارتباط HTTPOnly وليس البرنامج النصي من جانب العميل عندما يكون صحيحًا.
  • آمن (منطقي): يتم إرسال ملفات تعريف الارتباط فقط عبر نطاق SSL / TLS عندما يكون صحيحًا.
  • sameSite (سلسلة [Strict، Lax، None]): تُستخدم لتمكين / تقييد ملفات تعريف الارتباط المرسلة عبر الطلبات عبر المواقع. لمعرفة المزيد من التفاصيل حول ملفات تعريف الارتباط sameSite انظر MDN. يقبل ثلاثة خيارات Strict و Lax و None. تم تعيين القيمة الآمنة لملف تعريف الارتباط على "صواب" لتكوين ملف تعريف الارتباط sameSite = لا شيء.

لماذا HTTPOnly cookie for tokens؟

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

يتم تعيين / الحصول على ملفات تعريف الارتباط HTTP فقط عن طريق الخادم / الواجهة الخلفية ولكن ليس من جانب العميل.

البرنامج النصي من جانب العميل مقيد للوصول إلى ملف تعريف ارتباط HTTP فقط. لذا فإن ملفات تعريف الارتباط HTTPOnly ليست عرضة لهجمات XSS وهي أكثر أمانًا. لأنه لا يمكن الوصول إليه إلا من خلال الخادم.

تفعيل ملف تعريف الارتباط HTTPOnly في الخلفية الممكّنة لـ CORS

يحتاج تمكين ملف تعريف الارتباط في CORS إلى التكوين أدناه في التطبيق / الخادم.

  • قم بتعيين رأس Access-Control-Allow-Credentials على "صحيح".
  • يجب ألا يكون Access-Control-Allow-Origin و Access-Control-Allow-Headers حرف بدل (*).
  • يجب أن تكون سمة Cookie sameSite "لا شيء".
  • لتمكين قيمة sameSite إلى لا شيء ، قم بتعيين القيمة الآمنة على "true": قم بتمكين الواجهة الخلفية باستخدام شهادة SSL / TLS للعمل في اسم المجال.

دعنا نرى مثالاً رمزًا يعيّن رمز وصول في ملف تعريف الارتباط HTTPOnly بعد التحقق من بيانات اعتماد تسجيل الدخول.

 const express = require('express'); const app = express(); const cors = require('cors'); app.use(cors({ origin: [ 'https://app.geekflare.com', 'https://lab.geekflare.com' ], methods: ['GET', 'PUT', 'POST'], allowedHeaders: ['Content-Type', 'Authorization', 'x-csrf-token'], credentials: true, maxAge: 600, exposedHeaders: ['*', 'Authorization' ] })); app.post('/login', function (req, res, next) { res.cookie('access_token', access_token, { expires: new Date(Date.now() + (3600 * 1000 * 24 * 180 * 1)), //second min hour days year secure: true, // set to true if your using https or samesite is none httpOnly: true, // backend only sameSite: 'none' // set to none for cross-request }); res.json({ msg: 'Login Successfully', access_token }); }); app.listen(80, function () { console.log('CORS-enabled web server listening on port 80') });

يمكنك تكوين ملفات تعريف الارتباط CORS و HTTPOnly عن طريق تنفيذ الخطوات الأربع المذكورة أعلاه في لغة الواجهة الخلفية وخادم الويب.

يمكنك اتباع هذا البرنامج التعليمي لـ apache و Nginx لتمكين CORS باتباع الخطوات المذكورة أعلاه.

withCredentials لطلب Cross-Origin

أوراق الاعتماد (ملف تعريف الارتباط ، التفويض) المرسلة مع طلب نفس الأصل بشكل افتراضي. بالنسبة إلى الأصل المتقاطع ، يتعين علينا تحديد withCredentials إلى true.

XMLHttpRequest API:

 var xhr = new XMLHttpRequest(); xhr.open('GET', 'http://api.geekflare.com/user', true); xhr.withCredentials = true; xhr.send(null);

جلب API:

 fetch('http://api.geekflare.com/user', { credentials: 'include' });

JQuery Ajax:

 $.ajax({ url: 'http://api.geekflare.com/user', xhrFields: { withCredentials: true } });

أكسيوس:

 axios.defaults.withCredentials = true

استنتاج

آمل أن تساعدك المقالة أعلاه على فهم كيفية عمل CORS وتمكين CORS للطلبات عبر الأصل في الخادم. لماذا يعد تخزين ملفات تعريف الارتباط في HTTPOnly آمنًا وكيف يتم استخدام بيانات الاعتماد في العملاء للطلبات عبر الأصل.