在configuration文件中encryption密码?
我有一个程序从configuration文件中读取服务器信息,并希望encryption该configuration中可以被我的程序读取并解密的密码。
质量要求:
- encryption明文密码以存储在文件中
- 解密从我的程序中读入的encryption密码
任何关于如何去做这件事的reccomendations? 我正在考虑编写自己的algorithm,但我觉得这将是非常不安全的。
一个简单的方法是在Java中使用基于密码的encryption。 这使您可以使用密码来encryption和解密文本。
这基本上意味着使用algorithm"AES/CBC/PKCS5Padding"
初始化javax.crypto.Cipher
,并使用"PBKDF2WithHmacSHA512"
algorithm从javax.crypto.SecretKeyFactory
获取密钥。
这是一个代码示例(更新以取代不太安全的基于MD5的变体):
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(System.getProperty("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); } }
还有一个问题:你应该在哪里存储你用来encryption密码的密码? 您可以将其存储在源文件中并对其进行混淆,但是再次find它并不难。 或者,您可以在启动Java进程时将其作为系统属性( -DpropertyProtectionPassword=...
)。
如果您使用KeyStore,同样的问题仍然存在,它也受密码保护。 基本上,你需要有一个主密码的地方,这是很难保护。
是的,绝对不要写你自己的algorithm。 Java有很多encryptionAPI。
如果您正在安装的操作系统具有密钥库,则可以使用该密钥来存储您需要encryption和解密configuration或其他文件中的敏感数据的encryption密钥。
查看jasypt ,这是一个提供基本encryptionfunction的库,花费最less。
我认为最好的办法是确保你的configuration文件(包含你的密码) 只能被一个特定的用户帐户访问 。 例如,您可能只有一个特定于应用程序的用户appuser
,只有受信任的人才拥有密码(以及他们可以访问的密码)。
这样,没有烦人的密码开销,你仍然有一个安全的密码。
编辑: 我假设你是不是出口你的应用程序configuration以外的信任环境(我不知道会有什么意义,给出的问题)
那么要解决主密码的问题 – 最好的办法是不要在任何地方存储密码,应用程序应该自己encryption密码 – 只有它可以解密它们。 所以,如果我使用.config文件,我会执行以下, mySettings.config :
encryptTheseKeys =秘密密钥,anotherSecret
秘密密钥= unprotectedPasswordThatIputHere
anotherSecret = anotherPass
someKey = unprotectedSettingIdontCareAbout
所以我会阅读在encryptTheseKeys中提到的密钥,从上面应用Brodwalls示例,然后使用某种标记(可以说crypt :)将它们写回到文件中,让应用程序知道不要这样做再次,输出将如下所示:
encryptTheseKeys =秘密密钥,anotherSecret
secretKey = crypt:ii4jfj304fjhfj934fouh938
anotherSecret = crypt:jd48jofh48h
someKey = unprotectedSettingIdontCareAbout
只要确保将原件放在你自己的安全地方…
重要的一点,房间里的大象和所有这些,就是如果你的应用程序能够获得密码,那么一个能够访问这个盒子的黑客也可以得到它!
唯一的方法是,应用程序使用标准input要求控制台上的“主密码”,然后使用它来解密存储在文件中的密码。 当然,这完全使得应用程序在启动时无法随OS一起启动。
但是,即使有这样的烦恼,如果黑客设法获得root权限(甚至只是以运行应用程序的用户身份访问),他可以转储内存并在那里find密码。
要确保的是不让整个公司访问生产服务器(从而密码),并确保不可能破解这个盒子!
我用Java创build了一个简单的PropertyEncryptor。 它可以在构build过程中encryption你的属性文件。 然后你可以使用你的程序中的EncryptionHelper解密它。 你可以在这个位置find源代码http://devpinoy.org/blogs/jakelite/archive/2009/07/14/encrypting-passwords-in-java-property-files.aspx
尝试使用ESAPIsencryption方法。 它易于configuration,您也可以轻松地更改您的密钥。
http://owasp-esapi-java.googlecode.com/svn/trunk_doc/latest/org/owasp/esapi/Encryptor.html
您
1)encryption2)解密3)符号4)unsign 5)散列6)基于时间的签名和更多只有一个库。
根据您需要configuration文件的安全程度或应用程序的可靠性, http://activemq.apache.org/encrypted-passwords.html可能是一个很好的解决scheme。;
如果您不太担心密码被解密,使用bean来configuration密码密钥的configuration可能非常简单。 但是,如果您需要更多安全性,则可以使用该秘密设置环境variables,并在启动后将其删除。 有了这个,你不得不担心应用程序/服务器closures,而不是应用程序不能自动重新启动。
查看Jetty中可用于存储configuration文件中的密码(或散列)的内容,并考虑OBF编码是否对您有用。 然后在源文件中查看它是如何完成的。
http://www.eclipse.org/jetty/documentation/current/configuring-security-secure-passwords.html
如果使用java 8 ,则可以通过replace来避免使用内部Base64编码器和解码器
return new BASE64Encoder().encode(bytes);
同
return Base64.getEncoder().encodeToString(bytes);
和
return new BASE64Decoder().decodeBuffer(property);
同
return Base64.getDecoder().decode(property);
请注意,此解决scheme不保护您的数据,因为解密方法存储在同一个地方。 这只是让它更难打破。 主要是避免把它打印出来,误给大家看。
基于这里的评论,我写了一篇关于如何使用Talend数据集成在.propertiesconfiguration文件中encryption/解密和解密密码的教程 。
这是法语,但提出了两种方式使用Jasypt或Johannes的上述例子。 代码可能会让你感兴趣。