我有一个连接数据库的java应用程序
数据库的用户名和密码存储在属性文件中
避免在属性文件中以明文形式存储密码,同时仍保留让用户更改密码的常用做法是什么?
这里的主要动机是防止有人在管理员编辑属性文件时查看管理员的肩膀并看到密码
我读到here有一种内置的方法可以在C#中完成它
知道java,我不希望找到一个内置的解决方案,但我想听听其他人在做什么
如果我找不到任何好的选择,那么我可能会使用将保存在代码中的常量密码对其进行加密。但是我不喜欢这样做,因为它感觉不对。
编辑2012年12月12日 看起来没有魔力,我必须将密码存储在代码或类似的东西中。 最后,我们实现了与其中一个答案中提到的Jasypt非常类似的东西。 所以我接受了Jasypt的答案,因为它是最接近明确答案的答案。
答案 0 :(得分:46)
Jasypt提供org.jasypt.properties.EncryptableProperties类,用于加载,管理和透明地解密.properties文件中的加密值,允许在同一文件中混合使用加密值和未加密值。 < / p>
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"...
答案 1 :(得分:10)
穷人的妥协解决方案是使用简单的多签名方法。
例如,DBA将应用程序数据库密码设置为50个字符的随机字符串。 的 TAKqWskc4ncvKaJTyDcgAHq82X7tX6GfK2fc386bmNw3muknjU 强>
他或她将一半的密码提供给应用程序开发人员,然后将其硬编码到java二进制文件中。
私有字符串pass1 =&#34; TAKqWskc4ncvKaJTyDcgAHq82&#34;
另一半密码作为命令行参数传递。 DBA将pass2提供给系统支持或管理员,他们将应用程序启动时间输入或将其放入自动应用程序启动脚本中。
java -jar /myapplication.jar -pass2 X7tX6GfK2fc386bmNw3muknjU
当应用程序启动时,它使用pass1 + pass2并连接到数据库。
这种解决方案在提到的垮台方面有很多优点。
您可以安全地将一半密码放在命令行参数中,因为阅读它不会对您有所帮助,除非您是拥有另一半密码的开发人员。
DBA仍然可以更改密码的后半部分,开发人员无需重新部署应用程序。
源代码也可以半公开读取,密码不会给您应用程序访问权限。
您可以通过添加数据库将接受来自的IP地址范围的限制来进一步改善这种情况。
答案 2 :(得分:9)
如何提供自定义N因素身份验证机制?
在组合可用方法之前,我们假设我们可以执行以下操作:
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),但密码将始终保留在内存中。
甚至可以在需要时暂时解密它 - &gt;然后删除解密的,但始终将加密的密码保存在内存中。不幸的是,上述方法并没有增加安全性来防止未经授权的内存访问,因为实现这一目标的人可能会访问算法,盐和任何其他秘密。
第四个选项:提供自定义表单的密码,而不是命令行。这将避免记录曝光的问题。
第五个选项:提供一个文件作为先前存储在另一个媒体上的密码 - &gt;然后硬删除文件。这将再次避免记录曝光的问题,而且不需要打字,可能会被偷偷摸摸。如果需要更改,请提供另一个文件,然后再次删除。
第6个选项:再次避免肩膀冲浪,可以实施RMI方法调用,从其他设备(例如通过手机)提供密码(通过加密频道)。但是,您现在需要保护您的网络频道并访问其他设备。
我会选择上述方法的组合来实现最大的安全性,因此必须访问.class文件,属性文件,日志,网络通道,肩膀冲浪,中间人,其他文件bla bla bla。这可以通过所有sub_passwords之间的XOR操作轻松实现,以生成实际密码。
我们无法防止未经授权的内存访问,这只能通过使用一些访问受限的硬件(例如智能卡,HSM,SGX)来实现,其中所有内容都计算在其中,没有任何人,甚至是合法所有者能够访问解密密钥或算法。同样,人们也可以窃取这些硬件,据报道side-channel attacks可以帮助攻击者进行密钥提取,在某些情况下你需要信任另一方(例如你信任英特尔的SGX)。当然,当安全飞地克隆(拆卸)成为可能时,情况可能会恶化,但我想这需要几年时间才能实用。
此外,可以考虑一种密钥共享解决方案,其中完整密钥在不同服务器之间分配。但是,重建后,全密钥可能被盗。减轻上述问题的唯一方法是secure multiparty computation。
我们应该始终牢记,无论输入方法如何,我们都需要确保我们不会受到网络嗅探(MITM攻击)和/或密钥记录器的攻击。</ p>
答案 3 :(得分:0)
实际上,这是Encrypt Password in Configuration Files?的副本。
到目前为止,我找到的最佳解决方案是在这个问题中:https://stackoverflow.com/a/1133815/1549977
优点:密码保存为char数组,而不是字符串。它仍然不好,但比其他任何东西都好。