دليل شامل لمشاركة الموارد عبر الأصول (CORS)، يغطي الإعداد والآثار الأمنية وأفضل الممارسات للمطورين.
مشاركة الموارد عبر الأصول (CORS): الإعداد وأفضل الممارسات الأمنية
في عالم تطوير الويب، يعد الأمان أمرًا بالغ الأهمية. أحد الجوانب الحاسمة لأمان الويب هو إدارة كيفية وصول صفحات الويب من أصل معين إلى موارد من أصل مختلف. هذا هو المكان الذي تلعب فيه مشاركة الموارد عبر الأصول (CORS) دورها. CORS هي ميزة أمان في المتصفح تقيد صفحات الويب من إجراء طلبات إلى نطاق مختلف عن الذي قدم صفحة الويب. هذه الآلية موجودة لمنع المواقع الخبيثة من الوصول إلى البيانات الحساسة. يقدم هذا المقال دليلاً شاملاً لـ CORS، يغطي إعدادها، والآثار الأمنية، وأفضل الممارسات.
فهم سياسة نفس الأصل
تعتمد CORS على أساس سياسة نفس الأصل (Same-Origin Policy)، وهي آلية أمان أساسية تطبقها متصفحات الويب. تقيد سياسة نفس الأصل صفحات الويب من إجراء طلبات إلى نطاق مختلف عن الذي قدم صفحة الويب. يعتبر عنوانا URL من نفس الأصل إذا كان لهما نفس البروتوكول (على سبيل المثال، HTTP أو HTTPS)، والمضيف (على سبيل المثال، example.com)، والمنفذ (على سبيل المثال، 80 أو 443). على سبيل المثال:
http://example.comوhttp://example.com/pathهما من نفس الأصل.http://example.comوhttps://example.comهما من أصلين مختلفين (بروتوكولات مختلفة).http://example.comوhttp://www.example.comهما من أصلين مختلفين (مضيفان مختلفان).http://example.com:80وhttp://example.com:8080هما من أصلين مختلفين (منافذ مختلفة).
تم تصميم سياسة نفس الأصل لمنع هجمات البرمجة النصية عبر المواقع (XSS)، حيث يقوم موقع ويب خبيث بحقن نصوص برمجية في موقع ويب موثوق لسرقة بيانات المستخدم أو تنفيذ إجراءات غير مصرح بها. بدون سياسة نفس الأصل، يمكن لموقع ويب خبيث الوصول إلى معلومات حسابك البنكي إذا كنت مسجلاً الدخول إلى بوابة الخدمات المصرفية عبر الإنترنت في علامة تبويب أخرى.
ما هي مشاركة الموارد عبر الأصول (CORS)؟
في حين أن سياسة نفس الأصل حاسمة للأمان، إلا أنها يمكن أن تكون مقيدة أيضًا في السيناريوهات المشروعة حيث تحتاج مواقع الويب إلى الوصول إلى موارد من أصول مختلفة. على سبيل المثال، قد يحتاج تطبيق ويب مستضاف على example.com إلى جلب بيانات من واجهة برمجة تطبيقات (API) مستضافة على api.example.net. توفر CORS آلية لتجاوز سياسة نفس الأصل بطريقة محكومة، مما يسمح لصفحات الويب بإجراء طلبات عبر الأصول عندما يأذن الخادم بذلك صراحة.
تعمل CORS عن طريق إضافة ترويسات HTTP إلى الاستجابة من الخادم، مما يشير إلى الأصول المسموح لها بالوصول إلى المورد. يقوم المتصفح بعد ذلك بالتحقق من هذه الترويسات ويحظر الطلب إذا لم يكن أصل صفحة الويب التي تقدم الطلب مسموحًا به.
كيف تعمل CORS: ترويسات HTTP
تعتمد CORS على ترويسات HTTP محددة لتسهيل الطلبات عبر الأصول. إليك الترويسات الرئيسية المعنية:
1. Origin (ترويسة الطلب)
يتم إرسال ترويسة Origin بواسطة المتصفح في الطلبات عبر الأصول. تشير إلى أصل (البروتوكول والمضيف والمنفذ) لصفحة الويب التي تقدم الطلب. على سبيل المثال:
Origin: http://example.com
2. Access-Control-Allow-Origin (ترويسة الاستجابة)
ترويسة Access-Control-Allow-Origin هي أهم ترويسة في CORS. تحدد الأصول المسموح لها بالوصول إلى المورد. يمكن أن تحتوي على إحدى القيم التالية:
- أصل محدد: على سبيل المثال،
Access-Control-Allow-Origin: http://example.comيسمح فقط بالطلبات منhttp://example.com. *(حرف بدل):Access-Control-Allow-Origin: *يسمح بالطلبات من أي أصل. يجب استخدام هذا بحذر، لأنه يعطل فعليًا سياسة نفس الأصل لهذا المورد.
مثال:
Access-Control-Allow-Origin: https://www.example.com
3. Access-Control-Allow-Methods (ترويسة الاستجابة)
تحدد ترويسة Access-Control-Allow-Methods أساليب HTTP (مثل GET، POST، PUT، DELETE) المسموح بها في الطلب عبر الأصول. هذا مطلوب للطلبات المبدئية (سيتم شرحها أدناه).
مثال:
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
4. Access-Control-Allow-Headers (ترويسة الاستجابة)
تحدد ترويسة Access-Control-Allow-Headers ترويسات HTTP المسموح بها في الطلب عبر الأصول. هذا مطلوب أيضًا للطلبات المبدئية.
مثال:
Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With
5. Access-Control-Allow-Credentials (ترويسة الاستجابة)
تحدد ترويسة Access-Control-Allow-Credentials ما إذا كان يجب على المتصفح تضمين بيانات الاعتماد (مثل ملفات تعريف الارتباط، ترويسات التفويض) في الطلب عبر الأصول. يمكن أن تحتوي على إحدى قيمتين: true أو false. إذا تم تعيين true، لا يمكن تعيين ترويسة Access-Control-Allow-Origin إلى *. يجب أن يكون أصلًا محددًا.
مثال:
Access-Control-Allow-Credentials: true
6. Access-Control-Max-Age (ترويسة الاستجابة)
تحدد ترويسة Access-Control-Max-Age عدد الثواني التي يمكن للمتصفح تخزين نتائج الطلب المبدئي مؤقتًا. يمكن أن يؤدي ذلك إلى تحسين الأداء عن طريق تقليل عدد الطلبات المبدئية.
مثال:
Access-Control-Max-Age: 3600
الطلبات البسيطة مقابل الطلبات المبدئية
تميز CORS بين نوعين من الطلبات عبر الأصول: الطلبات البسيطة والطلبات المبدئية.
الطلبات البسيطة
الطلب البسيط هو طلب يفي بالمعايير التالية:
- الأسلوب هو
GETأوHEADأوPOST. - إذا كان الأسلوب هو
POST، فإن ترويسةContent-Typeهي واحدة مما يلي:application/x-www-form-urlencodedأوmultipart/form-dataأوtext/plain. - لا يقوم الطلب بتعيين أي ترويسات مخصصة (بخلاف تلك التي يتم تعيينها تلقائيًا بواسطة المتصفح).
بالنسبة للطلبات البسيطة، يرسل المتصفح الطلب مباشرة إلى الخادم. ثم يستجيب الخادم بترويسات CORS المناسبة. إذا كان الأصل مسموحًا به، يقوم المتصفح بمعالجة الاستجابة. وإلا، يحظر المتصفح الاستجابة ويطلق خطأ.
الطلبات المبدئية
الطلب المبدئي (preflight request) هو طلب يرسله المتصفح قبل إجراء الطلب الفعلي عبر الأصول إذا كان الطلب لا يفي بمعايير الطلب البسيط. يحدث هذا عادةً عندما يستخدم الطلب أسلوبًا آخر غير GET أو HEAD أو POST، أو عندما يقوم الطلب بتعيين ترويسات مخصصة.
الطلب المبدئي هو طلب OPTIONS يتضمن الترويسات التالية:
Origin: أصل صفحة الويب التي تقدم الطلب.Access-Control-Request-Method: أسلوب HTTP الذي سيتم استخدامه في الطلب الفعلي.Access-Control-Request-Headers: قائمة مفصولة بفواصل للترويسات المخصصة التي سيتم استخدامها في الطلب الفعلي.
ثم يستجيب الخادم بالترويسات التالية:
Access-Control-Allow-Origin: الأصل المسموح له بالوصول إلى المورد.Access-Control-Allow-Methods: أساليب HTTP المسموح بها في الطلب عبر الأصول.Access-Control-Allow-Headers: ترويسات HTTP المسموح بها في الطلب عبر الأصول.Access-Control-Max-Age: عدد الثواني التي يمكن للمتصفح تخزين نتائج الطلب المبدئي مؤقتًا.
إذا استجاب الخادم بترويسات CORS المناسبة، يتابع المتصفح الطلب الفعلي عبر الأصول. وإلا، يحظر المتصفح الطلب ويطلق خطأ.
أمثلة على إعداد CORS
يختلف تنفيذ CORS اعتمادًا على التقنية المستخدمة من جانب الخادم. إليك بعض الأمثلة للغات وأطر العمل الشائعة من جانب الخادم:
Node.js مع Express
يعد استخدام الوسيط cors نهجًا شائعًا لإعداد CORS في Node.js مع Express:
const express = require('express');
const cors = require('cors');
const app = express();
// Enable CORS for all origins
app.use(cors());
// Enable CORS for a specific origin
// app.use(cors({ origin: 'http://example.com' }));
// Enable CORS with options
// app.use(cors({
// origin: ['http://example.com', 'http://localhost:3000'],
// methods: ['GET', 'POST', 'PUT', 'DELETE'],
// allowedHeaders: ['Content-Type', 'Authorization'],
// credentials: true
// }));
app.get('/api/data', (req, res) => {
res.json({ message: 'Hello from the API!' });
});
app.listen(3001, () => {
console.log('Server listening on port 3001');
});
Python مع Flask
يمكنك استخدام ملحق Flask-CORS لإعداد CORS في Flask:
from flask import Flask
from flask_cors import CORS
app = Flask(__name__)
// Enable CORS for all origins
CORS(app)
// Enable CORS for specific origins
// CORS(app, origins=['http://example.com', 'http://localhost:3000'])
@app.route('/api/data')
def get_data():
return {'message': 'Hello from the API!'}
if __name__ == '__main__':
app.run(port=3001)
Java مع Spring Boot
يوفر Spring Boot عدة طرق لإعداد CORS. أحد الأساليب هو استخدام التعليق التوضيحي @CrossOrigin:
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@CrossOrigin(origins = "http://example.com") // Specific origin
public class ApiController {
@GetMapping("/api/data")
public String getData() {
return "Hello from the API!";
}
}
// Global CORS configuration (using WebMvcConfigurer):
// @Configuration
// public class CorsConfig implements WebMvcConfigurer {
// @Override
// public void addCorsMappings(CorsRegistry registry) {
// registry.addMapping("/**")
// .allowedOrigins("http://example.com", "http://localhost:3000")
// .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
// .allowedHeaders("Content-Type", "Authorization")
// .allowCredentials(true)
// .maxAge(3600);
// }
// }
PHP
في PHP، يمكنك تعيين ترويسات CORS مباشرة في النص البرمجي الخاص بك:
<?php
header("Access-Control-Allow-Origin: http://example.com");
header("Content-Type: application/json");
$data = array("message" => "Hello from the API!");
echo json_encode($data);
?>
اعتبارات أمان CORS
بينما تتيح CORS الطلبات عبر الأصول، من الضروري فهم الآثار الأمنية وتنفيذها بشكل صحيح لتجنب الثغرات الأمنية.
1. تجنب استخدام Access-Control-Allow-Origin: * في بيئة الإنتاج
يسمح استخدام حرف البدل * في ترويسة Access-Control-Allow-Origin بالطلبات من أي أصل، مما يعطل فعليًا سياسة نفس الأصل لهذا المورد. يمكن أن يعرض هذا واجهة برمجة التطبيقات الخاصة بك لمواقع الويب الخبيثة التي يمكنها سرقة بيانات المستخدم أو تنفيذ إجراءات غير مصرح بها. بدلاً من ذلك، حدد الأصول الدقيقة المسموح لها بالوصول إلى المورد. على سبيل المثال، إذا كان تطبيق الويب الخاص بك مستضافًا على example.com ويحتاج إلى الوصول إلى واجهة برمجة تطبيقات مستضافة على api.example.com، فقم بتعيين الترويسة على Access-Control-Allow-Origin: http://example.com.
مثال عالمي: تخيل واجهة برمجة تطبيقات لخدمة مالية تقوم بتعيين Access-Control-Allow-Origin: *. يمكن لموقع ويب خبيث بعد ذلك إجراء طلبات إلى هذه الواجهة نيابة عن مستخدم مسجل الدخول، مما قد يؤدي إلى تحويل الأموال دون علم المستخدم.
2. التحقق من صحة ترويسة Origin على الخادم
حتى إذا قمت بتحديد قائمة بالأصول المسموح بها، فمن المهم التحقق من صحة ترويسة Origin على الخادم لمنع المهاجمين من تزييف الأصل. يمكن للمهاجم إرسال طلب بترويسة Origin مزورة لتجاوز عمليات التحقق من CORS. للتخفيف من هذا، قارن ترويسة Origin بقائمة من الأصول الموثوقة من جانب الخادم. إذا لم يكن الأصل في القائمة، فارفض الطلب.
مثال عالمي: فكر في منصة للتجارة الإلكترونية. يمكن لمهاجم محاولة تقليد Origin لمتجر شرعي للوصول إلى بيانات العملاء الحساسة من واجهة برمجة تطبيقات منصة التجارة الإلكترونية.
3. كن حذرًا مع Access-Control-Allow-Credentials: true
إذا قمت بتعيين Access-Control-Allow-Credentials: true، لا يمكن تعيين ترويسة Access-Control-Allow-Origin إلى *. يجب أن يكون أصلًا محددًا. هذا لأن السماح ببيانات الاعتماد من أي أصل يمكن أن يخلق خطرًا أمنيًا، حيث يمكن أن يسمح للمواقع الخبيثة بالوصول إلى بيانات المستخدم إذا تمكنت من خداع المستخدم لزيارة موقعها بينما يكون المستخدم مسجلاً الدخول أيضًا إلى الموقع المستهدف. هذا الإعداد مهم عند التعامل مع ملفات تعريف الارتباط أو ترويسات التفويض.
مثال عالمي: منصة وسائط اجتماعية تسمح بطلبات عبر الأصول مع بيانات الاعتماد تتطلب إدارة دقيقة لمنع الوصول غير المصرح به إلى حسابات المستخدمين.
4. قم بإعداد Access-Control-Allow-Methods و Access-Control-Allow-Headers بشكل صحيح
اسمح فقط بأساليب وترويسات HTTP الضرورية للطلبات عبر الأصول. إذا كنت تحتاج فقط إلى السماح بطلبات GET و POST، فلا تسمح بـ PUT أو DELETE أو أساليب أخرى. وبالمثل، اسمح فقط بالترويسات المحددة التي يحتاجها تطبيقك. يمكن أن تزيد التكوينات المتساهلة بشكل مفرط من خطر الهجمات.
مثال عالمي: يجب على نظام إدارة علاقات العملاء (CRM) الكشف فقط عن نقاط نهاية واجهة برمجة التطبيقات والترويسات الضرورية لتكاملات الجهات الخارجية المعتمدة، مما يقلل من سطح الهجوم.
5. استخدم HTTPS للاتصال الآمن
استخدم دائمًا HTTPS للاتصال الآمن بين المتصفح والخادم. يقوم HTTPS بتشفير البيانات المنقولة بين المتصفح والخادم، مما يمنع التنصت وهجمات الرجل في المنتصف. يمكن أن يؤدي استخدام HTTP إلى كشف البيانات الحساسة للمهاجمين، حتى لو تم تكوين CORS بشكل صحيح.
مثال عالمي: يجب على تطبيقات الرعاية الصحية استخدام HTTPS لحماية بيانات المرضى المنقولة عبر أصول مختلفة.
6. سياسة أمان المحتوى (CSP)
على الرغم من أنها ليست مرتبطة مباشرة بـ CORS، إلا أن سياسة أمان المحتوى (CSP) هي آلية أمان مهمة أخرى يمكن أن تساعد في منع هجمات XSS. تتيح لك CSP تحديد قائمة بيضاء بالمصادر التي يُسمح للمتصفح بتحميل الموارد منها. يمكن أن يساعد هذا في منع المهاجمين من حقن نصوص برمجية خبيثة في موقع الويب الخاص بك، حتى لو تمكنوا من تجاوز تدابير الأمان الأخرى.
مثال عالمي: غالبًا ما تستخدم المؤسسات المالية سياسات CSP صارمة للحد من مصادر المحتوى الذي يتم تحميله على بواباتها المصرفية عبر الإنترنت، مما يقلل من خطر هجمات XSS.
مشكلات CORS الشائعة واستكشاف الأخطاء وإصلاحها
يمكن أن تكون أخطاء CORS محبطة عند تصحيحها. إليك بعض المشكلات الشائعة وكيفية استكشافها وإصلاحها:
1. "No 'Access-Control-Allow-Origin' header is present on the requested resource."
هذا هو خطأ CORS الأكثر شيوعًا. يشير إلى أن الخادم لا يعيد ترويسة Access-Control-Allow-Origin في استجابته. تأكد من أن الخادم مهيأ لإرسال ترويسات CORS الصحيحة لأصل صفحة الويب التي تقدم الطلب. تحقق مرة أخرى من الكود وملفات التكوين من جانب الخادم.
2. "Response to preflight request doesn't pass access control check: It does not have HTTP ok status."
يشير هذا الخطأ إلى فشل الطلب المبدئي. يمكن أن يحدث هذا إذا كان الخادم لا يستجيب لطلبات OPTIONS أو إذا كان الخادم يعيد رمز حالة خطأ (على سبيل المثال، 404، 500) استجابةً للطلب المبدئي. تأكد من أن الخادم مهيأ للتعامل مع طلبات OPTIONS وأنه يعيد رمز حالة 200 OK.
3. "Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'."
يحدث هذا الخطأ عندما تحاول إرسال بيانات اعتماد (مثل ملفات تعريف الارتباط) في طلب عبر الأصول ويتم تعيين ترويسة Access-Control-Allow-Origin على *. كما ذكرنا سابقًا، لا يمكنك استخدام حرف البدل * عند إرسال بيانات الاعتماد. يجب عليك تحديد الأصل الدقيق المسموح له بالوصول إلى المورد.
4. التخزين المؤقت للمتصفح
يمكن للمتصفحات تخزين استجابات CORS مؤقتًا، مما قد يؤدي إلى سلوك غير متوقع إذا تغير تكوين CORS. لمنع مشكلات التخزين المؤقت، قم بتعيين ترويسة Cache-Control في الاستجابة إلى no-cache أو no-store أو max-age=0. يمكنك أيضًا استخدام ترويسة Access-Control-Max-Age للتحكم في مدة تخزين المتصفح لنتائج الطلب المبدئي مؤقتًا.
بدائل CORS
بينما CORS هي الطريقة القياسية لتمكين الطلبات عبر الأصول، هناك بعض البدائل التي يمكنك وضعها في الاعتبار في سيناريوهات معينة:
1. JSON مع الحشو (JSONP)
JSONP هي تقنية تستخدم علامة <script> لتجاوز سياسة نفس الأصل. تعمل JSONP عن طريق تغليف بيانات JSON في استدعاء دالة JavaScript. يقوم المتصفح بعد ذلك بتنفيذ دالة JavaScript، ويمرر بيانات JSON كوسيط. يعد تنفيذ JSONP أبسط من CORS، ولكنه يحتوي على بعض القيود. فهو يدعم فقط طلبات GET، وهو أقل أمانًا من CORS.
2. الوكيل العكسي (Reverse Proxy)
الوكيل العكسي هو خادم يقع أمام خادم واجهة برمجة التطبيقات الخاص بك ويعيد توجيه الطلبات إليه. يمكن تكوين الوكيل العكسي لإضافة ترويسات CORS اللازمة إلى الاستجابة، مما يخفي فعليًا الطلبات عبر الأصول عن المتصفح. يمكن أن يكون هذا النهج مفيدًا إذا لم يكن لديك سيطرة على خادم واجهة برمجة التطبيقات أو إذا كنت ترغب في تبسيط تكوين CORS.
الخلاصة
مشاركة الموارد عبر الأصول (CORS) هي آلية أمان حاسمة تسمح لصفحات الويب بالوصول إلى الموارد من أصول مختلفة بطريقة محكومة. يعد فهم كيفية عمل CORS وتنفيذها بشكل صحيح أمرًا ضروريًا لبناء تطبيقات ويب آمنة وموثوقة. من خلال اتباع أفضل الممارسات الموضحة في هذا المقال، يمكنك إدارة CORS بفعالية وحماية واجهات برمجة التطبيقات الخاصة بك من الوصول غير المصرح به.
تذكر دائمًا إعطاء الأولوية للأمان عند تكوين CORS. تجنب استخدام أحرف البدل، وتحقق من صحة ترويسة Origin، واستخدم HTTPS للاتصال الآمن. من خلال اتخاذ هذه الاحتياطات، يمكنك التأكد من حماية تطبيقات الويب الخاصة بك من الهجمات عبر المواقع.
يقدم هذا الدليل الشامل أساسًا متينًا لفهم CORS. ارجع دائمًا إلى الوثائق الرسمية للتقنية المحددة من جانب الخادم للحصول على أحدث المعلومات وأفضل الممارسات. ابق على اطلاع على التهديدات الأمنية الناشئة وقم بتكييف تكوين CORS الخاص بك وفقًا لذلك.