73

我有一个连接到数据库的 java 应用程序。
数据库的用户名和密码存储在属性文件中。
避免在属性文件中以明文形式存储密码同时仍保留让用户更改密码的选项的常见做法是什么?
这里的主要动机是防止有人在管理员编辑属性文件时越过管理员的肩膀看到密码。我在这里
读到有一种内置的方法可以在 C# 中执行此操作。 了解java,我不希望找到一个内置的解决方案,但我想听听其他人在做什么。

如果我没有找到任何好的选择,那么我可能会使用将保存在代码中的恒定密码对其进行加密。但我不想这样做,因为感觉不对。

编辑 2012 年 12 月 12 日 看起来没有魔法,我必须将密码存储在代码或类似的东西中。最后,我们实现了与答案之一中提到的 Jasypt 非常相似的东西。所以我接受 Jasypt 的答案,因为它是最接近明确答案的东西。

4

4 回答 4

55

在此处输入图像描述

Jasypt 提供org.jasypt.properties.EncryptableProperties类用于加载、管理和透明解密 .properties 文件中的加密值,允许在同一文件中混合加密和未加密值。

http://www.jasypt.org/encrypting-configuration.html

通过使用 org.jasypt.properties.EncryptableProperties 对象,应用程序将能够正确读取和使用 .properties 文件,如下所示:

datasource.driver=com.mysql.jdbc.Driver 
datasource.url=jdbc:mysql://localhost/reportsdb 
datasource.username=reportsUser 
datasource.password=ENC(G6N718UuyPE5bHyWKyuLQSm02auQPUtm) 

请注意,数据库密码是加密的(事实上,任何其他属性也可以加密,无论是否与数据库配置有关)。

我们如何读取这个值?像这样:

/*
* First, create (or ask some other component for) the adequate encryptor for   
* decrypting the values in our .properties file.   
*/  
StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();     
encryptor.setPassword("jasypt"); // could be got from web, env variable...    
/*   
* Create our EncryptableProperties object and load it the usual way.   
*/  
Properties props = new EncryptableProperties(encryptor);  
props.load(new FileInputStream("/path/to/my/configuration.properties"));

/*   
* To get a non-encrypted value, we just get it with getProperty...   
*/  
String datasourceUsername = props.getProperty("datasource.username");

/*   
* ...and to get an encrypted value, we do exactly the same. Decryption will   
* be transparently performed behind the scenes.   
*/ 
String datasourcePassword = props.getProperty("datasource.password");

 // From now on, datasourcePassword equals "reports_passwd"...
于 2012-04-25T00:10:58.727 回答
13

穷人妥协的解决方案是使用简单的多签名方法。

例如,DBA 将应用程序数据库密码设置为 50 个字符的随机字符串。 TAKqWskc4ncvKaJTyDcgAHq82X7tX6GfK2fc386bmNw3muknjU

他或她将密码的一半提供给应用程序开发人员,然后他们将其硬编码到 java 二进制文件中。

私人字符串 pass1 = "TAKqWskc4ncvKaJTyDcgAHq82"

密码的另一半作为命令行参数传递。DBA 将 pass2 提供给系统支持人员或管理员,他们要么输入应用程序启动时间,要么将其放入自动应用程序启动脚本中。

java -jar /myapplication.jar -pass2 X7tX6GfK2fc386bmNw3muknjU

当应用程序启动时,它使用 pass1 + pass2 并连接到数据库。

该解决方案具有许多优点,没有提到的缺点。

您可以安全地将一半密码放在命令行参数中,因为除非您是拥有另一半密码的开发人员,否则阅读它不会对您有太大帮助。

DBA 仍然可以更改密码的后半部分,开发人员无需重新部署应用程序。

源代码也可以是半公开的,因为阅读它并且密码不会让您访问应用程序。

您可以通过对数据库接受连接的 IP 地址范围添加限制来进一步改善这种情况。

于 2014-10-22T06:53:34.820 回答
10

提供自定义 N 因子身份验证机制怎么样?

在组合可用方法之前,假设我们可以执行以下操作:

1) Java 程序内部的硬代码

2) 存储在 .properties 文件中

3)要求用户从命令行输入密码

4) 要求用户从表单中输入密码

5) 要求用户从命令行或表单加载密码文件

6) 通过网络提供密码

7)许多替代品(例如Draw A Secret、Fingerprint、IP-specific、bla bla bla)

第一种选择:我们可以通过使用混淆使攻击者的事情变得更复杂,但这不是一个好的对策。如果他/她可以访问文件,一个好的编码人员可以很容易地理解它是如何工作的。我们甚至可以导出每个用户的二进制文件(或者只是混淆部分或密钥部分),因此攻击者必须有权访问这个用户特定的文件,而不是另一个发行版。同样,我们应该找到一种更改密码的方法,例如通过重新编译或使用反射来即时更改类行为。

第二种选择:我们可以将密码以加密格式存储在 .properties 文件中,因此攻击者无法直接看到它(就像jasypt一样)。如果我们需要一个密码管理器,我们也需要一个主密码,它应该被存储在某个地方——一个 .class 文件、密钥库、内核、另一个文件甚至内存中——它们各有利弊。
但是,现在用户只需编辑 .properties 文件即可更改密码。

第三个选项:从命令行运行时输入密码,例如java -jar /myprogram.jar -p sdflhjkiweHIUHIU8976hyd

这不需要存储密码并将保留在内存中。但是,history命令和操作系统日志可能是您最大的敌人。要即时更改密码,您需要实现一些方法(例如监听控制台输入、RMI、套接字、REST bla bla bla),但密码将始终保留在内存中。

甚至可以仅在需要时对其进行临时解密->然后删除解密的内容,但始终将加密的密码保存在内存中。不幸的是,上述方法并没有增加针对未经授权的内存访问的安全性,因为实现这一点的人可能会访问算法、盐和任何其他正在使用的秘密。

第四个选项:从自定义表单而不是命令行提供密码。这将规避记录暴露的问题。

第 5 个选项:提供一个文件作为先前存储在另一个介质上的密码 -> 然后硬删除文件。这将再次规避记录暴露的问题,而且不需要打字,这可能会被偷走。当需要更改时,提供另一个文件,然后再次删除。

第 6 种选择:同样为了避免翻墙,可以实现 RMI 方法调用,以从另一设备(例如通过手机)提供密码(通过加密通道)。但是,您现在需要保护您的网络通道并访问其他设备。

我会选择上述方法的组合以实现最大的安全性,因此必须访问 .class 文件、属性文件、日志、网络通道、肩冲浪、中间人、其他文件 bla bla bla。这可以很容易地使用所有 sub_passwords 之间的 XOR 操作来生成实际密码来实现。

但是,我们无法保护我们免受未经授权的内存访问,这只能通过使用一些访问受限的硬件(例如智能卡、HSM、SGX)来实现,在这些硬件中,一切都被计算在内,没有任何人,甚至是合法的所有者能够访问解密密钥或算法。同样,人们也可以窃取此硬件,据报道,侧信道攻击可能有助于攻击者提取密钥,并且在某些情况下您需要信任另一方(例如,使用 SGX,您信任英特尔)。当然,当安全飞地克隆(拆卸)成为可能时,情况可能会恶化,但我想这需要几年时间才能实现。

此外,可以考虑一种密钥共享解决方案,其中完整密钥在不同服务器之间拆分。但是,在重建时,完整的密钥可能会被盗。缓解上述问题的唯一方法是通过安全多方计算

我们应该始终牢记,无论使用哪种输入法,我们都需要确保我们不会受到网络嗅探(MITM 攻击)和/或键盘记录器的攻击。

于 2015-12-21T12:28:53.797 回答
0

实际上,这是配置文件中加密密码的副本?.

到目前为止我发现的最佳解决方案是在这个答案中:https ://stackoverflow.com/a/1133815/1549977

优点:密码保存为 char 数组,而不是字符串。它仍然不好,但比其他任何东西都好。

于 2016-06-10T09:37:18.690 回答