JavaRush /Java blogi /Random-UZ /Java-da xavfsizlik: eng yaxshi amaliyotlar

Java-da xavfsizlik: eng yaxshi amaliyotlar

Guruhda nashr etilgan
Server ilovalarida eng muhim ko'rsatkichlardan biri xavfsizlikdir. Bu Funktsional bo'lmagan talablarning turlaridan biridir . Java-da xavfsizlik: eng yaxshi amaliyotlar - 1Xavfsizlik ko'plab komponentlarga ega. Albatta, ma'lum bo'lgan barcha himoya tamoyillari va harakatlarini to'liq qamrab olish uchun siz bir nechta maqola yozishingiz kerak, shuning uchun eng muhimlariga e'tibor qarataylik. Ushbu mavzuni yaxshi biladigan, barcha jarayonlarni o'rnata oladigan va ular yangi xavfsizlik teshiklarini yaratmasligini ta'minlaydigan odam har qanday jamoaga kerak bo'ladi. Albatta, agar siz ushbu amaliyotlarga rioya qilsangiz, dastur butunlay xavfsiz bo'ladi deb o'ylamasligingiz kerak. Yo'q! Lekin, albatta, ular bilan xavfsizroq bo'ladi. Bor.

1. Java tili darajasida xavfsizlikni ta'minlang

Birinchidan, Java-da xavfsizlik to'g'ridan-to'g'ri til xususiyatlari darajasida boshlanadi. Kirish modifikatorlari bo'lmaganida, biz nima qilar edik?... Anarxiya, kam emas. Dasturlash tili bizga xavfsiz kod yozishga yordam beradi va ko'plab yashirin xavfsizlik xususiyatlaridan foydalanishga yordam beradi:
  1. Kuchli yozish. Java statik tarzda yozilgan til bo'lib, ish vaqtida xatoliklarni aniqlash imkonini beradi.
  2. Kirish modifikatorlari. Ularning yordami bilan biz sinflar, usullar va sinf maydonlariga kirishni kerakli tarzda sozlashimiz mumkin.
  3. Avtomatik xotirani boshqarish. Shu maqsadda bizda (Javachilar ;)) sizni qo'lda sozlashdan ozod qiladigan Garbage Collector mavjud. Ha, ba'zida muammolar paydo bo'ladi.
  4. Bayt kodini tekshirish: Java uni ishga tushirishdan oldin ish vaqti bo'yicha tekshiriladigan bayt kodiga kompilyatsiya qiladi .
Boshqa narsalar qatorida, Oracle tomonidan xavfsizlik bo'yicha tavsiyalar mavjud . Albatta, u "yuqori uslubda" yozilmagan va siz uni o'qiyotganda bir necha marta uxlab qolishingiz mumkin, lekin bunga arziydi. Ayniqsa, muhim hujjat Java SE uchun xavfsiz kodlash boʻyicha koʻrsatmalar boʻlib , u xavfsiz kod yozish boʻyicha maslahatlar beradi. Ushbu hujjat juda ko'p foydali ma'lumotlarni o'z ichiga oladi. Iloji bo'lsa, albatta o'qishga arziydi. Ushbu materialga qiziqish uyg'otish uchun quyidagi qiziqarli maslahatlar mavjud:
  1. Xavfsiz sezgir sinflarni ketma-ketlashtirishdan saqlaning. Bunday holda siz seriyali fayldan sinf interfeysini olishingiz mumkin, ketma-ketlashtirilayotgan ma'lumotlarni hisobga olmaganda.
  2. O'zgaruvchan ma'lumotlar sinflaridan qochishga harakat qiling. Bu o'zgarmas sinflarning barcha afzalliklarini beradi (masalan, ip xavfsizligi). Agar o'zgaruvchan ob'ekt bo'lsa, bu kutilmagan xatti-harakatlarga olib kelishi mumkin.
  3. Qaytarilgan o'zgaruvchan ob'ektlarning nusxalarini yarating. Agar usul ichki o'zgaruvchan ob'ektga havolani qaytarsa, mijoz kodi ob'ektning ichki holatini o'zgartirishi mumkin.
  4. Va hokazo…
Umuman olganda, Java SE uchun xavfsiz kodlash bo'yicha ko'rsatmalar Java-da kodni to'g'ri va xavfsiz yozish bo'yicha maslahatlar va tavsiyalar to'plamini o'z ichiga oladi.

2. SQL injection zaifligini yo'q qilish

Noyob zaiflik. Uning o'ziga xosligi shundaki, u eng mashhur va eng keng tarqalgan zaifliklardan biri hisoblanadi. Agar siz xavfsizlik masalasiga qiziqmasangiz, unda siz bu haqda bilmaysiz. SQL in'ektsiyasi nima? Bu kutilmagan joyda qo'shimcha SQL kodini kiritish orqali ma'lumotlar bazasiga hujum. Aytaylik, bizda ma'lumotlar bazasini so'rash uchun ba'zi parametrlarni oladigan usul mavjud. Masalan, foydalanuvchi nomi. Zaiflikka ega kod quyidagicha ko'rinadi:
// Метод достает из базы данных всех пользователей с определенным именем
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) {
   //переводит в коллекцию юзеров
}
Bu misolda sql so'rovi alohida satrda oldindan tayyorlangan. Muammo nimada ekan, shunday emasmi? Ehtimol, muammo shundaki, undan foydalanish yaxshiroqmi String.format? Yo'qmi? Keyin nima? Keling, o'zimizni sinovchining o'rniga qo'yaylik va qiymatda nimani etkazish mumkinligi haqida o'ylaymiz firstName. Masalan:
  1. Siz kutilgan narsani o'tkazishingiz mumkin - foydalanuvchi nomi. Keyin ma'lumotlar bazasi shu nomdagi barcha foydalanuvchilarni qaytaradi.
  2. Siz bo'sh qatorni o'tkazishingiz mumkin: keyin barcha foydalanuvchilar qaytariladi.
  3. Yoki siz quyidagilarni topshirishingiz mumkin: “''; JADVAL FOYDALANUVCHILARINI TOSHLASH;”. Va bu erda yanada katta muammolar bo'ladi. Ushbu so'rov jadvalni ma'lumotlar bazasidan olib tashlaydi. Barcha ma'lumotlar bilan. HAMMA.
Bu qanday muammolarga olib kelishi mumkinligini tasavvur qila olasizmi? Keyin xohlagan narsani yozishingiz mumkin. Siz barcha foydalanuvchilarning nomini o'zgartirishingiz mumkin, ularning manzillarini o'chirishingiz mumkin. Sabotajning ko'lami juda katta. Bunga yo'l qo'ymaslik uchun siz tayyor so'rovni kiritishni to'xtatishingiz va uning o'rniga uni parametrlar yordamida qurishingiz kerak. Bu ma'lumotlar bazasini so'rashning yagona yo'li bo'lishi kerak. Shu tarzda siz ushbu zaiflikni yo'q qilishingiz mumkin. Misol:
// Метод достает из базы данных всех пользователей с определенным именем
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) {
   //переводим в коллекцию юзеров
}
Shunday qilib, bu zaiflikning oldini oladi. Ushbu maqoladan ko'ra muammoga chuqurroq kirishni istaganlar uchun bu erda ajoyib misol . Bu qismni tushunganingizni qanday bilasiz? Agar quyidagi hazil aniq bo'lsa, bu zaiflikning mohiyati aniq ekanligining aniq belgisidir: D Java-da xavfsizlik: eng yaxshi amaliyotlar - 2

3. Bog'liqlarni skanerlang va yangilab turing

Bu nima degani? Bog'liqlik nima ekanligini bilmaganlar uchun tushuntiraman: bu boshqa birovning yechimini qayta ishlatish uchun avtomatik qurish tizimlari (Maven, Gradle, Ant) yordamida loyihaga ulangan kodli jar arxivi. Masalan, biz uchun ish vaqtida oluvchilar, o'rnatuvchilar va hokazolarni ishlab chiqaradigan Project Lombok . Va agar biz katta ilovalar haqida gapiradigan bo'lsak, ular juda ko'p turli xil bog'liqliklardan foydalanadilar. Ba'zilari tranzitivdir (ya'ni har bir bog'liqlikning o'ziga xos bog'liqliklari bo'lishi mumkin va hokazo). Shu sababli, tajovuzkorlar ochiq manbali bog'liqliklarga tobora ko'proq e'tibor berishmoqda, chunki ular muntazam ravishda qo'llaniladi va ko'plab mijozlar uchun muammolarga olib kelishi mumkin. To'liq qaramlik daraxtida ma'lum zaifliklar yo'qligiga ishonch hosil qilish muhim (bu xuddi shunday ko'rinadi). Va buni amalga oshirishning bir necha yo'li mavjud.

Monitoring uchun Snyk-dan foydalaning

Snyk vositasi loyihaning barcha bog'liqliklarini tekshiradi va ma'lum zaifliklarni belgilaydi. U erda, masalan, GitHub orqali loyihalaringizni ro'yxatdan o'tkazishingiz va import qilishingiz mumkin. Java-da xavfsizlik: eng yaxshi amaliyotlar - 3Bundan tashqari, yuqoridagi rasmdan ko'rinib turibdiki, agar yangiroq versiyada ushbu zaiflikka yechim bo'lsa, Snyk buni qilishni va Pull-Request yaratishni taklif qiladi. U ochiq kodli loyihalar uchun bepul ishlatilishi mumkin. Loyihalar ma'lum bir chastotada skanerdan o'tkaziladi: haftada bir marta, oyda bir marta. Men ro'yxatdan o'tdim va barcha ommaviy omborlarimni Snyk skaneriga qo'shdim (bu erda hech qanday xavfli narsa yo'q: ular allaqachon hamma uchun ochiq). Keyinchalik, Snyk skanerlash natijasini ko'rsatdi: Java-da xavfsizlik: eng yaxshi amaliyotlar - 4Va bir muncha vaqt o'tgach, Snyk-bot bog'liqliklar yangilanishi kerak bo'lgan loyihalarda bir nechta Pull-Requestlarni tayyorladi: Java-da xavfsizlik: eng yaxshi amaliyotlar - 5Va yana bir narsa: Java-da xavfsizlik: eng yaxshi amaliyotlar - 6Demak, bu zaifliklarni qidirish va yangilanishni kuzatish uchun ajoyib vosita. yangi versiyalar.

GitHub xavfsizlik laboratoriyasidan foydalaning

GitHub-da ishlaydiganlar o'zlarining o'rnatilgan vositalaridan ham foydalanishlari mumkin. Ushbu yondashuv haqida ko'proq ma'lumotni GitHub Xavfsizlik Laboratoriyasining e'lonlari blogidagi tarjimamda o'qishingiz mumkin . Ushbu vosita, albatta, Snyk-ga qaraganda sodda, ammo siz buni e'tiborsiz qoldirmasligingiz kerak. Bundan tashqari, ma'lum zaifliklar soni faqat o'sib boradi, shuning uchun ham Snyk, ham GitHub Security Lab kengayadi va yaxshilanadi.

Sonatype DepShield-ni faollashtiring

Agar siz omborlaringizni saqlash uchun GitHub-dan foydalansangiz, MarketPlace - Sonatype DepShield-dan loyihalaringizga ilovalardan birini qo'shishingiz mumkin. Uning yordami bilan siz loyihalarni bog'liqliklar uchun ham skanerlashingiz mumkin. Bundan tashqari, agar biror narsa topilsa, quyida ko'rsatilganidek, tegishli tavsif bilan GitHub muammosi yaratiladi: Java-da xavfsizlik: eng yaxshi amaliyotlar - 7

4. Nozik ma'lumotlarga ehtiyotkorlik bilan munosabatda bo'ling

Java-da xavfsizlik: eng yaxshi amaliyotlar - 8Ingliz tilida nutqda "sezgir ma'lumotlar" iborasi ko'proq uchraydi. Mijozning shaxsiy ma'lumotlari, kredit karta raqamlari va boshqa shaxsiy ma'lumotlarini oshkor qilish tuzatib bo'lmaydigan zarar etkazishi mumkin. Avvalo, siz dastur dizaynini diqqat bilan ko'rib chiqishingiz va biron bir ma'lumot haqiqatan ham zarurligini aniqlashingiz kerak. Ehtimol, ularning ba'zilariga ehtiyoj yo'q, lekin ular kelmagan va kelishi dargumon kelajak uchun qo'shilgan. Bundan tashqari, loyiha jurnali paytida bunday ma'lumotlar oqishi mumkin. toString()Maxfiy ma'lumotlarning jurnallaringizga kirishini oldini olishning oddiy usuli bu domen ob'ektlari usullarini (masalan, Foydalanuvchi, Talaba, O'qituvchi va boshqalar) tozalashdir . Bu nozik maydonlarni tasodifan chop etishning oldini oladi. Agar usul yaratish uchun Lombok'dan foydalansangiz , maydonni usuli orqali chiqishda foydalanishni oldini olish uchun toString()izohdan foydalanishingiz mumkin . Bundan tashqari, tashqi dunyo bilan ma'lumotlarni almashishda juda ehtiyot bo'ling. Misol uchun, barcha foydalanuvchilarning ismlarini ko'rsatadigan http so'nggi nuqtasi mavjud. Foydalanuvchining ichki noyob identifikatorini ko'rsatishning hojati yo'q. Nega? Chunki undan foydalanib, tajovuzkor har bir foydalanuvchi haqida boshqa, ko'proq maxfiy ma'lumotlarni olishi mumkin. Misol uchun, agar siz POJO-larni JSON- ga seriyalashtirish va seriyadan chiqarish uchun Jeksondan foydalansangiz, muayyan maydonlarni ketma-ketlashtirish va seriyadan chiqarishni oldini olish uchun va izohlardan foydalanishingiz mumkin . Umuman olganda, turli joylar uchun turli POJO sinflaridan foydalanishingiz kerak. Bu nima degani? @ToString.ExcludetoString()@JsonIgnore@JsonIgnoreProperties
  1. Ma'lumotlar bazasi bilan ishlash uchun faqat POJO - Entity dan foydalaning.
  2. Biznes mantig'i bilan ishlash uchun ob'ektni Modelga o'tkazing.
  3. Tashqi dunyo bilan ishlash va http so'rovlarini yuborish uchun uchinchi shaxslar - DTO dan foydalaning.
Shunday qilib, qaysi maydonlar tashqaridan ko'rinib turishini va qaysi biri ko'rinmasligini aniq belgilashingiz mumkin.

Kuchli shifrlash va xeshlash algoritmlaridan foydalaning

Mijozlarning maxfiy ma'lumotlari xavfsiz tarzda saqlanishi kerak. Buning uchun siz shifrlashdan foydalanishingiz kerak. Vazifaga qarab, qanday shifrlash turidan foydalanishni hal qilishingiz kerak. Bundan tashqari, kuchliroq shifrlash ko'proq vaqt talab etadi, shuning uchun unga bo'lgan ehtiyoj unga sarflangan vaqtni qanchalik oqlashini yana bir bor o'ylab ko'rishingiz kerak. Albatta, algoritmni o'zingiz yozishingiz mumkin. Lekin bu keraksiz. Siz ushbu sohada mavjud echimlardan foydalanishingiz mumkin. Masalan, Google Tink :
<!-- 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>
Keling, uni qanday ishlatishni ko'rib chiqaylik, masalan, qanday qilib shifrlashning bir usuli va boshqasi:
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));
}

Parolni shifrlash

Ushbu vazifa uchun assimetrik shifrlashdan foydalanish eng xavfsiz hisoblanadi. Nega? Chunki ilova haqiqatan ham parollarni qayta shifrlashi shart emas. Bu umumiy yondashuv. Haqiqatda, foydalanuvchi parolni kiritganda, tizim uni shifrlaydi va uni parollar omboridagi narsalar bilan taqqoslaydi. Shifrlash xuddi shu vositalar yordamida amalga oshiriladi, shuning uchun siz ularning mos kelishini kutishingiz mumkin (agar siz to'g'ri parolni kiritsangiz; albatta). Buning uchun BCrypt va SCrypt mos keladi. Har ikkisi ham bir tomonlama funksiyalar (kriptografik xeshlar) bo‘lib, ular juda ko‘p vaqt talab qiladigan hisoblash jihatidan murakkab algoritmlarga ega. Bu sizga kerak bo'lgan narsa, chunki uni boshdan kechirish abadiy davom etadi. Masalan, Spring Security bir qator algoritmlarni qo'llab-quvvatlaydi. SCryptPasswordEncoderSiz ham foydalanishingiz mumkin BCryptPasswordEncoder. Endi kuchli shifrlash algoritmi keyingi yil zaif bo'lishi mumkin. Natijada, biz foydalanilgan algoritmlarni tekshirish va kutubxonalarni algoritmlar bilan yangilash kerak degan xulosaga keldik.

Chiqish o'rniga

Bugun biz xavfsizlik haqida gaplashdik va, albatta, ko'p narsalar sahnada qolib ketdi. Men senga endigina yangi dunyo eshigini ochdim: o‘z hayotini o‘tkazadigan dunyo. Xavfsizlik bilan siyosat bilan bir xil: agar siz siyosat bilan shug'ullanmasangiz, siyosat siz bilan shug'ullanadi. An'anaga ko'ra, men Github hisobimga obuna bo'lishni taklif qilaman . U erda men o'zim o'rganadigan va ishda qo'llaydigan turli texnologiyalar bo'yicha ishimni joylashtiraman.

foydali havolalar

Ha, saytdagi deyarli barcha maqolalar ingliz tilida yozilgan. Biz xohlaymizmi yoki yo'qmi, ingliz tili dasturchilar uchun muloqot qilish tilidir. Dasturlash bo'yicha barcha eng yangi maqolalar, kitoblar va jurnallar ingliz tilida yozilgan. Shuning uchun tavsiyalarga havolalarim asosan ingliz tilida:
  1. Habr: Yangi boshlanuvchilar uchun SQL Injection
  2. Oracle: Java Xavfsizlik Resurs Markazi
  3. Oracle: Java SE uchun xavfsiz kodlash bo'yicha ko'rsatmalar
  4. Baeldung: Java xavfsizligi asoslari
  5. O'rta: Java xavfsizligingizni kuchaytirish uchun 10 ta maslahat
  6. Snyk: Java xavfsizligi bo'yicha 10 ta eng yaxshi amaliyot
  7. JR: GitHub Security Lab e'loni: barcha kodlaringizni birgalikda himoya qilish
Izohlar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION