JavaRush /مدونة جافا /Random-AR /الأمن في جافا: أفضل الممارسات
Roman Beekeeper
مستوى

الأمن في جافا: أفضل الممارسات

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

1. توفير الأمان على مستوى لغة جافا

أولاً، يبدأ الأمان في Java مباشرةً على مستوى ميزات اللغة. هذا ما سنفعله لو لم تكن هناك معدّلات الوصول؟... الفوضى، لا أقل. تساعدنا لغة البرمجة على كتابة تعليمات برمجية آمنة وكذلك الاستفادة من العديد من ميزات الأمان الضمنية:
  1. كتابة قوية. Java هي لغة مكتوبة بشكل ثابت توفر القدرة على اكتشاف أخطاء الكتابة في وقت التشغيل.
  2. معدّلات الوصول. بفضلهم، يمكننا تكوين الوصول إلى الفئات والأساليب وحقول الفئات بالطريقة التي نحتاجها.
  3. إدارة الذاكرة التلقائية. لهذا الغرض، لدينا (Javaists ;)) جامع البيانات المهملة، الذي يحررك من التكوين اليدوي. نعم، في بعض الأحيان تنشأ مشاكل.
  4. فحص Bytecode: يتم تجميع Java إلى bytecode، والذي يتم فحصه بواسطة وقت التشغيل قبل تشغيله.
ومن بين أمور أخرى، هناك توصيات من Oracle بشأن الأمان. بالطبع، إنها ليست مكتوبة "بأسلوب رفيع" وقد تغفو عدة مرات أثناء قراءتها، لكن الأمر يستحق ذلك. هناك وثيقة مهمة بشكل خاص وهي إرشادات الترميز الآمن لـ Java SE ، والتي توفر نصائح حول كيفية كتابة تعليمات برمجية آمنة. تحتوي هذه الوثيقة على الكثير من المعلومات المفيدة. إذا كان ذلك ممكنا، فهو بالتأكيد يستحق القراءة. لإثارة الاهتمام بهذه المادة، إليك بعض النصائح المثيرة للاهتمام:
  1. تجنب إجراء تسلسل للفئات الحساسة للأمن. في هذه الحالة، يمكنك الحصول على واجهة الفئة من الملف المتسلسل، ناهيك عن البيانات التي يتم إجراء تسلسل لها.
  2. حاول تجنب فئات البيانات القابلة للتغيير. وهذا يعطي جميع فوائد الفئات غير القابلة للتغيير (مثل سلامة الخيط). إذا كان هناك كائن قابل للتغيير، فقد يؤدي ذلك إلى سلوك غير متوقع.
  3. عمل نسخ من الكائنات القابلة للتغيير التي تم إرجاعها. إذا قامت إحدى الطرق بإرجاع مرجع إلى كائن داخلي قابل للتغيير، فيمكن لرمز العميل تغيير الحالة الداخلية للكائن.
  4. وما إلى ذلك وهلم جرا…
بشكل عام، تحتوي إرشادات الترميز الآمن لـ Java SE على مجموعة من النصائح والحيل حول كيفية كتابة التعليمات البرمجية في Java بشكل صحيح وآمن.

2. القضاء على ثغرة حقن SQL

الضعف الفريد. يكمن تفردها في حقيقة أنها واحدة من أشهر نقاط الضعف وأكثرها شيوعًا. إذا لم تكن مهتما بمسألة الأمن، فلن تعرف عنها. ما هو حقن SQL؟ هذا هجوم على قاعدة بيانات عن طريق إدخال تعليمات برمجية SQL إضافية في مكان غير متوقع. لنفترض أن لدينا طريقة تأخذ بعض المعلمات للاستعلام عن قاعدة البيانات. على سبيل المثال، اسم المستخدم. سيبدو رمز الثغرة الأمنية كما يلي:
// Метод достает из базы данных всех пользователей с определенным именем
public List<User> findByFirstName(String firstName) throws SQLException {
   // Создается связь с базой данных
   Connection connection = DriverManager.getConnection(DB_URL, USER, PASS);

   // Пишем sql request в базу данных с нашим firstName
   String query = "SELECT * FROM USERS WHERE firstName = " + firstName;

   // выполняем request
   Statement statement = connection.createStatement();
   ResultSet result = statement.executeQuery(query);

   // при помощи mapToUsers переводит ResultSet в коллекцию юзеров.
   return mapToUsers(result);
}

private List<User> mapToUsers(ResultSet resultSet) {
   //переводит в коллекцию юзеров
}
في هذا المثال، يتم إعداد استعلام SQL مسبقًا في سطر منفصل. يبدو أن ما هي المشكلة، أليس كذلك؟ ربما المشكلة هي أنه سيكون من الأفضل استخدامها String.format؟ لا؟ ماذا بعد؟ دعونا نضع أنفسنا في مكان المُختبر ونفكر فيما يمكن نقله من خلال القيمة firstName. على سبيل المثال:
  1. يمكنك تمرير ما هو متوقع - اسم المستخدم. ثم ستعيد قاعدة البيانات كافة المستخدمين بهذا الاسم.
  2. يمكنك تمرير سلسلة فارغة: ثم سيتم إرجاع جميع المستخدمين.
  3. أو يمكنك تمرير ما يلي: "''; إسقاط مستخدمي الجدول؛". وهنا ستكون هناك مشاكل أكبر. سيقوم هذا الاستعلام بإزالة الجدول من قاعدة البيانات. مع كافة البيانات. الجميع.
هل يمكنك أن تتخيل ما هي المشاكل التي يمكن أن يسببها هذا؟ ثم يمكنك أن تكتب ما تريد. يمكنك تغيير اسم جميع المستخدمين، ويمكنك حذف عناوينهم. نطاق التخريب واسع. لتجنب ذلك، تحتاج إلى التوقف عن إدخال استعلام جاهز وبدلاً من ذلك قم بإنشائه باستخدام المعلمات. يجب أن تكون هذه هي الطريقة الوحيدة للاستعلام عن قاعدة البيانات. بهذه الطريقة يمكنك القضاء على هذه الثغرة الأمنية. مثال:
// Метод достает из базы данных всех пользователей с определенным именем
public List<User> findByFirstName(String firstName) throws SQLException {
   // Создается связь с базой данных
   Connection connection = DriverManager.getConnection(DB_URL, USER, PASS);

   // Создаем параметризированный request.
   String query = "SELECT * FROM USERS WHERE firstName = ?";

   // Создаем подготовленный стейтмент с параметризованным requestом
   PreparedStatement statement = connection.prepareStatement(query);

   // Передаем meaning параметра
   statement.setString(1, firstName);

   // выполняем request
   ResultSet result = statement.executeQuery(query);

   // при помощи mapToUsers переводим ResultSet в коллекцию юзеров.
   return mapToUsers(result);
}

private List<User> mapToUsers(ResultSet resultSet) {
   //переводим в коллекцию юзеров
}
وبهذه الطريقة يتم تجنب هذه الثغرة الأمنية. بالنسبة لأولئك الذين يريدون التعمق في هذه القضية أكثر من هذه المقالة، إليك مثال رائع . كيف تعرف إذا كنت تفهم هذا الجزء؟ إذا أصبحت النكتة أدناه واضحة، فهذه علامة أكيدة على أن جوهر الثغرة الأمنية واضح:D الأمان في Java: أفضل الممارسات - 2

3. قم بمسح التبعيات وتحديثها باستمرار

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

استخدم Snyk للمراقبة

تقوم أداة Snyk بفحص كافة تبعيات المشروع وتحديد نقاط الضعف المعروفة. هناك يمكنك تسجيل واستيراد مشاريعك عبر GitHub، على سبيل المثال. الأمان في Java: أفضل الممارسات - 3أيضًا، كما ترون من الصورة أعلاه، إذا كان الإصدار الأحدث يحتوي على حل لهذه الثغرة الأمنية، فسوف يعرض Snyk القيام بذلك وإنشاء طلب سحب. ويمكن استخدامه مجانا للمشاريع مفتوحة المصدر. سيتم فحص المشاريع بوتيرة معينة: مرة واحدة في الأسبوع، ومرة ​​واحدة في الشهر. لقد قمت بالتسجيل وأضفت جميع مستودعاتي العامة إلى فحص Snyk (لا يوجد شيء خطير في هذا: فهي مفتوحة بالفعل للجميع). بعد ذلك، أظهر Snyk نتيجة الفحص: الأمان في Java: أفضل الممارسات - 4وبعد فترة، أعد Snyk-bot العديد من طلبات السحب في المشاريع التي تحتاج إلى تحديث التبعيات: الأمان في Java: أفضل الممارسات - 5وإليك آخر: الأمان في Java: أفضل الممارسات - 6إذن هذه أداة ممتازة للبحث عن الثغرات الأمنية ومراقبة التحديث الإصدارات الجديدة.

استخدم GitHub Security Lab

يمكن أيضًا لأولئك الذين يعملون على GitHub الاستفادة من أدواتهم المدمجة. يمكنك قراءة المزيد عن هذا النهج في ترجمتي من مدونتهم إعلان GitHub Security Lab . هذه الأداة، بالطبع، أبسط من Snyk، لكن بالتأكيد لا ينبغي عليك إهمالها. بالإضافة إلى ذلك، فإن عدد الثغرات الأمنية المعروفة سوف ينمو، لذلك سوف يتوسع ويتحسن كل من Snyk وGitHub Security Lab.

تفعيل سوناتايب DepShield

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

4. تعامل مع البيانات الحساسة بعناية

الأمان في Java: أفضل الممارسات - 8في اللغة الإنجليزية، تعد عبارة "البيانات الحساسة" أكثر شيوعًا. قد يؤدي الكشف عن المعلومات الشخصية وأرقام بطاقات الائتمان وغيرها من المعلومات الشخصية للعميل إلى ضرر لا يمكن إصلاحه. أولاً، تحتاج إلى إلقاء نظرة فاحصة على تصميم التطبيق وتحديد ما إذا كانت هناك حاجة بالفعل إلى أي بيانات. ربما لا حاجة لبعضها، لكنها أضيفت لمستقبل لم يأت، ومن غير المرجح أن يأتي. بالإضافة إلى ذلك، أثناء تسجيل المشروع، قد تتسرب هذه البيانات. تتمثل إحدى الطرق البسيطة لمنع وصول البيانات الحساسة إلى سجلاتك في تنظيف أساليب toString()كيانات المجال (مثل المستخدم والطالب والمعلم وما إلى ذلك). سيؤدي هذا إلى منع طباعة الحقول الحساسة عن طريق الخطأ. إذا كنت تستخدم Lombok لإنشاء طريقة toString()، فيمكنك استخدام تعليق توضيحي @ToString.Excludeلمنع استخدام الحقل في الإخراج عبر الطريقة toString(). كن حذرًا جدًا أيضًا عند مشاركة البيانات مع العالم الخارجي. على سبيل المثال، هناك نقطة نهاية http تعرض أسماء كافة المستخدمين. ليست هناك حاجة لإظهار المعرف الفريد الداخلي للمستخدم. لماذا؟ لأنه باستخدامه يمكن للمهاجم الحصول على معلومات أخرى أكثر سرية حول كل مستخدم. على سبيل المثال، إذا كنت تستخدم Jackson لإجراء تسلسل لكائنات POJO وإلغاء تسلسلها في JSON ، فيمكنك استخدام @JsonIgnoreو التعليقات التوضيحية @JsonIgnorePropertiesلمنع تسلسل حقول معينة وإلغاء تسلسلها. بشكل عام، تحتاج إلى استخدام فئات POJO مختلفة لأماكن مختلفة. ماذا يعني ذلك؟
  1. للعمل مع قاعدة البيانات، استخدم POJO - Entity فقط.
  2. للعمل مع منطق الأعمال، قم بنقل الكيان إلى النموذج.
  3. للعمل مع العالم الخارجي وإرسال طلبات http، استخدم كيانات ثالثة - DTO.
بهذه الطريقة يمكنك تحديد الحقول التي ستكون مرئية من الخارج وأيها لن تكون مرئية بوضوح.

استخدم خوارزميات التشفير والتجزئة القوية

يجب أن يتم تخزين بيانات العملاء السرية بشكل آمن. للقيام بذلك تحتاج إلى استخدام التشفير. اعتمادًا على المهمة، عليك أن تقرر نوع التشفير الذي ستستخدمه. علاوة على ذلك، يستغرق التشفير الأقوى وقتًا أطول، لذا عليك مرة أخرى التفكير في مقدار الحاجة إليه التي تبرر الوقت الذي تقضيه فيه. بالطبع، يمكنك كتابة الخوارزمية بنفسك. ولكن هذا غير ضروري. يمكنك الاستفادة من الحلول الموجودة في هذا المجال. على سبيل المثال جوجل تينك :
<!-- https://mvnrepository.com/artifact/com.google.crypto.tink/tink -->
<dependency>
   <groupId>com.google.crypto.tink</groupId>
   <artifactId>tink</artifactId>
   <version>1.3.0</version>
</dependency>
دعونا نرى كيفية استخدامه، باستخدام مثال كيفية التشفير بطريقة أو بأخرى:
private static void encryptDecryptExample() {
   AeadConfig.register();
   KeysetHandle handle = KeysetHandle.generateNew(AeadKeyTemplates.AES128_CTR_HMAC_SHA256);

   String plaintext = "Цой жив!";
   String aad = "Юрий Клинских";

   Aead aead = handle.getPrimitive(Aead.class);
   byte[] encrypted = aead.encrypt(plaintext.getBytes(), aad.getBytes());
   String encryptedString = Base64.getEncoder().encodeToString(encrypted);
   System.out.println(encryptedString);

   byte[] decrypted = aead.decrypt(Base64.getDecoder().decode(encrypted), aad.getBytes());
   System.out.println(new String(decrypted));
}

تشفير كلمة المرور

لهذه المهمة، من الأكثر أمانًا استخدام التشفير غير المتماثل. لماذا؟ لأن التطبيق حقًا لا يحتاج إلى فك تشفير كلمات المرور مرة أخرى. هذا هو النهج العام. في الواقع، عندما يقوم المستخدم بإدخال كلمة مرور، يقوم النظام بتشفيرها ومقارنتها بما هو موجود في مخزن كلمات المرور. يتم إجراء التشفير باستخدام نفس الوسائل، لذلك يمكنك توقع تطابقها (إذا قمت بإدخال كلمة المرور الصحيحة؛)، بالطبع). BCrypt وSCrypt مناسبان لهذا الغرض. كلاهما دالتان أحادية الاتجاه (تجزئات التشفير) مع خوارزميات معقدة حسابيًا وتستغرق الكثير من الوقت. هذا هو بالضبط ما تحتاجه، حيث أن فك شفرته وجهاً لوجه سيستغرق إلى الأبد. على سبيل المثال، يدعم Spring Security مجموعة من الخوارزميات. SCryptPasswordEncoderتستطيع ايضا استخذام BCryptPasswordEncoder. ما هي خوارزمية التشفير القوية الآن قد تكون ضعيفة في العام المقبل. ونتيجة لذلك، نستنتج أنه من الضروري التحقق من الخوارزميات المستخدمة وتحديث المكتبات بالخوارزميات.

بدلا من الإخراج

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

روابط مفيدة

نعم، جميع المقالات الموجودة على الموقع تقريبًا مكتوبة باللغة الإنجليزية. سواء أحببنا ذلك أم لا، اللغة الإنجليزية هي لغة التواصل بين المبرمجين. جميع أحدث المقالات والكتب والمجلات المتعلقة بالبرمجة مكتوبة باللغة الإنجليزية. ولهذا السبب فإن روابط التوصيات الخاصة بي تكون في الغالب باللغة الإنجليزية:
  1. حبر: حقن SQL للمبتدئين
  2. أوراكل: مركز موارد أمن جافا
  3. Oracle: إرشادات الترميز الآمن لـ Java SE
  4. Baeldung: أساسيات أمن جافا
  5. متوسط: 10 نصائح لتعزيز أمان Java لديك
  6. Snyk: 10 أفضل ممارسات أمان جافا
  7. JR: إعلان عن GitHub Security Lab: حماية كافة التعليمات البرمجية الخاصة بك معًا
تعليقات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION