JavaRush /Java Blogu /Random-AZ /Java-da təhlükəsizlik: ən yaxşı təcrübələr
Roman Beekeeper
Səviyyə

Java-da təhlükəsizlik: ən yaxşı təcrübələr

Qrupda dərc edilmişdir
Server proqramlarında ən vacib göstəricilərdən biri təhlükəsizlikdir. Bu , qeyri-funksional tələblərin növlərindən biridir . Java-da təhlükəsizlik: ən yaxşı təcrübələr - 1Təhlükəsizlik bir çox komponentə malikdir. Əlbəttə ki, bütün bu qoruyucu prinsipləri və məlum olan hərəkətləri tam əhatə etmək üçün birdən çox məqalə yazmalısınız, ona görə də ən vaciblərinə diqqət yetirək. Bu mövzunu yaxşı bilən, bütün prosesləri qura bilən və onların yeni təhlükəsizlik boşluqları yaratmamasını təmin edən şəxs istənilən komandaya lazım olacaq. Əlbəttə ki, bu təcrübələrə əməl etsəniz, tətbiqin tamamilə təhlükəsiz olacağını düşünməməlisiniz. Yox! Ancaq onlarla mütləq daha təhlükəsiz olacaq. Get.

1. Java dili səviyyəsində təhlükəsizliyi təmin edin

Əvvəla, Java-da təhlükəsizlik birbaşa dil xüsusiyyətləri səviyyəsindən başlayır. Giriş modifikatorları olmasaydı, bunu edərdik?... Anarxiya, az deyil. Proqramlaşdırma dili bizə təhlükəsiz kod yazmağa kömək edir və bir çox gizli təhlükəsizlik xüsusiyyətlərindən faydalanır:
  1. Güclü yazmaq. Java, işləmə zamanı tip səhvlərini aşkar etmək imkanı verən statik olaraq yazılmış bir dildir.
  2. Modifikatorlara giriş. Onların sayəsində biz lazım olan şəkildə siniflərə, metodlara və sinif sahələrinə girişi konfiqurasiya edə bilərik.
  3. Avtomatik yaddaş idarəetməsi. Bu məqsədlə bizdə (Javaçılar ;)) sizi əl ilə konfiqurasiyadan azad edən Çöp Kollektoru var. Bəli, bəzən problemlər yaranır.
  4. Bayt kodun yoxlanılması: Java, işə başlamazdan əvvəl iş vaxtı ilə yoxlanılan bayt kodunu tərtib edir .
Digər şeylər arasında Oracle-dan təhlükəsizliklə bağlı tövsiyələr var . Əlbəttə ki, o, "yüksək üslubda" yazılmayıb və onu oxuyarkən bir neçə dəfə yuxuya gedə bilərsiniz, amma buna dəyər. Xüsusilə vacib sənəd Java SE üçün Təhlükəsiz Kodlaşdırma Təlimatlarıdır ki, bu da təhlükəsiz kodun necə yazılmasına dair məsləhətlər verir. Bu sənəddə çoxlu faydalı məlumatlar var. Mümkünsə, mütləq oxumağa dəyər. Bu materiala marağı artırmaq üçün burada bəzi maraqlı məsləhətlər var:
  1. Təhlükəsizliyə həssas sinifləri seriallaşdırmaqdan çəkinin. Bu halda siz seriallaşdırılmış fayldan sinif interfeysini əldə edə bilərsiniz, nəinki seriallaşdırılan məlumatları qeyd etmək olmaz.
  2. Dəyişən məlumat siniflərindən qaçmağa çalışın. Bu, dəyişməz siniflərin bütün üstünlüklərini verir (məsələn, ip təhlükəsizliyi). Dəyişən obyekt varsa, bu, gözlənilməz davranışa səbəb ola bilər.
  3. Qaytarılan dəyişkən obyektlərin surətlərini çıxarın. Metod daxili dəyişən obyektə istinad qaytarırsa, müştəri kodu obyektin daxili vəziyyətini dəyişə bilər.
  4. Və sair…
Ümumiyyətlə, Java SE üçün Təhlükəsiz Kodlaşdırma Təlimatları Java-da kodun düzgün və təhlükəsiz şəkildə yazılmasına dair bir sıra tövsiyə və fəndləri ehtiva edir.

2. SQL injection zəifliyini aradan qaldırın

Unikal zəiflik. Onun unikallığı həm ən məşhur, həm də ən çox yayılmış zəifliklərdən biri olmasındadır. Əgər təhlükəsizlik məsələsi sizi maraqlandırmırsa, o zaman bundan xəbəriniz olmayacaq. SQL injection nədir? Bu, gözlənilməyən yerə əlavə SQL kodu daxil etməklə verilənlər bazasına hücumdur. Tutaq ki, verilənlər bazasını sorğulamaq üçün bəzi parametrlər götürən bir metodumuz var. Məsələn, istifadəçi adı. Zəifliyi olan kod bu kimi görünəcək:
// Метод достает из базы данных всех пользователей с определенным именем
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 nümunədə sql sorğusu əvvəlcədən ayrıca sətirdə hazırlanır. Deyəsən problem nədədir, elə deyilmi? Bəlkə problem ondan istifadə etmək daha yaxşı olardı String.format? Yox? Bəs onda? Gəlin özümüzü bir testerin yerinə qoyaq və dəyərdə nəyi çatdıra biləcəyini düşünək firstName. Misal üçün:
  1. Siz gözlənilənləri keçə bilərsiniz - istifadəçi adı. Sonra verilənlər bazası bu adla bütün istifadəçiləri qaytaracaq.
  2. Siz boş bir sətir ötürə bilərsiniz: sonra bütün istifadəçilər geri qaytarılacaq.
  3. Və ya aşağıdakıları keçə bilərsiniz: “''; CƏDVƏL İSTİFADƏÇİLƏRİNİ DÜŞÜN;”. Və burada daha böyük problemlər olacaq. Bu sorğu cədvəli verilənlər bazasından siləcək. Bütün məlumatlarla. HƏR KƏS.
Bunun hansı problemlərə səbəb ola biləcəyini təsəvvür edə bilərsinizmi? Sonra nə istəsən yaza bilərsən. Bütün istifadəçilərin adını dəyişə bilərsiniz, ünvanlarını silə bilərsiniz. Sabotajın əhatə dairəsi genişdir. Bunun qarşısını almaq üçün hazır sorğunun yeridilməsini dayandırmalı və əvəzinə onu parametrlərdən istifadə edərək qurmalısınız. Bu verilənlər bazasını sorğulamağın yeganə yolu olmalıdır. Bu yolla siz bu zəifliyi aradan qaldıra bilərsiniz. Misal:
// Метод достает из базы данных всех пользователей с определенным именем
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) {
   //переводим в коллекцию юзеров
}
Beləliklə, bu zəifliyin qarşısı alınır. Məsələyə bu məqalədən daha dərindən girmək istəyənlər üçün əla bir nümunə var . Bu hissəni başa düşdüyünüzü necə bilirsiniz? Aşağıdakı zarafat aydınlaşdısa, bu, zəifliyin mahiyyətinin aydın olduğuna əmin bir işarədir :D Java-da təhlükəsizlik: ən yaxşı təcrübələr - 2

3. Asılılıqları skan edin və yeni saxlayın

Bunun mənası nədi? Asılılığın nə olduğunu bilməyənlər üçün izah edəcəyəm: bu, başqasının həllini təkrar istifadə etmək üçün avtomatik qurma sistemlərindən (Maven, Gradle, Ant) istifadə edərək bir layihəyə qoşulan kodu olan bir banka arxividir. Məsələn, iş vaxtı bizim üçün alıcılar, tənzimləyicilər və s. yaradan Project Lombok . Böyük tətbiqlərdən danışsaq, onlar çoxlu müxtəlif asılılıqlardan istifadə edirlər. Bəziləri keçidlidir (yəni hər bir asılılığın öz asılılıqları ola bilər və s.). Buna görə də, təcavüzkarlar getdikcə daha çox açıq mənbə asılılıqlarına diqqət yetirirlər, çünki onlar müntəzəm olaraq istifadə olunur və bir çox müştərilər üçün problem yarada bilər. Bütün asılılıq ağacında məlum zəifliklərin olmadığına əmin olmaq vacibdir (bu, tam olaraq göründüyü kimidir). Və bunun bir neçə yolu var.

Monitorinq üçün Snyk istifadə edin

Snyk aləti bütün layihə asılılıqlarını yoxlayır və məlum zəiflikləri qeyd edir. Orada, məsələn, GitHub vasitəsilə layihələrinizi qeydiyyatdan keçirə və idxal edə bilərsiniz. Java-da təhlükəsizlik: ən yaxşı təcrübələr - 3Həmçinin, yuxarıdakı şəkildən də gördüyünüz kimi, əgər daha yeni versiyada bu zəifliyin həlli varsa, Snyk bunu etməyi və Pull-Request yaratmağı təklif edəcək. Açıq mənbəli layihələr üçün pulsuz istifadə edilə bilər. Layihələr müəyyən tezlikdə skan ediləcək: həftədə bir dəfə, ayda bir dəfə. Mən qeydiyyatdan keçdim və bütün ictimai depolarımı Snyk skanına əlavə etdim (bunun üçün təhlükəli bir şey yoxdur: onlar artıq hamı üçün açıqdır). Sonra, Snyk taramanın nəticəsini göstərdi: Java-da təhlükəsizlik: ən yaxşı təcrübələr - 4Və bir müddət sonra, Snyk-bot asılılıqların yenilənməsi lazım olan layihələrdə bir neçə Pull-Request hazırladı: Java-da təhlükəsizlik: ən yaxşı təcrübələr - 5Və burada başqa bir şey var: Java-da təhlükəsizlik: ən yaxşı təcrübələr - 6Beləliklə, bu, zəiflikləri axtarmaq və yeniləməyə nəzarət etmək üçün əla vasitədir. yeni versiyalar.

GitHub Təhlükəsizlik Laboratoriyasından istifadə edin

GitHub-da işləyənlər də daxili alətlərindən istifadə edə bilərlər. Bu yanaşma haqqında daha çox GitHub Təhlükəsizlik Laboratoriyasının elanı bloqundan mənim tərcüməmdə oxuya bilərsiniz . Bu vasitə, əlbəttə ki, Snyk-dən daha sadədir, lakin siz mütləq onu laqeyd etməməlisiniz. Üstəlik, məlum zəifliklərin sayı artacaq, beləliklə həm Snyk, həm də GitHub Təhlükəsizlik Laboratoriyası genişlənəcək və təkmilləşəcək.

Sonatype DepShield-i aktivləşdirin

Depozitlərinizi saxlamaq üçün GitHub-dan istifadə edirsinizsə, MarketPlace - Sonatype DepShield-dən layihələrinizə tətbiqlərdən birini əlavə edə bilərsiniz. Onun köməyi ilə siz həmçinin layihələri asılılıqlar üçün skan edə bilərsiniz. Üstəlik, bir şey tapsa, aşağıda göstərildiyi kimi müvafiq təsviri olan GitHub Problemi yaradılacaq: Java-da təhlükəsizlik: ən yaxşı təcrübələr - 7

4. Həssas məlumatları ehtiyatla idarə edin

Java-da təhlükəsizlik: ən yaxşı təcrübələr - 8İngilis nitqində "həssas məlumatlar" ifadəsi daha çox yayılmışdır. Müştərinin şəxsi məlumatlarının, kredit kartı nömrələrinin və digər şəxsi məlumatların açıqlanması düzəlməz zərər verə bilər. Hər şeydən əvvəl, proqram dizaynını diqqətlə nəzərdən keçirməli və hər hansı bir məlumatın həqiqətən lazım olub olmadığını müəyyən etməlisiniz. Ola bilsin ki, bəzilərinə ehtiyac yoxdur, amma gəlməmiş və gələcək ehtimalı az olan gələcək üçün əlavə edilib. Bundan əlavə, layihənin qeydiyyatı zamanı belə məlumatlar sıza bilər. toString()Həssas məlumatların jurnallarınıza daxil olmasının qarşısını almağın sadə yolu domen obyektlərinin metodlarını (məsələn, İstifadəçi, Tələbə, Müəllim və s.) təmizləməkdir . Bu, həssas sahələrin təsadüfən çap edilməsinin qarşısını alacaq. Metod yaratmaq üçün Lombok istifadə edirsinizsə , metod vasitəsilə sahənin çıxışda istifadə edilməsinin qarşısını almaq üçün toString()annotasiyadan istifadə edə bilərsiniz . Həmçinin, məlumatları xarici dünya ilə paylaşarkən çox diqqətli olun. Məsələn, bütün istifadəçilərin adlarını göstərən http son nöqtəsi var. İstifadəçinin daxili unikal ID-sini göstərməyə ehtiyac yoxdur. Niyə? Çünki ondan istifadə edərək təcavüzkar hər bir istifadəçi haqqında başqa, daha məxfi məlumatları əldə edə bilər. Məsələn, POJO-ları JSON- da seriallaşdırmaq və seriyadan çıxarmaq üçün Ceksondan istifadə edirsinizsə , xüsusi sahələrin seriallaşdırılmasının və seriyadan çıxarılmasının qarşısını almaq üçün və qeydlərindən istifadə edə bilərsiniz . Ümumiyyətlə, müxtəlif yerlər üçün müxtəlif POJO siniflərindən istifadə etməlisiniz. Bunun mənası nədi? @ToString.ExcludetoString()@JsonIgnore@JsonIgnoreProperties
  1. Verilənlər bazası ilə işləmək üçün yalnız POJO - Entity istifadə edin.
  2. Biznes məntiqi ilə işləmək üçün Müəssisəni Modelə köçürün.
  3. Xarici dünya ilə işləmək və http sorğuları göndərmək üçün üçüncü qurumlardan - DTO-dan istifadə edin.
Bu yolla siz hansı sahələrin kənardan görünəcəyini və hansının görünməyəcəyini dəqiq müəyyən edə bilərsiniz.

Güclü şifrələmə və hashing alqoritmlərindən istifadə edin

Məxfi müştəri məlumatları təhlükəsiz şəkildə saxlanmalıdır. Bunu etmək üçün şifrələmədən istifadə etməlisiniz. Tapşırıqdan asılı olaraq, hansı növ şifrələmədən istifadə edəcəyinizə qərar verməlisiniz. Bundan əlavə, daha güclü şifrələmə daha çox vaxt tələb edir, buna görə də ona olan ehtiyacın ona sərf olunan vaxtı nə qədər əsaslandırdığını yenidən nəzərdən keçirməlisiniz. Təbii ki, alqoritmi özünüz yaza bilərsiniz. Amma bu lazımsızdır. Bu sahədə mövcud həllərdən yararlana bilərsiniz. Məsələn, 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>
Bir və digər şəkildə şifrələmə nümunəsindən istifadə edərək, ondan necə istifadə edəcəyimizi görək:
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));
}

Parolun şifrələnməsi

Bu tapşırıq üçün asimmetrik şifrələmədən istifadə etmək ən təhlükəsizdir. Niyə? Çünki proqram həqiqətən parolları geri açmağa ehtiyac duymur. Bu ümumi yanaşmadır. Reallıqda istifadəçi parol daxil etdikdə sistem onu ​​şifrələyir və parol anbarında olanlarla müqayisə edir. Şifrələmə eyni vasitələrdən istifadə etməklə həyata keçirilir, buna görə də onların uyğun gəlməsini gözləmək olar (əgər düzgün parol daxil etsəniz; əlbəttə). BCrypt və SCrypt bu məqsəd üçün uyğundur. Hər ikisi çox vaxt aparan hesablama baxımından mürəkkəb alqoritmləri olan birtərəfli funksiyalardır (kriptoqrafik hashlər). Məhz bu sizə lazım olan şeydir, çünki onu baş-başa deşifrə etmək əbədi vaxt aparacaq. Məsələn, Spring Security bir sıra alqoritmləri dəstəkləyir. SCryptPasswordEncoderSiz də istifadə edə bilərsiniz BCryptPasswordEncoder. İndi güclü şifrələmə alqoritmi gələn il zəif ola bilər. Nəticədə belə qənaətə gəlirik ki, istifadə olunan alqoritmləri yoxlamaq və kitabxanaları alqoritmlərlə yeniləmək lazımdır.

Çıxış əvəzinə

Bu gün biz təhlükəsizlik haqqında danışdıq və təbii ki, çox şey pərdə arxasında qaldı. Mən sizin üçün yeni bir dünyanın qapısını açdım: öz həyatını yaşayan bir dünya. Təhlükəsizliklə siyasətlə eynidir: sən siyasətlə məşğul olmasan, siyasət də səninlə məşğul olacaq. Ənənəvi olaraq Github hesabıma abunə olmağı təklif edirəm . Orada oxuduğum və işdə tətbiq etdiyim müxtəlif texnologiyalar üzrə işlərimi yerləşdirirəm.

faydalı bağlantılar

Bəli, saytda demək olar ki, bütün məqalələr ingilis dilində yazılıb. İstəsək də, istəməsək də, ingilis dili proqramçıların ünsiyyət qura biləcəyi dildir. Proqramlaşdırma ilə bağlı bütün ən yeni məqalələr, kitablar və jurnallar ingilis dilində yazılmışdır. Buna görə tövsiyələrə olan keçidlərim əsasən ingilis dilindədir:
  1. Habr: Başlayanlar üçün SQL Injection
  2. Oracle: Java Təhlükəsizlik Resurs Mərkəzi
  3. Oracle: Java SE üçün Təhlükəsiz Kodlaşdırma Təlimatları
  4. Baeldung: Java Təhlükəsizliyinin Əsasları
  5. Orta: Java təhlükəsizliyinizi gücləndirmək üçün 10 məsləhət
  6. Snyk: 10 ən yaxşı java təhlükəsizlik təcrübəsi
  7. JR: GitHub Təhlükəsizlik Laboratoriyasının elanı: bütün kodlarınızı birlikdə qorumaq
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION