在整個技術生態系統中引起反響的一個重大事件是2018年推出的GDPR,即歐洲公民的通用數據保護法規。雖然我將會或不會影響英國公民,但它仍然有待觀察,它爲Java開發人員提供了一個積極的機會,可以對三個安全領域感興趣:
在其應用程序中查找個人身份信息(PII)或其他敏感數據。
正確使用加密技術,以正確保護此信息和安全系統。
應用自定義代碼,庫和JRE的有效補丁管理。
查找PII和敏感數據
Java開發人員可以通過靜態類型和清除API來定位PII。對於開發人員編寫的POJO的例子,標準化的方法命名通過大部分的社區可以揭示潛在的PII信息一樣 getAddress()
, getName()
或 getSomethingElseThatLooksLikePII()
。通過方法名稱,熟悉PII目標的開發人員可以輕鬆找到PII睡眠的興趣點,並識別潛在的泄漏。
Java API還提供了另一種識別PII熊洞穴的簡單方法。例如,大多數持久性由JDBC或ORM庫(如Hibernate)處理。通過觀察查詢或直接查看數據庫,開發人員可以識別流經這些接口的PII。標準化API(如JDBC和Hibernate)的存在使得基於儀器的工具可以輕鬆地找到PII,類似於免費的基於儀器的工具監控安全性或性能的方式。
正確使用密碼學
Java開發人員受益於Java Cryptographic Architecture,這是一套兼容的工具和庫,涵蓋了基本的加密方法。從JDK 9開始,大多數JRE都附帶了Unlimited Strength Cryptography。無限強度的加密強度和策略文件配置的限制一直是需要強加密的開發項目混淆的根源。Java開發人員提供了一個快速測試,您可以運行以瞭解是否正確配置了無限強度。
導入 javax。加密。密碼 ;
class TestCryptoLimitations {
public static void main(String [] args){
嘗試 {
系統。出。println(“Hello World!”);
int maxKeyLen = 密碼。getMaxAllowedKeyLength(“AES”);
系統。出。println(“最大 密鑰 長度 爲 ” + maxKeyLen);
} catch(例外 e){
系統。出。println(“悲傷的世界:(”);
}
}
}
接下來,您可能會在項目中遇到三個主要的加密用例:散列文件/憑證,對稱加密和非對稱加密。
哈希和消息摘要
散列通常用於生成文件校驗和或加密憑據。它是一種單向算法,從密鑰計算哈希值可以在多項式時間內完成,並且被認爲是有效的計算。相反的操作,找到產生給定散列的值,稱爲碰撞,效率不高且計算成本高。考慮生日***以O(2 ^(n / 2)時間爲例。單向散列函數的行爲使它們適合於憑證存儲或測試數據(例如,文件)篡改。即使是一個小的改變文件將顯着更改哈希值。
常見的哈希算法有:SHA-256,SHA-512或較舊的算法,如MD5和SHA-1,可以在jdk.certpath.disabledAlgorithms屬性下的jre / lib / security / java.security文件中列入黑名單。
在對憑證的祕密部分進行散列(例如,密碼)時,散列值應包括每用戶鹽的唯一值。鹽是加密隨機值,難以猜測,通常採用長串十六進制值或字節數組的形式。包含鹽可防止預計算***,***者只需在稱爲彩虹表的字典中查找預先計算的值。不需要Salting來散列非祕密信息,例如文件檢查。最好使用像PBKDF2這樣的密鑰派生函數而不是自己的憑證散列,我們將很快介紹。
計算給定文件的哈希值:
MessageDigest md = MessageDigest。getInstance(“SHA - 256 ”);
md。更新(fileinbytes);
final byte [] hashed = md。doFinal();
這可以使用基於密碼的密鑰推導(PBKDF2)來生成信息的散列,這些信息應該是祕密的並且更難以預先計算。
final String password = “12345” ;
final String salt = “[email protected]” ;
final int iterations = 32 ;
PBEKeySpec keySpec = 新 PBEKeySpec(密碼。toCharArray(),鹽。的getBytes(),次迭代,512);
SecretKeyFactory skf = SecretKeyFactory。getInstance(“PBKDF2WithHmacSHA256”);
byte [] hashed = skf。generateSecret(keySpec)。getEncoded();
final String encoded = Base64。getEncoder()。encodeToString(hashed);
系統。出。println(“編碼:” + 編碼);
對稱密碼
對稱密碼用於加密和解密信息。對稱密碼得名,因爲加密和解密操作使用相同的密鑰。對稱密碼術是密碼學的基礎,比非對稱密碼學更快。密鑰通常是長字符串或字節數組,在字典中不容易找到。
常見的對稱算法包括AES,Blowfish和DES。以下是對稱加密和解密的示例。
導入 javax。加密。密碼 ;
導入 javax。加密。規範。IvParameterSpec ;
導入 javax。加密。規範。SecretKeySpec ;
導入 java。安全。SecureRandom ;
導入 java。util。Base64 ;
public class CryptoAdvent {
public static String encrypt(byte [] key,byte [] initVector,String value)throws Exception {
IvParameterSpec iv = new IvParameterSpec(initVector);
SecretKeySpec skeySpec = new SecretKeySpec(key,“AES”);
密碼 密碼 = 密碼。getInstance(“AES / CBC / PKCS5PADDING”);
密碼。INIT(密碼。ENCRYPT_MODE,skeySpec,IV);
byte [] encrypted = cipher。doFinal(值。的getBytes(“UTF-8” ));
字符串 編碼 = Base64。getEncoder()。encodeToString(加密);
返回 編碼 ;
}
public static String decrypt(byte [] key,byte [] initVector,String encrypted)throws Exception {
IvParameterSpec iv = new IvParameterSpec(initVector);
SecretKeySpec skeySpec = new SecretKeySpec(key,“AES”);
密碼 密碼 = 密碼。getInstance(“AES / CBC / PKCS5PADDING”);
密碼。INIT(密碼。DECRYPT_MODE,skeySpec,IV);
byte [] original = cipher。doFinal(Base64的。getDecoder()。解碼(加密));
return new String(original);
}
private static String bytesToHex(byte [] bytes){
StringBuilder sb = new StringBuilder();
for(byte b:bytes){
SB。追加(字符串。格式(“%02X” ,b));
}
返回 某人。toString();
}
public static void main(String [] args){
嘗試 {
//注意:每次程序運行時都會生成一個新的Key和initVector。真實的
//實現你需要將密鑰和initVector存儲爲祕密
//以後解密。
//
SecureRandom sr = new SecureRandom();
byte [] key = new byte [ 16 ];
sr。nextBytes(key); // 128位密鑰
byte [] initVector = new byte [ 16 ];
sr。nextBytes(initVector); // 16字節IV
系統。出。println(“Random key =” + bytesToHex(key));
系統。出。println(“initVector =” + bytesToHex(initVector));
String payload = “這是Erik和Milton的文章的明文。” ;
系統。出。println(“Original text =” + payload);
String encrypted = encrypt(key,initVector,payload);
系統。出。println(“加密文本=” + 加密);
串 解密 = 解密(鍵,initVector,加密);
系統。出。println(“Decrypted text =” + decrypted);
字符串 結果 =已 解密。等於(有效載荷)? “有用!” :“事情不對。” ;
系統。出。println(結果);
} catch(Exception t){
t。printStackTrace();
}
}
}
一個示例輸出是:
隨機 鍵= E5 01 B6 AC 9 C A5 6 D 64 08 DE AB DD 83 9 C E0 87
initVector = AC 09 5 C B0 6 E 76 3 B E6 A4 2 B D7 4 C B3 4 B CE F8
原始 文本= 這 是 在 明文 從 埃裏克 和 米爾頓的文章。
加密 文本= / LQlJp7fR4Gkq5unWU4X + 5 qrje1WWKyCms + MPzcwsFf2eE + QHVr2RQDoJVfrSmoc / dM5ulrtk5z4z4evozprUQ ==
解密 文本= 這 是 在 明文 從 埃裏克 和 米爾頓的文章。
它的 作品!
不對稱密碼
大多數Internet加密(例如HTTPS)都是圍繞非對稱加密構建的。非對稱加密技術的優點在於它爲客戶端和服務器提供了一種安全地協商密鑰和密碼套件的方法,這些祕密密鑰和密碼套件後來用於使用通用的對稱加密技術來保護數據。非對稱加密利用一些新的類,如中 KeyPair
, PublicKey
, PrivateKey
,和 Certificate
。這些類中的每一個都設計爲可以共享公鑰以便通過不受信任的網絡訪問任何人,然後使用他們自己的私鑰加密消息。然後,公鑰的所有者可以使用他們自己的私鑰解密消息,使兩者能夠通話。
非對稱加密的最常見用途是與網站進行加密的HTTPS通信。在這種情況下,每個客戶端都有一個已知的證書頒發機構列表,用於建立身份並驗證每個網站的公鑰的所有者。
與瀏覽器不同,大多數JRE都有一個截斷的證書頒發機構列表,其中包含許多來自Digicert的不同證書,但不包含流行的證書頒發機構,如Amazon Trust(AWS)或SSL.com。因此,Java客戶端可能會因PKIX異常而無法對某些URL進行身份驗證。
發生這種情況時,開發人員不應只是禁用SSL身份驗證。這樣做可以簡單地確保應用程序通過安全通道發送信息,而無需知道此通道另一端的內容。
正確的機制是將根證書添加到lib / security / cacerts文件中:
keytool -importcert -keystore lib/security/cacerts -alias awstrust -file awstrust.cer
雖然將根證書添加到此根證書頒發機構存儲是合理的,但是耳機之類的東西不需要根證書,如果是,則這些耳機的私鑰應保持私密。
有效的補丁管理
開發人員需要考慮兩個方面進行修補:
保持與JRE的節奏
跟上庫漏洞
Oracle JRE和Amazon Corretto都按季度進行補丁。與Oracle JRE(其Java 8支持在2019年4月結束)不同,Amazon Corretto承諾在2023年之前按季度免費修補補丁 - 大約四年。
Java開發人員無法抵禦最近***Node社區的***類型,從而竊取了不同數量的比特幣。例如,在2014年,針對Maven Central進行了一次***,以修改字節碼,因爲它在jar文件中移動到網絡中。雖然響應很快就能啓用SSL,但大多數JAR文件仍然沒有通過jarsigner工具簽名,這使得檢測篡改變得更加困難。類似的***在別處發生。
當在第三方庫中發現漏洞時,在部署補丁之前,您的應用程序幾乎沒有防禦。這就是爲快速修補設計軟件應用程序,服務和基礎架構對於強大的安全性至關重要的原因。除了快速部署之外,測試通常是一個常見的障礙。大多數組織推遲修補,因爲他們沒有很大的信心推動修補程序不會破壞生產。這就是爲什麼投資高質量的單元測試案例非常重要的原因。
爲了監控第三方庫的安全狀態,OWASP Dependency Check或Contrast Community Edition等開發人員可以使用免費工具。
許多軟件購買者強制執行這種依賴性分析,稱爲軟件組合分析,部分原因是隻需查看庫就可以輕鬆檢測到。忽視此建議的開發人員可能會發現他們的應用程序取消部署,後續發票未付。
一般建議
開發人員應該關注他們擁有的數據類型以及他們如何保護這些數據。由於GDPR的監管環境,“保存所有數據”的默認業務方法可能成爲嚴重的商業責任。數據可能是新油,但油是易燃的,並且在處理加密數據時,不要將密鑰與加密數據一起存儲,因爲這會破壞目的。