2012-04-24 152 views
53

我有一个连接到数据库的Java应用程序。
数据库的用户名和密码存储在属性文件中。
避免将属性文件中的密码以明文形式存储,同时仍保留允许用户更改密码的选项的常用做法是什么?
这里的主要动机是防止有人在管理员编辑属性文件时查看管理员的肩膀并查看密码。
我读了here,有一种内置的方法可以在C#中完成。
了解java,我不期望找到内置的解决方案,但我想听听其他人在做什么。
如果我没有找到任何好的选择,那么我可能会用一个将保存在代码中的常量密码进行加密。但我不想这样做,因为它感觉不对。保护属性文件中的密码

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

+3

如果程序能够读取它,那么你可以期望的最好的方式就是模糊,任何有权访问这些文件的人都可以。这并不是说你不能让它难以进入。 – lynks 2012-04-24 22:11:28

+0

使用代码中保存的常量密码对其进行加密,看起来像是一种合法的方式,只要查看管理员肩膀的人是主要威胁。 – ZeroOne 2012-04-24 22:20:46

+0

有多少人访问数据库?他们不需要核心数据库访问密码吗?你为什么要存储第二个/这个? – 2012-04-24 22:22:02

回答

40

enter image description here

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"... 
+12

那么,基本上,现在密码在程序中是硬编码的? – mazaneicha 2012-04-25 03:50:18

+8

您在示例中看到的“密码”用于执行值的加密/解密。在这个例子中,它是硬编码的,但它可以从任何地方检索(例如环境变量)。但是,您不希望以纯文本形式存储的属性值是**加密**,然后在通过'getProperty()'方法读取时解密。它基本上是一个模糊的层面,但确实解决了肩上冲浪和休息时随机访问敏感数据的问题。 – 2012-04-25 10:48:49

+1

@MadsHansen感谢您的信息。我认为我不会将它用于这个项目(已经进入代码冻结阶段了......),但我一定会记住它的下一个版本/项目。 – daramasala 2012-04-30 08:02:53

9

穷人芒折衷的解决办法是使用一个简单的多签名的方法。

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

他或她对应用程序开发人员给予一半的密码谁再硬编码成Java的二进制文件。

私人字符串PASS1 =“TAKqWskc4ncvKaJTyDcgAHq82”

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

Java的罐子/myapplication.jar -pass2 X7tX6GfK2fc386bmNw3muknjU

应用程序启动时,它使用PASS1 + PASS2并连接到数据库。

这个解决方案有很多优点,没有提到的缺点。

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

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

源代码在阅读时也可能是半公开的,并且密码不会为您提供应用程序访问权限。

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

+1

这可能不安全。由于操作系统日志记录,通常不建议通过命令行提供凭据。入侵者只需打开源文件 - >读取一半密码,然后在命令行输入'history',瞧! – 2017-12-01 10:46:42

7

如何提供一个自定义的N-因素认证机制?

结合可用的方法之前,让我们假设,我们可以执行以下操作:在Java程序中

1)硬编码

2)在.properties存储文件

3)向用户从命令行

4)向用户从表单

5)向用户键入密码键入密码加载一个密码音响乐从命令行或形式

6)通过网络提供密码

7)许多替代方案(例如绘制一个秘密,指纹,IP专用,唧唧歪歪)

第一选项:我们可以通过使用模糊处理让攻击者变得更加复杂,但这并不是一个好的对策。一个好的编码人员可以很容易地理解他/她是否可以访问该文件。我们甚至可以导出每个用户的二进制文件(或者只是混淆部分或关键部分),因此攻击者必须能够访问此用户特定的文件,而不是另一个发行版。 同样,我们应该找到一种方法来更改密码,例如通过重新编译或使用反射来实时更改类行为。

第二个选项:我们可以存储在属性文件中的密码以加密格式,所以它不是从攻击(就像jasypt一样)直接可见。如果我们需要密码管理器,我们还需要一个主密码,这个密码也应该存储在某个地方 - 在一个。类文件,密钥库,内核,另一个文件甚至内存 - 都有其优点和缺点。
但是,现在用户只需编辑.properties文件以更改密码。

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

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

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

第4个选项:从自定义窗体而不是命令行提供密码。这将规避记录曝光的问题。

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

第6个选项:再次为了避免肩负式冲浪,可以实现RMI方法调用,以从另一个设备(例如通过移动电话)提供密码(通过加密通道)。但是,您现在需要保护您的网络通道并访问其他设备。

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

虽然我们无法保护未经授权的内存访问,但这只能通过使用一些访问受限的硬件(例如智能卡,HSM,SGX)来实现,即无需任何人即可计算所有内容合法所有者能够访问解密密钥或算法。同样,也可以窃取这些硬件,据报道有side-channel attacks可以帮助攻击者进行密钥提取,在某些情况下,您需要信任另一方(例如,您信任英特尔的SGX)。当然,当可能进行安全飞地克隆(拆卸)时情况可能会恶化,但我想这需要几年时间才能实用。

此外,人们可能会考虑一个密钥共享解决方案,其中全密钥在不同服务器之间分割。但是,重建后,全键可能会被盗。减轻上述问题的唯一方法是通过secure multiparty computation

我们应该时刻牢记,无论输入法如何,我们都需要确保我们不会受到网络嗅探(MITM攻击)和/或密钥记录器的攻击。