Cara sederhana untuk melakukan ini adalah dengan menggunakan Enkripsi Berbasis Kata Sandi di Java. Ini memungkinkan Anda untuk mengenkripsi dan mendekripsi teks dengan menggunakan kata sandi.
Ini pada dasarnya berarti menginisialisasi javax.crypto.Cipher
dengan algoritma "AES/CBC/PKCS5Padding"
dan mendapatkan kunci dari javax.crypto.SecretKeyFactory
dengan "PBKDF2WithHmacSHA512"
algoritma.
Ini adalah contoh kode (diperbarui untuk mengganti varian berbasis MD5 yang kurang aman):
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.AlgorithmParameters;
import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
public class ProtectedConfigFile {
public static void main(String[] args) throws Exception {
String password = System.getProperty("password");
if (password == null) {
throw new IllegalArgumentException("Run with -Dpassword=<password>");
}
// The salt (probably) can be stored along with the encrypted data
byte[] salt = new String("12345678").getBytes();
// Decreasing this speeds down startup time and can be useful during testing, but it also makes it easier for brute force attackers
int iterationCount = 40000;
// Other values give me java.security.InvalidKeyException: Illegal key size or default parameters
int keyLength = 128;
SecretKeySpec key = createSecretKey(password.toCharArray(),
salt, iterationCount, keyLength);
String originalPassword = "secret";
System.out.println("Original password: " + originalPassword);
String encryptedPassword = encrypt(originalPassword, key);
System.out.println("Encrypted password: " + encryptedPassword);
String decryptedPassword = decrypt(encryptedPassword, key);
System.out.println("Decrypted password: " + decryptedPassword);
}
private static SecretKeySpec createSecretKey(char[] password, byte[] salt, int iterationCount, int keyLength) throws NoSuchAlgorithmException, InvalidKeySpecException {
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
PBEKeySpec keySpec = new PBEKeySpec(password, salt, iterationCount, keyLength);
SecretKey keyTmp = keyFactory.generateSecret(keySpec);
return new SecretKeySpec(keyTmp.getEncoded(), "AES");
}
private static String encrypt(String property, SecretKeySpec key) throws GeneralSecurityException, UnsupportedEncodingException {
Cipher pbeCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
pbeCipher.init(Cipher.ENCRYPT_MODE, key);
AlgorithmParameters parameters = pbeCipher.getParameters();
IvParameterSpec ivParameterSpec = parameters.getParameterSpec(IvParameterSpec.class);
byte[] cryptoText = pbeCipher.doFinal(property.getBytes("UTF-8"));
byte[] iv = ivParameterSpec.getIV();
return base64Encode(iv) + ":" + base64Encode(cryptoText);
}
private static String base64Encode(byte[] bytes) {
return Base64.getEncoder().encodeToString(bytes);
}
private static String decrypt(String string, SecretKeySpec key) throws GeneralSecurityException, IOException {
String iv = string.split(":")[0];
String property = string.split(":")[1];
Cipher pbeCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
pbeCipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(base64Decode(iv)));
return new String(pbeCipher.doFinal(base64Decode(property)), "UTF-8");
}
private static byte[] base64Decode(String property) throws IOException {
return Base64.getDecoder().decode(property);
}
}
Masih ada satu masalah: Di mana Anda harus menyimpan kata sandi yang Anda gunakan untuk mengenkripsi kata sandi? Anda dapat menyimpannya di file sumber dan mengaburkannya, tetapi tidak terlalu sulit untuk menemukannya lagi. Atau, Anda bisa memberikannya sebagai properti sistem ketika Anda memulai proses Java ( -DpropertyProtectionPassword=...
).
Masalah yang sama tetap ada jika Anda menggunakan KeyStore, yang juga dilindungi oleh kata sandi. Pada dasarnya, Anda perlu memiliki satu kata sandi utama di suatu tempat, dan itu cukup sulit untuk dilindungi.
Ya, pasti jangan menulis algoritma Anda sendiri. Java memiliki banyak API kriptografi.
Jika OS yang Anda instal memiliki keystore, maka Anda dapat menggunakannya untuk menyimpan kunci kripto yang Anda perlukan untuk mengenkripsi dan mendekripsi data sensitif dalam konfigurasi Anda atau file lain.
sumber
Lihatlah jasypt , yang merupakan perpustakaan yang menawarkan kemampuan enkripsi dasar dengan upaya minimal.
sumber
Saya pikir pendekatan terbaik adalah memastikan bahwa file konfigurasi Anda (berisi kata sandi Anda) hanya dapat diakses oleh akun pengguna tertentu . Misalnya, Anda mungkin memiliki pengguna khusus aplikasi
appuser
yang hanya orang tepercaya yang memiliki kata sandi (dan yang merekasu
gunakan).Dengan begitu, tidak ada overhead kriptografi yang mengganggu dan Anda masih memiliki kata sandi yang aman.
EDIT: Saya berasumsi bahwa Anda tidak mengekspor konfigurasi aplikasi Anda di luar lingkungan tepercaya (yang saya tidak yakin akan masuk akal, mengingat pertanyaan)
sumber
Nah untuk menyelesaikan masalah kata sandi master - pendekatan terbaik adalah tidak menyimpan kata sandi di mana saja, aplikasi harus mengenkripsi kata sandi itu sendiri - sehingga hanya itu yang dapat mendekripsi kata sandi tersebut. Jadi jika saya menggunakan file .config saya akan melakukan yang berikut, mySettings.config :
jadi saya akan membaca di kunci yang disebutkan dalam mengenkripsi TheseKeys, menerapkan contoh Brodwalls dari atas pada mereka dan menulisnya kembali ke file dengan penanda semacam (misalkan crypt:) untuk membiarkan aplikasi tahu untuk tidak melakukannya lagi, hasilnya akan terlihat seperti ini:
Pastikan untuk menyimpan aslinya di tempat aman Anda sendiri ...
sumber
Intinya, dan gajah di ruangan itu dan semua itu, adalah bahwa jika aplikasi Anda dapat memperoleh kata sandi, maka seorang peretas yang memiliki akses ke kotak itu juga bisa mendapatkannya!
Satu-satunya cara untuk mengatasi hal ini, adalah bahwa aplikasi meminta "kata sandi utama" pada konsol menggunakan Input Standar, dan kemudian menggunakannya untuk mendekripsi kata sandi yang disimpan dalam file. Tentu saja, ini benar-benar membuat tidak mungkin untuk memiliki aplikasi memulai tanpa pengawasan bersama dengan OS saat boot.
Namun, bahkan dengan tingkat gangguan ini, jika seorang hacker berhasil mendapatkan akses root (atau bahkan hanya mengakses sebagai pengguna yang menjalankan aplikasi Anda), ia dapat membuang memori dan menemukan kata sandi di sana.
Hal yang perlu dipastikan, adalah untuk tidak membiarkan seluruh perusahaan memiliki akses ke server produksi (dan dengan demikian ke kata sandi), dan pastikan bahwa tidak mungkin untuk memecahkan kotak ini!
sumber
Coba gunakan metode Enkripsi ESAPI. Mudah dikonfigurasikan dan Anda juga dapat dengan mudah mengubah kunci Anda.
http://owasp-esapi-java.googlecode.com/svn/trunk_doc/latest/org/owasp/esapi/Encryptor.html
Kamu
1) mengenkripsi 2) mendekripsi 3) tanda 4) unsign 5) hashing 6) tanda tangan berdasarkan waktu dan banyak lagi hanya dengan satu perpustakaan.
sumber
Lihat apa yang tersedia di Jetty untuk menyimpan kata sandi (atau hash) dalam file konfigurasi, dan pertimbangkan apakah pengkodean OBF mungkin berguna bagi Anda. Kemudian lihat di sumbernya bagaimana hal itu dilakukan.
http://www.eclipse.org/jetty/documentation/current/configuring-security-secure-passwords.html
sumber
Bergantung pada seberapa aman Anda memerlukan file konfigurasi atau seberapa andal aplikasi Anda, http://activemq.apache.org/encrypted-passwords.html mungkin merupakan solusi yang baik untuk Anda.
Jika Anda tidak terlalu takut kata sandi didekripsi dan sangat mudah untuk mengkonfigurasi menggunakan kacang untuk menyimpan kunci kata sandi. Namun, jika Anda membutuhkan lebih banyak keamanan Anda dapat mengatur variabel lingkungan dengan rahasia dan menghapusnya setelah diluncurkan. Dengan ini Anda harus khawatir tentang aplikasi / server turun dan bukan aplikasi tidak secara otomatis meluncurkan kembali.
sumber
Jika Anda menggunakan java 8 penggunaan encoder dan decoder Base64 internal dapat dihindari dengan mengganti
return new BASE64Encoder().encode(bytes);
dengan
return Base64.getEncoder().encodeToString(bytes);
dan
return new BASE64Decoder().decodeBuffer(property);
dengan
return Base64.getDecoder().decode(property);
Perhatikan bahwa solusi ini tidak melindungi data Anda karena metode dekripsi disimpan di tempat yang sama. Itu hanya membuatnya lebih sulit untuk istirahat. Terutama itu menghindari untuk mencetaknya dan menunjukkannya kepada semua orang secara tidak sengaja.
sumber