CodeGym/Java Blogu/Rastgele/Java'da güvenlik: en iyi uygulamalar
John Squirrels
Seviye
San Francisco

Java'da güvenlik: en iyi uygulamalar

grupta yayınlandı
Sunucu uygulamalarında en önemli ölçütlerden biri güvenliktir. Bu, işlevsel olmayan bir gereksinim türüdür . Java'da güvenlik: en iyi uygulamalar - 1Güvenlik birçok bileşen içerir. Tabii ki, bilinen tüm güvenlik ilkelerini ve güvenlik önlemlerini tam olarak ele almak için birden fazla makale gerekir, bu nedenle en önemlileri üzerinde duracağız. Bu konuda bilgili bir kişi, ilgili tüm süreçleri kurabilir, yeni güvenlik açıkları oluşturmaktan kaçınabilir ve herhangi bir ekipte ihtiyaç duyulacaktır. Elbette bu uygulamaları takip ettiğiniz takdirde uygulamanızın %100 güvenli olacağını düşünmemelisiniz. HAYIR! Ama onlarla kesinlikle daha güvenli olacak. Hadi gidelim.

1. Java dili düzeyinde güvenlik sağlayın

Her şeyden önce, Java'da güvenlik, dilin yetenekleri düzeyinde başlar. Erişim değiştiricileri olmasaydı ne yapardık? Anarşiden başka bir şey olmazdı. Programlama dili, güvenli kod yazmamıza yardımcı olur ve ayrıca birçok örtük güvenlik özelliğini kullanır:
  1. Güçlü yazım. Java, statik olarak yazılan bir dildir. Bu, çalışma zamanında tiple ilgili hataları yakalamayı mümkün kılar.
  2. Erişim değiştiricileri. Bunlar, sınıflara, yöntemlere ve alanlara erişimi gerektiği gibi özelleştirmemize izin verir.
  3. Otomatik bellek yönetimi. Bunun için Java geliştiricileri, bizi her şeyi manuel olarak yapılandırmaktan kurtaran bir çöp toplayıcıya sahiptir. Evet, bazen sorunlar ortaya çıkar.
  4. Bayt kodu doğrulaması : Java, çalıştırılmadan önce çalışma zamanı tarafından kontrol edilen bayt kodunda derlenir.
Ek olarak, Oracle'ın güvenlik önerileri de vardır . Elbette kibirli bir dille yazılmamış ve okurken birkaç kez uyuyakalabilirsiniz ama buna değer. Özellikle Secure Coding Guidelines for Java SE başlıklı belge önemlidir. Güvenli kodun nasıl yazılacağı konusunda tavsiyeler sağlar. Bu belge çok miktarda son derece yararlı bilgi aktarmaktadır. İmkanınız varsa mutlaka okumalısınız. Bu malzemeye olan ilginizi artırmak için işte size birkaç ilginç ipucu:
  1. Güvenlik açısından hassas sınıfları seri hale getirmekten kaçının. Seri hale getirme, seri hale getirilmiş veriler bir yana, seri hale getirilmiş dosyadaki sınıf arayüzünü gösterir.
  2. Veriler için değiştirilebilir sınıflardan kaçınmaya çalışın. Bu değişmez sınıfların tüm avantajlarını sağlar (örn. iş parçacığı güvenliği). Değişken bir nesneniz varsa, beklenmedik davranışlara yol açabilir.
  3. Döndürülen değiştirilebilir nesnelerin kopyalarını oluşturun. Bir yöntem dahili değişken bir nesneye referans döndürürse, istemci kodu nesnenin dahili durumunu değiştirebilir.
  4. Ve benzeri…
Temel olarak, Java SE için Güvenli Kodlama Yönergeleri, Java kodunun doğru ve güvenli bir şekilde nasıl yazılacağına ilişkin ipuçları ve püf noktalarından oluşan bir koleksiyondur.

2. SQL enjeksiyon güvenlik açıklarını ortadan kaldırın

Bu, özel bir güvenlik açığı türüdür. Özeldir çünkü hem en ünlü hem de en yaygın güvenlik açıklarından biridir. Bilgisayar güvenliğiyle hiç ilgilenmediyseniz, bunu bilmeyeceksiniz. SQL enjeksiyonu nedir? Bu, beklenmeyen yerlerde ek SQL kodunun enjekte edilmesini içeren bir veritabanı saldırısıdır. Veritabanını sorgulamak için bir tür parametre kabul eden bir yöntemimiz olduğunu varsayalım. Örneğin, bir kullanıcı adı. Güvenlik açığı bulunan kod şuna benzer:
// This method retrieves from the database all users with a certain name
public List findByFirstName(String firstName) throws SQLException {
   // Connect to the database
   Connection connection = DriverManager.getConnection(DB_URL, USER, PASS);

   // Compose a SQL database query with our firstName
   String query = "SELECT * FROM USERS WHERE firstName = " + firstName;

   // Execute the query
   Statement statement = connection.createStatement();
   ResultSet result = statement.executeQuery(query);

   // Use mapToUsers to convert the ResultSet into a collection of users.
   return mapToUsers(result);
}

private List mapToUsers(ResultSet resultSet) {
   // Converts to a collection of users
}
Bu örnekte, ayrı bir satırda önceden bir SQL sorgusu hazırlanmıştır. Öyleyse sorun ne, değil mi? Belki de sorun, String.format kullanmanın daha iyi olacağıdır . HAYIR? Peki ya o zaman? Kendimizi bir testçinin yerine koyalım ve firstName değeri olarak neyin aktarılabileceğini düşünelim . Örneğin:
  1. Beklenen şeyi iletebiliriz - bir kullanıcı adı. Ardından veritabanı, bu ada sahip tüm kullanıcıları döndürür.
  2. Boş bir string geçirebiliriz. Ardından tüm kullanıcılar iade edilecektir.
  3. Ancak şunu da geçebiliriz: "'; DROP TABLE USERS;". Ve burada şimdi huuuuuuge sorunlarımız var. Bu sorgu veritabanından bir tabloyu silecektir. Tüm verilerle birlikte. HEPSİNİ.
Bunun yol açacağı sorunları hayal edebiliyor musunuz? Onun dışında ne istersen yazabilirsin. Tüm kullanıcıların adlarını değiştirebilirsiniz. Adreslerini silebilirsiniz. Sabotajın kapsamı çok büyük. Bunu önlemek için, hazır bir sorgunun enjeksiyonunu engellemeniz ve bunun yerine sorguyu parametrelerle oluşturmanız gerekir. Veritabanı sorguları oluşturmanın tek yolu bu olmalıdır. Bu güvenlik açığını bu şekilde ortadan kaldırabilirsiniz. Örneğin:
// This method retrieves from the database all users with a certain name
public List findByFirstName(String firstName) throws SQLException {
   // Connect to the database
   Connection connection = DriverManager.getConnection(DB_URL, USER, PASS);

   // Create a parameterized query.
   String query = "SELECT * FROM USERS WHERE firstName = ?";

   // Create a prepared statement with the parameterized query
   PreparedStatement statement = connection.prepareStatement(query);

   // Pass the parameter's value
   statement.setString(1, firstName);

   // Execute the query
   ResultSet result = statement.executeQuery(query);

   // Use mapToUsers to convert the ResultSet into a collection of users.
   return mapToUsers(result);
}

private List mapToUsers(ResultSet resultSet) {
   // Converts to a collection of users
}
Bu şekilde güvenlik açığı önlenir. Bu makalenin derinliklerine dalmak isteyenler için işte harika bir örnek . Bu güvenlik açığını ne zaman anladığınızı nasıl anlarsınız? Aşağıdaki çizgi romandaki şakayı anladıysanız, muhtemelen bu güvenlik açığının neyle ilgili olduğunu net bir şekilde anlamışsınızdır: DJava'da güvenlik: en iyi uygulamalar - 2

3. Bağımlılıkları tarayın ve güncel tutun

Bu ne anlama gelir? Bağımlılığın ne olduğunu bilmiyorsanız, açıklayacağım. Bağımlılık, başka birinin çözümünü yeniden kullanmak için otomatik derleme sistemleri (Maven, Gradle, Ant) kullanan bir projeye bağlanan kodlu bir JAR arşividir. Örneğin, çalışma zamanında bizim için alıcılar, ayarlayıcılar vb. üreten Project Lombok . Büyük uygulamaların çok sayıda bağımlılığı olabilir. Bazıları geçişlidir (yani, her bağımlılığın kendi bağımlılıkları olabilir vb.). Sonuç olarak, saldırganlar, düzenli olarak kullanıldıkları ve birçok istemcinin bunlar nedeniyle sorun yaşayabileceği için açık kaynak bağımlılıklarına giderek daha fazla dikkat ediyor. Bağımlılık ağacının tamamında bilinen bir güvenlik açığı olmadığından emin olmak önemlidir (evet, bir ağaca benziyor). Bunu yapmanın birkaç yolu var.

Bağımlılık izleme için Snyk kullanın

Snyk, tüm proje bağımlılıklarını kontrol eder ve bilinen güvenlik açıklarını işaretler. Snyk'e kayıt olabilir ve projelerinizi GitHub üzerinden içe aktarabilirsiniz. Java'da güvenlik: en iyi uygulamalar - 3Ayrıca, yukarıdaki resimden de görebileceğiniz gibi, daha yeni bir sürümde bir güvenlik açığı giderilirse, Snyk düzeltmeyi sunacak ve bir çekme isteği oluşturacaktır. Açık kaynaklı projeler için ücretsiz olarak kullanabilirsiniz. Projeler düzenli aralıklarla, örneğin haftada bir, ayda bir taranır. Kayıt oldum ve tüm genel depolarımı Snyk taramasına ekledim (zaten herkese açık oldukları için bunda tehlikeli bir şey yok). Snyk daha sonra tarama sonucunu gösterdi: Java'da güvenlik: en iyi uygulamalar - 4Ve bir süre sonra Snyk-bot, bağımlılıkların güncellenmesi gereken projelerde birkaç çekme isteği hazırladı: Java'da güvenlik: en iyi uygulamalar - 5Ve ayrıca:Java'da güvenlik: en iyi uygulamalar - 6Bu, güvenlik açıklarını bulmak ve yeni sürümler için güncellemeleri izlemek için harika bir araçtır.

GitHub Güvenlik Laboratuvarı'nı kullanın

GitHub'da çalışan herkes yerleşik araçlarından yararlanabilir. Bu yaklaşım hakkında daha fazla bilgiyi GitHub Güvenlik Laboratuvarı Duyurusu başlıklı blog gönderilerinde okuyabilirsiniz . Bu araç elbette Snyk'ten daha basit ama kesinlikle ihmal etmemelisiniz. Dahası, bilinen güvenlik açıklarının sayısı yalnızca artacak, dolayısıyla hem Snyk hem de GitHub Security Lab genişlemeye ve gelişmeye devam edecek.

Sonatype DepShield'ı Etkinleştir

Depolarınızı depolamak için GitHub kullanıyorsanız, MarketPlace'teki uygulamalardan biri olan Sonatype DepShield'ı projelerinize ekleyebilirsiniz. Projeleri bağımlılıklar için taramak için de kullanılabilir. Ayrıca, bir şey bulursa, aşağıda gösterildiği gibi uygun bir açıklama ile bir GitHub Sorunu oluşturulur:Java'da güvenlik: en iyi uygulamalar - 7

4. Gizli verileri dikkatli kullanın

Alternatif olarak "hassas veriler" ifadesini kullanabiliriz. Bir müşterinin kişisel bilgilerinin, kredi kartı numaralarının ve diğer hassas bilgilerinin sızdırılması onarılamaz zararlara neden olabilir. Her şeyden önce, uygulamanızın tasarımına yakından bakın ve gerçekten buna veya bu verilere ihtiyacınız olup olmadığını belirleyin. Belki de sahip olduğunuz verilerin bir kısmına gerçekten ihtiyacınız yoktur - gelmemiş ve gelmesi muhtemel olmayan bir gelecek için eklenen veriler. Ek olarak, birçoğunuz yanlışlıkla bu tür verileri günlük kaydı yoluyla sızdırıyorsunuz. Hassas verilerin günlüklerinize girmesini önlemenin kolay bir yolu , etki alanı varlıklarının (Kullanıcı, Öğrenci, Öğretmen vb.) toString() yöntemlerini temizlemektir . Bu, yanlışlıkla gizli alanların çıktısını almanızı önleyecektir. ToString() öğesini oluşturmak için Lombok kullanıyorsanızyönteminde, toString() yönteminin çıktısında bir alanın kullanılmasını önlemek için @ToString.Exclude ek açıklamasını kullanabilirsiniz . Ayrıca dış dünyaya veri gönderirken çok dikkatli olun. Tüm kullanıcıların adlarını gösteren bir HTTP uç noktamız olduğunu varsayalım. Bir kullanıcının benzersiz dahili kimliğini göstermeye gerek yoktur. Neden? Çünkü bir saldırgan bunu kullanıcı hakkında daha hassas başka bilgiler elde etmek için kullanabilir. Örneğin, bir POJO'yu JSON'a seri hale getirmek/serisini kaldırmak için Jackson kullanıyorsanız , @JsonIgnore ve @JsonIgnoreProperties'i kullanabilirsiniz .belirli alanların seri hale getirilmesini/seri hale getirilmesini önlemek için ek açıklamalar. Genel olarak, farklı yerlerde farklı POJO sınıfları kullanmanız gerekir. Bu ne anlama gelir?
  1. Bir veritabanıyla çalışırken, bir tür POJO (varlık) kullanın.
  2. İş mantığıyla çalışırken, bir varlığı modele dönüştürün.
  3. Dış dünyayla çalışırken ve HTTP istekleri gönderirken farklı varlıklar (DTO'lar) kullanın.
Bu şekilde hangi alanların dışarıdan görünüp hangilerinin görünmeyeceğini net bir şekilde belirleyebilirsiniz.

Güçlü şifreleme ve karma algoritmalar kullanın

Müşterilerin gizli verileri güvenli bir şekilde saklanmalıdır. Bunu yapmak için şifreleme kullanmamız gerekiyor. Göreve bağlı olarak, hangi tür şifrelemenin kullanılacağına karar vermeniz gerekir. Ek olarak, daha güçlü şifreleme daha fazla zaman alır, bu nedenle, buna duyulan ihtiyacın, üzerinde harcanan zamanı ne kadar haklı çıkardığını tekrar düşünmeniz gerekir. Tabii ki, kendiniz bir şifreleme algoritması yazabilirsiniz. Ama bu gereksiz. Bu alanda mevcut çözümleri kullanabilirsiniz. Örneğin, 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>
Şifreleme ve şifre çözmeyi içeren bu örneği kullanarak ne yapacağımızı görelim:
private static void encryptDecryptExample() {
   AeadConfig.register();
   KeysetHandle handle = KeysetHandle.generateNew(AeadKeyTemplates.AES128_CTR_HMAC_SHA256);

   String plaintext = "Elvis lives!";
   String aad = "Buddy Holly";

   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));
}

şifreleri şifrelemek

Bu görev için asimetrik şifreleme kullanmak en güvenlisidir. Neden? Çünkü uygulamanın gerçekten şifreleri çözmesi gerekmiyor. Bu standart yaklaşımdır. Gerçekte, bir kullanıcı bir şifre girdiğinde, sistem onu ​​şifreler ve şifre deposunda bulunanlarla karşılaştırır. Aynı şifreleme işlemi yapılıyor yani doğru şifre girilirse eşleşmelerini bekleyebiliriz tabii ki :) Burada BCrypt ve SCrypt uygundur. Her ikisi de uzun zaman alan hesaplama açısından karmaşık algoritmalara sahip tek yönlü işlevlerdir (kriptografik karmalar). Bu tam olarak ihtiyacımız olan şey, çünkü doğrudan hesaplamalar sonsuza kadar sürecek (yani, uzun, çok uzun bir zaman). Spring Security, çok çeşitli algoritmaları destekler. SCryptPasswordEncoder ve BCryptPasswordEncoder'ı kullanabiliriz. Şu anda güçlü bir şifreleme algoritması olarak kabul edilen şey, gelecek yıl zayıf kabul edilebilir. Sonuç olarak, kullandığımız algoritmaları düzenli olarak kontrol etmemiz ve gerektiğinde şifreleme algoritmalarını içeren kitaplıkları güncellememiz gerektiği sonucuna varıyoruz.

Bir sonuç yerine

Bugün güvenlik hakkında konuştuk ve doğal olarak pek çok şey perde arkasında kaldı. Senin için yeni bir dünyanın kapısını araladım, kendine ait bir hayatı olan bir dünya. Güvenlik tıpkı siyaset gibidir: siz siyasetle meşgul olmazsanız, siyaset sizinle meşgul olur. Geleneksel olarak beni GitHub hesabında takip etmenizi öneririm . Orada, üzerinde çalıştığım ve işte uyguladığım çeşitli teknolojileri içeren kreasyonlarımı yayınlıyorum.

Kullanışlı bağlantılar

  1. Guru99: SQL Enjeksiyon Eğitimi
  2. Oracle: Java Güvenlik Kaynak Merkezi
  3. Oracle: Java SE için Güvenli Kodlama Yönergeleri
  4. Baeldung: Java Güvenliğinin Temelleri
  5. Orta: Java güvenliğinizi güçlendirmek için 10 ipucu
  6. Snyk: 10 Java güvenliği en iyi uygulamaları
  7. GitHub: GitHub Güvenlik Laboratuvarı Duyurusu: dünyanın kodunu birlikte güvence altına alıyoruz
Yorumlar
  • Popüler
  • Yeni
  • Eskimiş
Yorum bırakmak için giriş yapmalısınız
Bu sayfada henüz yorum yok