如何在操作系统中安全地存储密码"默认"密钥存储?

时间:2017-04-20 17:48:37

标签: java security

我正在开发一个连接到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

有了这个,我已经可以阅读一些键,但无法写任何键。最后两行是我不可行的解决方案(每个都抛出一个不同的例外)。

我认为安全存储密码是一个非常普遍的问题。我想通过使用操作系统提供的选项来解决它。我怎么能这样做?

  • 如何改进我的代码才能工作?
  • 如何改进我的代码以便在不同的操作系统下工作?
  • 是否有可以使用操作系统提供的选项存储数据的库?
  • 我还有其他选择吗?

2 个答案:

答案 0 :(得分:1)

  1. JKS曾经是Java中的标准KeyStore格式(直到Java 8)。它使用非常弱的加密并且是有限的。例如。它无法存储SecretKey实例。 恕我直言,苹果特定的KeyStore或至少Java访问它有类似的限制。

  2. 如果您考虑创建独立于操作系统的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很笨拙,而且并非针对您的用例而设计。

如何在Windows,Linux或macOS中存储密码

Java Keyring库。它将密码存储在:

  1. Keychain在macOS上
  2. Windows上的
  3. Credential Manager
  4. DBus Secret Service在GNOME上

这里是使用方法:

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以外的桌面环境,则可能必须提出自己的解决方案或搜索其他库,但这应该可以帮助您入门。