Java 在配置文件中加密密码?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1132567/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Encrypt Password in Configuration Files?
提问by Petey B
I have a program that reads server information from a configuration file and would like to encrypt the password in that configuration that can be read by my program and decrypted.
我有一个从配置文件读取服务器信息的程序,并希望在该配置中加密密码,该密码可由我的程序读取并解密。
Requirments:
要求:
- Encrypt plaintext password to be stored in the file
- Decrypt the encrypted password read in from the file from my program
- 加密明文密码存储在文件中
- 解密从我的程序文件中读取的加密密码
Any reccomendations on how i would go about doing this? I was thinking of writing my own algorithm but i feel it would be terribly insecure.
关于我将如何做这件事的任何建议?我正在考虑编写自己的算法,但我觉得它非常不安全。
采纳答案by Johannes Brodwall
A simple way of doing this is to use Password Based Encryption in Java. This allows you to encrypt and decrypt a text by using a password.
一种简单的方法是在 Java 中使用基于密码的加密。这允许您使用密码加密和解密文本。
This basically means initializing a javax.crypto.Cipher
with algorithm "AES/CBC/PKCS5Padding"
and getting a key from javax.crypto.SecretKeyFactory
with the "PBKDF2WithHmacSHA512"
algorithm.
这基本上意味着初始化javax.crypto.Cipher
与算法"AES/CBC/PKCS5Padding"
,并从获得的关键javax.crypto.SecretKeyFactory
与"PBKDF2WithHmacSHA512"
算法。
Here is a code example (updated to replace the less secure MD5-based variant):
这是一个代码示例(已更新以替换安全性较低的基于 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(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);
}
}
One problem remains: Where should you store the password that you use to encrypt the passwords? You can store it in the source file and obfuscate it, but it's not too hard to find it again. Alternatively, you can give it as a system property when you start the Java process (-DpropertyProtectionPassword=...
).
仍然存在一个问题:您应该将用于加密密码的密码存储在哪里?您可以将其存储在源文件中并对其进行混淆,但再次找到它并不难。或者,您可以在启动 Java 进程 ( -DpropertyProtectionPassword=...
)时将其作为系统属性提供。
The same issue remains if you use the KeyStore, which also is protected by a password. Basically, you will need to have one master password somewhere, and it's pretty hard to protect.
如果您使用同样受密码保护的 KeyStore,同样的问题仍然存在。基本上,您需要在某处拥有一个主密码,而且很难保护。
回答by JeeBee
Yes, definitely don't write your own algorithm. Java has lots of cryptography APIs.
是的,绝对不要编写自己的算法。Java 有很多加密 API。
If the OS you are installing upon has a keystore, then you could use that to store your crypto keys that you will need to encrypt and decrypt the sensitive data in your configuration or other files.
如果您正在安装的操作系统有一个密钥库,那么您可以使用它来存储您需要加密和解密配置或其他文件中的敏感数据的加密密钥。
回答by JeeBee
回答by oxbow_lakes
I think that the best approach is to ensure that your config file (containing your password) is only accessible to a specific user account. For example, you might have an application specific user appuser
to which only trusted people have the password (and to which they su
to).
我认为最好的方法是确保您的配置文件(包含您的密码)只能由特定用户帐户访问。例如,您可能有一个特定appuser
于应用程序的用户,只有受信任的人才能拥有(以及他们拥有的)密码su
。
That way, there's no annoying cryptography overhead and you still have a password which is secure.
这样,就没有烦人的加密开销,而且您仍然拥有一个安全的密码。
EDIT:I am assuming that you are not exporting your application configuration outside of a trusted environment (which I'm not sure would make any sense, given the question)
编辑:我假设您没有在受信任的环境之外导出您的应用程序配置(鉴于问题,我不确定这是否有意义)
回答by Thorbj?rn Ravn Andersen
See what is available in Jetty for storing password (or hashes) in configuration files, and consider if the OBF encoding might be useful for you. Then see in the source how it is done.
查看 Jetty 中可用于在配置文件中存储密码(或哈希)的内容,并考虑 OBF 编码是否对您有用。然后在源代码中查看它是如何完成的。
http://www.eclipse.org/jetty/documentation/current/configuring-security-secure-passwords.html
http://www.eclipse.org/jetty/documentation/current/configuring-security-secure-passwords.html
回答by user1007231
Well to solve the problems of master password - the best approach is not to store the password anywhere, the application should encrypt passwords for itself - so that only it can decrypt them. So if I was using a .config file I would do the following, mySettings.config:
那么解决主密码的问题 - 最好的方法是不要将密码存储在任何地方,应用程序应该为自己加密密码 - 只有它才能解密它们。因此,如果我使用的是 .config 文件,我会执行以下操作mySettings.config:
encryptTheseKeys=secretKey,anotherSecret
secretKey=unprotectedPasswordThatIputHere
anotherSecret=anotherPass
someKey=unprotectedSettingIdontCareAbout
encryptThisKeys=secretKey,anotherSecret
secretKey=unprotectedPasswordThatIputHere
另一个秘密=另一个通行证
someKey=unprotectedSettingIdontCareAbout
so I would read in the keys that are mentioned in the encryptTheseKeys, apply the Brodwalls example from above on them and write them back to the file with a marker of some sort (lets say crypt:) to let the application know not to do it again, the output would look like this:
所以我会读入 encryptThisKeys 中提到的密钥,将上面的 Brodwalls 示例应用到它们上,然后用某种标记(比如crypt:)将它们写回文件,让应用程序知道不要这样做同样,输出将如下所示:
encryptTheseKeys=secretKey,anotherSecret
secretKey=crypt:ii4jfj304fjhfj934fouh938
anotherSecret=crypt:jd48jofh48h
someKey=unprotectedSettingIdontCareAbout
encryptThisKeys=secretKey,anotherSecret
secretKey=地穴:ii4jfj304fjhfj934fouh938
另一个秘密 =地穴:jd48jofh48h
someKey=unprotectedSettingIdontCareAbout
Just make sure to keep the originals in your own secure place...
只要确保将原件保存在您自己的安全位置...
回答by Rohit Salecha
Try using ESAPIs Encryption methods. Its easy to configure and you can also easily change your keys.
尝试使用 ESAPIs 加密方法。它易于配置,您还可以轻松更改密钥。
http://owasp-esapi-java.googlecode.com/svn/trunk_doc/latest/org/owasp/esapi/Encryptor.html
http://owasp-esapi-java.googlecode.com/svn/trunk_doc/latest/org/owasp/esapi/Encryptor.html
You
你
1)encrypt 2)decrypt 3)sign 4)unsign 5)hashing 6)time based signatures and much more with just one library.
1) 加密 2) 解密 3) 签名 4) 取消签名 5) 散列 6) 基于时间的签名等等,只需一个库即可。
回答by stolsvik
The big point, and the elephant in the room and all that, is that if your application can get hold of the password, then a hacker with access to the box can get hold of it too!
重要的一点,以及房间里的大象等等,是如果您的应用程序可以获取密码,那么可以访问该框的黑客也可以获取它!
The only way somewhat around this, is that the application asks for the "master password" on the console using Standard Input, and then uses this to decrypt the passwords stored on file. Of course, this completely makes is impossible to have the application start up unattended along with the OS when it boots.
解决此问题的唯一方法是应用程序使用标准输入在控制台上要求“主密码”,然后使用它来解密存储在文件中的密码。当然,这完全使得应用程序在启动时与操作系统一起在无人看管的情况下启动是不可能的。
However, even with this level of annoyance, if a hacker manages to get root access (or even just access as the user running your application), he could dump the memory and find the password there.
然而,即使有这种烦恼,如果黑客设法获得 root 访问权限(或者甚至只是作为运行应用程序的用户访问),他可以转储内存并在那里找到密码。
The thing to ensure, is to not let the entire company have access to the production server (and thereby to the passwords), and make sure that it is impossible to crack this box!
要确保的是,不要让整个公司都可以访问生产服务器(从而访问密码),并确保不可能破解这个盒子!
回答by CPrescott
Depending on how secure you need the configuration files or how reliable your application is, http://activemq.apache.org/encrypted-passwords.htmlmay be a good solution for you.
根据您需要配置文件的安全程度或您的应用程序的可靠性,http://activemq.apache.org/encrypted-passwords.html可能是一个很好的解决方案。
If you are not too afraid of the password being decrypted and it can be really simple to configure using a bean to store the password key. However, if you need more security you can set an environment variable with the secret and remove it after launch. With this you have to worry about the application / server going down and not application not automatically relaunching.
如果您不太害怕密码被解密,那么使用 bean 来存储密码密钥的配置非常简单。但是,如果您需要更高的安全性,您可以使用密钥设置环境变量并在启动后将其删除。有了这个,您必须担心应用程序/服务器会关闭,而不是应用程序不会自动重新启动。
回答by Antonio Raposo
If you are using java 8the use of the internal Base64 encoder and decoder can be avoided by replacing
如果您使用的是java 8,则可以通过替换来避免使用内部 Base64 编码器和解码器
return new BASE64Encoder().encode(bytes);
return new BASE64Encoder().encode(bytes);
with
和
return Base64.getEncoder().encodeToString(bytes);
return Base64.getEncoder().encodeToString(bytes);
and
和
return new BASE64Decoder().decodeBuffer(property);
return new BASE64Decoder().decodeBuffer(property);
with
和
return Base64.getDecoder().decode(property);
return Base64.getDecoder().decode(property);
Note that this solution doesn't protect your data as the methods for decrypting are stored in the same place. It just makes it more difficult to break. Mainly it avoids to print it and show it to everybody by mistake.
请注意,此解决方案不会保护您的数据,因为解密方法存储在同一位置。它只会让打破变得更加困难。主要是避免打印出来误给大家看。