我正在开发一个连接到Web服务的Java客户端应用程序。对于此Web服务,我需要一个身份验证密钥(密码/令牌/ ...)。 如何在操作系统中安全地存储此密码"默认"密钥库系统?
("默认"我的意思是操作系统提供的标准工具,例如在Mac上有一个" Keychain Access"应用程序,用于存储证书和密码。一些应用程序管理存储他们的密码在那里,每次需要密码时,操作系统本身都会提供一个请求权限的对话框。或者在Windows上有Data Protection API。)
到目前为止,我遇到了question about storing certificates和Javas KeyStore.class。并设法编写以下内容:
//Loading the OS default keystore
KeyStore ks = KeyStore.getInstance("KeychainStore", "Apple");
ks.load(null, null);
//Reading keys
Enumeration<String> aliases = ks.aliases();
while (aliases.hasMoreElements()) {
String alias = aliases.nextElement();
if (ks.isKeyEntry(alias)) {
Key key = ks.getKey(alias, "anything".toCharArray()); //this invokes the OS popup
if (key == null) {
System.err.println(alias + " could not be read");
} else {
System.out.println(alias + " (algorithm = " + key.getAlgorithm() + ", format = " + key.getFormat() + ")");
}
}
}
//Writing keys (does not work yet)
String secretExample = "my very secret secret";
SecretKey generatedSecret = SecretKeyFactory.getInstance("PBE").generateSecret(new PBEKeySpec(secretExample.toCharArray()));
ks.setKeyEntry("my.app.Secret", generatedSecret, null, null); //throws java.security.KeyStoreException: Key protection algorithm not found: java.security.KeyStoreException: Key is not a PrivateKey
ks.setKeyEntry("my.app.Secret", secretExample.getBytes(), null); //throws java.security.KeyStoreException: key is not encoded as EncryptedPrivateKeyInfo
有了这个,我已经可以阅读一些键,但无法写任何键。最后两行是我不可行的解决方案(每个都抛出一个不同的例外)。
我认为安全存储密码是一个非常普遍的问题。我想通过使用操作系统提供的选项来解决它。我怎么能这样做?
答案 0 :(得分:1)
JKS曾经是Java中的标准KeyStore格式(直到Java 8)。它使用非常弱的加密并且是有限的。例如。它无法存储SecretKey实例。 恕我直言,苹果特定的KeyStore或至少Java访问它有类似的限制。
如果您考虑创建独立于操作系统的KeyStore并使用便携式解决方案,您可以选择其他格式,例如PKCS12或JCEKS。详情见这里: http://www.pixelstech.net/article/1408345768-Different-types-of-keystore-in-Java----Overview 在这种情况下,您应该知道使用Java代码创建新的KeyStore非常棘手。最简单的方法是使用keytool(JDK附带的命令行工具)来创建初始KeyStore。然后,您可以轻松使用加载和存储方法来加载它并保存更改。 如果您设法让它使用特定于操作系统的KeyStore,您实际上不必创建它,因为它已经存在。
答案 1 :(得分:1)
java.security.KeyStore
来处理密码。它是加密密钥和证书的存储工具。虽然您可以尝试使用它来存储密码(因为它可以存储私钥),但是我建议您这样做,因为KeyStore的API很笨拙,而且并非针对您的用例而设计。
有Java Keyring库。它将密码存储在:
这里是使用方法:
public static void main(String[] args) throws Exception {
Keyring keyring = Keyring.create();
String serviceName = "test-app";
String accountName = "test-account";
keyring.setPassword(serviceName, accountName, "test-password");
String password = keyring.getPassword(serviceName, accountName);
System.out.println(password);
}
Gradle
implementation 'com.github.javakeyring:java-keyring:1.0.1'
行家
<dependency>
<groupId>com.github.javakeyring</groupId>
<artifactId>java-keyring</artifactId>
<version>1.0.1</version>
</dependency>
如果要支持GNOME以外的桌面环境,则可能必须提出自己的解决方案或搜索其他库,但这应该可以帮助您入门。