Rails/security

من موسوعة حسوب

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

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

  • جميع التدابير المضادة التي سيسلط الضوء عليها.
  • مفهوم الجلسات (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 في الصورة). نظرًا لأنه لا يجوز لك تغيير ملف تعريف ارتباط لنطاق آخر (بسبب نفس سياسة الأصل)، يجب على المهاجم تشغيل 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، مستحيلًا. هذا بسبب نفس سياسة الأصل في المتصفح الخاص بك: قد لا تقرأ الشيفرة البرمجية التي حُقنَت (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.

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

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

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

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

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

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

التعبيرات العادية

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

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

/^https?:\/\/[^\n]+$/i

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

javascript:exploit_code();/*

http://hi.com

*/

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

link_to "Homepage", @user.homepage

يبدو الارتباط بريئًا للزائرين، ولكن عند النقر عليه، ينفذ وظيفة JavaScript "exploit_code" أو أي JavaScript آخر يوفره المهاجم.

لإصلاح التعبير العادي، يجب استخدام \ A و \ z بدلاً من ^ و $، مثل:

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

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

# content should include a line "Meanwhile" anywhere in the string

validates :content, format: { with: /^Meanwhile$/, multiline: true }

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

تصعيد الصلاحيات

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

المعامل الأكثر شيوعًا التي قد يعبث بها المستخدم هو معامل المعرّف، كما هو الحال في 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 كل طلب وقد تكررها وتغيرها. هذه طريقة سهلة لتجاوز أي عمليات التحقق من جافا سكريبت. وهناك أيضًا البروكسي من جانب العميل تسمح لك باعتراض أي طلب واستجابة من وإلى الإنترنت.

الحقن

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

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

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

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

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

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

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

حقن SQL

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

المقدمة

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

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

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

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

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

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

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

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 بحيث يعرض تطبيق الويب القيم من جدول المستخدم. تأكد من تحديث Rails الخاصة بك إلى 2.1.1 على الأقل.

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

يحتوي Ruby on Rails على فلتر مدمج لأحرف 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 يحتوي على علامات استفهام. الإصدارات المعقمة للمتغيرات في الجزء الثاني من المصفوفة تحل محل علامات الاستفهام. أو يمكنك تمرير تجزئة لنفس النتيجة:

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

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

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

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

نقاط الدخول

نقطة الإدخال هي عنوان URL ضعيف ومعاملاته حيث يمكن للمهاجم بدء هجوم.

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

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

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