保护属性文件中的密码
我有一个连接到数据库的Java应用程序。
数据库的用户名和密码存储在属性文件中。
避免将属性文件中的密码以明文forms存储,同时仍然保留允许用户更改密码的选项的常用做法是什么?
这里的主要动机是防止有人在pipe理员编辑属性文件时查看pipe理员的肩膀并看到密码。
我在这里读到,有一个build立在C#中的方式。
了解Java,我不期望find一个内置的解决scheme,但我想听听别人在做什么。
如果我没有find任何好的select,那么我可能会用一个常量密码进行encryption,这个密码将保存在代码中。 但我讨厌这样做,因为感觉不对。
编辑2012年12月12日看起来像没有魔法,我必须将密码存储在代码或类似的东西。 最后,我们实现了一个与Jasypt非常相似的东西,就是其中一个答案中提到的Jasypt。 所以我接受了Jasypt的答案,因为它是最接近确切答案的东西。
Jasypt提供了org.jasypt.properties.EncryptableProperties类,用于加载,pipe理和透明地解密.properties文件中的encryption值,允许在同一个文件中混合encryption值和非encryption值。
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)
请注意,数据库密码是encryption的(事实上,任何其他属性也可以encryption,无论是否与数据库configuration有关)。
我们如何读取这个值? 喜欢这个:
/* * 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"...
穷人妥协解决scheme是使用一个简单的多签名方法。
例如,DBA将应用程序数据库密码设置为50个字符的随机string。 TAKqWskc4ncvKaJTyDcgAHq82X7tX6GfK2fc386bmNw3muknjU
他或她将密码的一半给应用程序开发人员,然后将其硬编码到java二进制文件中。
私人stringpass1 =“TAKqWskc4ncvKaJTyDcgAHq82”
另一半的密码作为命令行parameter passing。 DBA将pass2发给系统支持人员或pipe理员,或者将其input到应用程序启动时间或将其放入自动应用程序启动脚本中。
java -jar /myapplication.jar -pass2 X7tX6GfK2fc386bmNw3muknjU
当应用程序启动时,它使用pass1 + pass2并连接到数据库。
这个解决scheme有很多优点,没有提到的缺点。
你可以安全地把一半的密码放在一个命令行参数中,因为阅读它不会帮助你,除非你是拥有另一半密码的开发者。
DBA还可以更改密码的后半部分,开发人员不需要重新部署应用程序。
源代码在读取时也可以是半公开的,密码不会给你应用程序访问权限。
您可以通过在数据库将接受连接的IP地址范围上添加限制来进一步改善情况。
那么提供一个自定义的N-因素authentication机制呢?
在结合可用的方法之前,让我们假设我们可以执行以下操作:
1)Java程序内部的硬编码
2)存储在.properties文件中
3)要求用户从命令行input密码
4)要求用户从表单中input密码
5)要求用户从命令行或表单加载密码文件
6)通过networking提供密码
7)许多select(例如,画一个秘密,指纹,知识产权,Bla bla bla)
第一种select:我们可以通过使用混淆来使攻击者变得更加复杂,但这不是一个好的对策。 一个好的编码器可以很容易地理解它如何工作,如果他/她可以访问该文件。 我们甚至可以导出每个用户的二进制文件(或只是模糊处理部分或关键部分),因此攻击者必须能够访问这个用户特定的文件,而不是另一个发行版。 再次,我们应该find一种方法来更改密码,例如通过重新编译或使用reflection来实时更改类的行为。
第二种select:我们可以将encryption格式的密码存储在.properties文件中,所以它不能直接从攻击者看到(就像jasypt一样)。 如果我们需要一个密码pipe理器,我们还需要一个主密码,这个密码也应该存储在.class文件,密钥库,内核,另一个文件甚至是内存中 – 都有其优点和缺点。
但是,现在用户只需编辑.properties文件来更改密码。
第三个选项:从命令行运行时input密码,例如java -jar /myprogram.jar -p sdflhjkiweHIUHIU8976hyd
。
这不需要密码被存储,并将保持在内存中。 但是, history
命令和操作系统日志,可能是你最大的敌人。 要实时更改密码,您将需要实现一些方法(例如,监听控制台input,RMI,套接字,REST bla bla bla),但密码将始终保留在内存中。
甚至可以在需要的时候临时解密 – >然后删除解密的内容,但始终将encryption的密码保存在内存中。 不幸的是,上述方法不会增加未经授权的内存访问的安全性,因为实现该目的的人可能有权访问algorithm,盐和任何其他正在使用的秘密。
第四个选项:从自定义表单提供密码,而不是命令行。 这将规避logging曝光的问题。
第五选项:提供一个文件作为先前存储在另一个媒体上的密码 – >然后硬删除文件。 这将再次规避logging曝光的问题,再加上不需要打字就可以肩上冲浪被盗。 当需要更改时,请提供另一个文件,然后再次删除。
第6个选项:为了避免肩上冲浪,可以实现RMI方法调用,以便从另一个设备(例如通过移动电话)提供密码(通过encryption的信道)。 但是,您现在需要保护您的networking通道并访问其他设备。
我会select上述方法的组合,以实现最大的安全性,所以人们将不得不访问.class文件,属性文件,日志,networking频道,肩上冲浪,中间人,其他文件。 这可以通过使用所有的子密码之间的XOR操作来实现,以产生实际的密码。
我们无法保护未经授权的内存访问,但这只能通过使用一些访问受限的硬件(例如智能卡,HSM,SGX)来实现,一切都计算在内,没有任何人,甚至合法的所有者能够访问解密密钥或algorithm。 再一次,也可以窃取这个硬件,有报道说可能帮助攻击者进行关键提取的边信道攻击 ,在某些情况下,你需要信任另一方(例如你信任英特尔的SGX)。 当然,安全飞地克隆(解体)将是可能的,情况可能会恶化,但我想这需要几年时间才能实用。
另外,可以考虑一个密钥共享解决scheme,其中全部密钥在不同的服务器之间被分开。 然而,重build后,全钥匙可以被盗。 减轻上述问题的唯一方法是通过安全的多方计算 。
我们应该永远记住,不pipeinput法如何,我们都需要确保我们不会受到networking嗅探(MITM攻击)和/或密钥logging器的攻击。
其实这是在configuration文件中encryption密码的副本? 。
到目前为止我发现的最好的解决scheme是在这个答案: https ://stackoverflow.com/a/1133815/1549977
优点:密码保存为一个字符数组,而不是一个string。 这还不好,但比其他任何事情都好。