我有一个连接到数据库的java应用程序.
数据库的用户名和密码存储在属性文件中.
避免在属性文件中以明文形式存储密码的常见做法是什么,同时仍保留让用户更改密码的选项?
这里的主要动机是防止有人在管理员编辑属性文件时查看管理员的肩膀并看到密码.
我在这里读到,在C#中有一种内置的方法.
知道java,我不希望找到内置的解决方案,但我想听听其他人在做什么.
如果我找不到任何好的选择,那么我可能会使用将保存在代码中的常量密码对其进行加密.但是我不喜欢这样做,因为它感觉不对.
编辑2012年12月12日 看起来没有魔力,我必须将密码存储在代码或类似的东西中.最后,我们实现了与其中一个答案中提到的Jasypt非常类似的东西.所以我接受了Jasypt的答案,因为它是最接近确定答案的东西.
Mad*_*sen 50

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)
Run Code Online (Sandbox Code Playgroud)
请注意,数据库密码是加密的(事实上,任何其他属性也可以加密,无论是否与数据库配置相关).
我们如何读取这个值?像这样:
/*
* 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"...
Run Code Online (Sandbox Code Playgroud)
Abe*_*pan 11
穷人的妥协解决方案是使用简单的多签名方法.
例如,DBA将应用程序数据库密码设置为50个字符的随机字符串. TAKqWskc4ncvKaJTyDcgAHq82X7tX6GfK2fc386bmNw3muknjU
他或她将一半的密码提供给应用程序开发人员,然后将其硬编码到java二进制文件中.
private String pass1 ="TAKqWskc4ncvKaJTyDcgAHq82"
密码的另一半作为命令行参数传递.DBA为系统支持或管理员提供pass2,该系统支持或管理员将其输入应用程序启动时间或将其放入自动应用程序启动脚本中.
java -jar /myapplication.jar -pass2 X7tX6GfK2fc386bmNw3muknjU
当应用程序启动时,它使用pass1 + pass2并连接到数据库.
在提到的垮台时,这种解决方案具有许多优点.
您可以安全地将一半密码放在命令行参数中,因为阅读它不会对您有所帮助,除非您是具有另一半密码的开发人员.
DBA还可以更改密码的后半部分,开发人员无需重新部署应用程序.
源代码也可以半公开读取,密码不会给您应用程序访问权限.
您可以通过添加数据库将接受来自的IP地址范围的限制来进一步改善这种情况.
那么提供自定义N-Factor身份验证机制呢?
在组合可用方法之前,我们假设我们可以执行以下操作:
1)Java程序中的硬编码
2)存储在.properties文件中
3)要求用户从命令行输入密码
4)要求用户从表单中键入密码
5)要求用户从命令行或表单加载密码文件
6)通过网络提供密码
7)许多替代品(例如,绘制秘密,指纹,IP特定,bla bla bla)
第一种选择:我们可以通过混淆使攻击者的事情变得更复杂,但这不是一个好的对策.如果一个好的程序员可以访问该文件,它可以很容易地理解它是如何工作的.我们甚至可以导出每用户二进制文件(或只是混淆部分或密钥部分),因此攻击者必须能够访问此特定于用户的文件,而不是另一个发行版.同样,我们应该找到一种更改密码的方法,例如通过重新编译或使用反射来实现更改类行为.
第二个选项:我们可以将密码以加密格式存储在.properties文件中,因此攻击者无法直接看到它(就像jasypt一样).如果我们需要一个密码管理我们需要一个主密码也再次应保存在某个地方-一个.class文件中,密钥库,内核,另一个文件中,甚至在内存中-都有自己的优点和缺点.
但是,现在用户只需编辑.properties文件以进行密码更改.
第3个选项:从命令行运行时键入密码,例如java -jar /myprogram.jar -p sdflhjkiweHIUHIU8976hyd.
这不需要存储密码并将保留在内存中.但是,history命令和操作系统日志可能是您最大的敌人.要即时更改密码,您需要实现一些方法(例如,监听控制台输入,RMI,套接字,REST bla bla bla),但密码将始终保留在内存中.
甚至可以在需要时暂时解密它 - >然后删除解密的,但始终将加密的密码保存在内存中.遗憾的是,上述方法不会增加针对未经授权的内存访问的安全性,因为实现该方法的人可能会访问算法,盐和任何其他使用的秘密.
第四个选项:提供自定义表单的密码,而不是命令行.这将避免记录曝光的问题.
第五个选项:提供一个文件作为先前存储在另一个媒体上的密码 - >然后是硬删除文件.这将再次避免记录曝光的问题,而且不需要打字可能会被偷偷摸摸.如果需要更改,请提供另一个文件,然后再次删除.
第六种选择:再次避免肩膀冲浪,可以实现RMI方法调用,从另一个设备(例如通过移动电话)提供密码(通过加密信道).但是,您现在需要保护您的网络通道并访问其他设备.
我会选择上述方法的组合,以实现最大的安全性,以便人们必须进入.class文件,属性文件,日志,网络信道,肩窥,中间人,其他文件唧唧歪歪.这可以使用所有sub_passwords之间的XOR操作轻松实现,以生成实际密码.
我们无法防止未经授权的内存访问,这只能通过使用一些访问受限的硬件(例如智能卡,HSM,SGX)来实现,其中所有内容都计算在其中,没有任何人,甚至是合法的所有者能够访问解密密钥或算法.同样,人们也可以窃取这些硬件,据报道可能有助于攻击者进行密钥提取的侧通道攻击,在某些情况下,您需要信任另一方(例如,您信任英特尔的SGX).当然,当安全飞地克隆(拆卸)成为可能时,情况可能会恶化,但我想这需要几年时间才能实用.
此外,可以考虑一种密钥共享解决方案,其中完整密钥在不同服务器之间分配.但是,重建后,全密钥可能被盗.减轻上述问题的唯一方法是通过安全的多方计算.
我们应该始终牢记,无论输入方法如何,我们都需要确保我们不会受到网络嗅探(MITM攻击)和/或密钥记录器的攻击.
| 归档时间: |
|
| 查看次数: |
103905 次 |
| 最近记录: |