我有一个连接到数据库的Java应用程序。
数据库的用户名和密码存储在一个属性文件。
什么是常见的做法,以避免明文存储密码属性文件中,同时仍可以让用户改变它的选项?
这里的主要动机是为了防止有人找过管理员的肩膀,看到密码,而管理员正在编辑的属性文件。
我读到这里 ,有在办法做到这一点在C#中建。
知道java的,我不希望找到一个内置的解决方案,但我想听听其他人在做什么。
如果我没有找到任何很好的选择,然后,我可能将其与将保持在代码中恒定的密码进行加密。 但是我讨厌,因为它觉得这是错做这种方式。
编辑2012年12月12日貌似没有魔法,我必须在代码或类似的东西存储密码。 最后,我们实现非常相似,在其中一个答案确实提到什么Jasypt东西。 所以我接受Jasypt答案,因为它是最接近的一个明确的答复。
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"...
可怜的芒折衷的解决办法是使用一个简单的多签名的方法。
对于实施例的DBA设置应用程序的数据库的密码到50个字符的随机串。 TAKqWskc4ncvKaJTyDcgAHq82X7tX6GfK2fc386bmNw3muknjU
他或她对应用程序开发人员给予一半的密码谁再硬编码成Java的二进制文件。
私人字符串PASS1 = “TAKqWskc4ncvKaJTyDcgAHq82”
密码的另一半作为命令行参数来传递。 数据库管理员提供了PASS2的系统支持或管理的人无论谁进入它的应用程序启动时间或将其放入自动应用程序启动脚本。
Java的罐子/myapplication.jar -pass2 X7tX6GfK2fc386bmNw3muknjU
当应用程序启动时,它使用PASS1 + PASS2并连接到数据库。
该解决方案具有了挫折提到的许多优点。
您可以放心地把在命令行参数一半的密码,阅读它不会帮助你很多,除非你是谁拥有密码的另一半开发商。
DBA还仍然可以更改密码下半年和开发人员不需要不得不重新部署应用程序。
源代码也可以是半公众阅读它,密码不会给你的应用程序访问。
您可以通过IP地址添加限制范围内的数据库将接受来自连接的进一步改善这种情况。
怎么样提供自定义的N-因素认证机制?
结合之前可用的方法,让我们假设,我们可以执行以下操作:
1)在Java程序中的硬编码
2)在属性文件存储
3)向用户从命令行键入密码
4)向用户从表单中输入密码
5)向用户加载从命令行或形式的密码文件
6)提供通过网络的密码
7)许多替代品(如绘制一个秘密,指纹识别,IP专用,唧唧歪歪)
第一种选择:我们可以做的事情通过使用混淆攻击者更加复杂,但这不认为是一个很好的对策。 一个好的编码器可以很容易地理解它是如何工作的,如果他/她可以访问该文件。 我们甚至可以导出每个用户的二进制文件(或只是混淆的部分或关键部分),因此攻击者必须能够访问该用户特定的文件,而不是其他发行版。 同样,我们应该找到一种方法来更改密码,例如通过重新编译或使用反射来的即时变化类的行为。
第二个选项:我们可以存储在一个加密格式的属性文件的密码,所以它不是从攻击者直接可见的(就像jasypt一样)。 如果我们需要一个密码管理我们需要一个主密码也再次应保存在某个地方 - 一个.class文件中,密钥库,内核,另一个文件中,甚至在内存中 - 都有自己的优点和缺点。
但是,现在的用户只会编辑密码更改的属性文件。
第三选项:从命令行例如运行时,键入密码java -jar /myprogram.jar -p sdflhjkiweHIUHIU8976hyd
。
这并不需要存储密码,并会留在内存中。 然而, history
的命令和操作系统日志,可能是你最大的敌人在这里。 要更改即时密码,您将需要实现一些方法(如监听控制台输入,RMI,插座,REST唧唧歪歪),但密码将永远留在了记忆。
人们甚至可以暂时将其解密仅在需要时 - >然后删除解密,但始终保持加密的口令在内存中。 不幸的是,上述方法不增加防止未经授权的内存访问的安全性,因为谁实现了这个人,可能有机会获得算法,盐和正在使用的任何其他秘密。
第四选择:从提供自定义窗体,而不是在命令行中输入密码。 这将规避记录暴露的问题。
5日选项:提供文件作为在另一个媒体先前存储的密码- >然后硬删除文件。 这将再次规避记录暴露的问题,再加上没有打字需要,可能是肩窥被盗。 当需要改变,提供其他文件,然后再删除。
第六选项:再次避免肩窥,可以实现RMI方法调用,以提供密码(通过加密信道)从另一装置,例如经由移动电话。 但是,现在需要保护您的网络渠道,并获得了其他设备。
我会选择上述方法的组合,以实现最大的安全性,以便人们必须进入.class文件,属性文件,日志,网络信道,肩窥,中间人,其他文件唧唧歪歪。 这可以使用所有sub_passwords之间的异或运算,产生实际的密码很容易地实现。
我们不能被未经授权的内存访问,虽然保护,这只能通过使用一些限制存取硬件(如智能卡,硬件安全模块,SGX),这里的一切都算入其中,没有任何人,即使是合法的拥有者是能够访问解密密钥或算法。 同样,一个能够窃取这个硬件也有报道侧信道攻击 ,可以帮助攻击者在密钥提取并在某些情况下,你必须相信另一方(例如,与新交所信任的英特尔)。 当然,情况可能会恶化,当安全的飞地克隆(去组装)将是可能的,但我想这将需要数年才能成为现实。
另外,可以考虑在全键在不同的服务器之间拆分密钥共享解决方案。 然而,在重建,完整的密钥可能被盗。 要缓解上述问题的唯一方法是通过安全多方计算 。
我们要始终牢记,无论输入法,我们需要确保我们不从网络嗅探易受攻击(MITM攻击)和/或按键记录器。
其实,这是一个重复的密码加密的配置文件? 。
我迄今发现的最好的解决办法是在这个answert: https://stackoverflow.com/a/1133815/1549977
优点:密码保存AA字符数组,而不是作为一个字符串。 它仍然不是很好,但比什么都好。