对 spring applicationContext.xml 中使用的数据源使用编码密码
Posted
技术标签:
【中文标题】对 spring applicationContext.xml 中使用的数据源使用编码密码【英文标题】:Using encoded password for the datasource used in spring applicationContext.xml 【发布时间】:2012-10-01 19:48:08 【问题描述】:我想在下面提到的 springApplicationContext.xml 中保留编码密码
有什么方法可以实现吗?
目前我已经使用属性占位符配置了所有属性 如下所示,但原始密码仍然在我的 database.properties 中打开
springApplicationContext.xml
<beans:bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<beans:property name="driverClassName"><beans:value>$db.driverClassName</beans:value></beans:property>
<beans:property name="url"><beans:value>$db.url</beans:value></beans:property>
<beans:property name="username"><beans:value>$db.username</beans:value></beans:property>
<beans:property name="password"><beans:value>$db.password</beans:value></beans:property>
</beans:bean>
但实际值存在于我的database.properties
db.driverClassName=com.mysql.jdbc.Driver
db.url=jdbc:mysql://localhost/myDB
db.username=root
db.password=root
我想要类似下面的东西:
springApplicationContext.xml(同上)
<beans:bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<beans:property name="driverClassName"><beans:value>$db.driverClassName</beans:value></beans:property>
<beans:property name="url"><beans:value>$db.url</beans:value></beans:property>
<beans:property name="username"><beans:value>$db.username</beans:value></beans:property>
<beans:property name="password"><beans:value>$db.password</beans:value></beans:property>
</beans:bean>
但是密码属性值应该是我database.properties
中的加密格式
db.driverClassName=com.mysql.jdbc.Driver
db.url=jdbc:mysql://localhost/myDB
db.username=root
db.password=3g6n72ef8x (using any encription method).
在建立新的数据库连接之前,我的数据源会在内部解密密码。
非常感谢您对此提供的任何帮助/建议。
【问题讨论】:
当您可以获取编码字符串并直接对其进行解码时,您在下面建议的方法可以正常工作。但是对于真正的加密,您不能获取加密字符串并对其进行解密:您获取明文密码,对其进行加密,然后将其与已加密的值进行比较。例如,请参阅 org.springframework.security.crypto.password.StandardPasswordEncoder ,它类似于您在经过 base64 编码器后可能会使用的东西。所以问题是:你的 DataSource 如何获取实际密码来检查 db.password 的加密值? 实际上,要求不是在我的 database.properties 文件中保持原始密码处于打开状态。因此,我的 CustomDataSource 正在解码 database.properties 文件的编码值,然后用于创建新的数据库连接。 我认为 base64 编码密码本质上与原始密码相同(即不安全),但我猜需求的语义由需求制定者决定。 【参考方案1】:我回答自己的问题可能很有趣。但我仍然只是想告诉其他可能面临同样问题的人的解决方案..
为简单起见,我使用了 BASE64Encoder 和 BASE64Decoder。稍后我将修改我的代码以使用安全/更好的加密/解密算法。
我已使用以下代码对我的数据库密码(例如:我的案例的 root)进行了编码:
private String encode(String str)
BASE64Encoder encoder = new BASE64Encoder();
str = new String(encoder.encodeBuffer(str.getBytes()));
return str;
并将编码后的密码放在我的 database.properties 文件中,如下所示:
之前
db.driverClassName=com.mysql.jdbc.Driver
db.url=jdbc:mysql://localhost/myDB
db.username=root
db.password=root
之后
db.driverClassName=com.mysql.jdbc.Driver
db.url=jdbc:mysql://localhost/myDB
db.username=root
db.password=cm9vdA== (Note: encoded 'root' by using BASE64Encoder)
现在我已经为 org.apache.commons.dbcp.BasicDataSource 编写了一个包装类 并重写 setPassword() 方法:
import java.io.IOException;
import org.apache.commons.dbcp.BasicDataSource;
import sun.misc.BASE64Decoder;
public class MyCustomBasicDataSource extends BasicDataSource
public CustomBasicDataSource()
super();
public synchronized void setPassword(String encodedPassword)
this.password = decode(encodedPassword);
private String decode(String password)
BASE64Decoder decoder = new BASE64Decoder();
String decodedPassword = null;
try
decodedPassword = new String(decoder.decodeBuffer(password));
catch (IOException e)
e.printStackTrace();
return decodedPassword;
这样我正在解码(BASE64Decoder)database.properties中提供的编码密码
还修改了springApplicationContext.xml文件中提到的我的dataSource bean的类属性。
<beans:bean id="dataSource" class="edu.config.db.datasource.custom.MyCustomBasicDataSource" destroy-method="close">
<beans:property name="driverClassName"><beans:value>$db.driverClassName</beans:value></beans:property>
<beans:property name="url"><beans:value>$db.url</beans:value></beans:property>
<beans:property name="username"><beans:value>$db.username</beans:value></beans:property>
<beans:property name="password"><beans:value>$db.password</beans:value></beans:property>
谢谢。
【讨论】:
你不需要做 super.password =decode(encodedPassword);而不是 this.password= decode(encodedPassword); Base64 不是加密,而是编码!虽然使用 Base64 算法对用户名和密码进行编码通常会使它们肉眼无法读取,但它们的解码与编码一样容易。安全性不是编码步骤的目的。相反,编码的目的是将用户名或密码中可能存在的不兼容 HTTP 的字符编码为兼容 HTTP 的字符。 此解决方案对属性文件中的密码进行 base 64 编码,但未加密!我将粘贴的“cm9vdA==”复制到base64decode.org 并立即获得“root”。为了其他人阅读此问题和答案,请修改问题以询问“如何使用 base 64 编码密码”而不是“如何使用加密密码”,因为此答案绝对没有加密它。我不希望其他读者认为编码与加密相同。【参考方案2】:创建自定义的 PropertyPlaceHolderConfigurer 扩展 Spring PropertyPlaceHolderConfigurer
public class PropertyPlaceholderConfigurer extends
org.springframework.beans.factory.config.PropertyPlaceholderConfigurer
@Override
protected String convertPropertyValue(final String originalValue)
if (originalValue.startwith("SomeText:"))
//Apply the decryption logic
...
您可以加密属性并附加 SomeText:。使用这个自定义的 PropertyPlaceHolderConfigurer 来加载属性
【讨论】:
【参考方案3】:我想在这里看大图:为什么要加密属性文件中的值?未经授权的人可以访问您的属性文件的情况是什么?
处理存储生产凭证这一更大问题的常用技术是使凭证成为您环境的一部分,而不是源代码的一部分。这里有一些方法可以做到这一点:
将属性文件(带有明文密码)放在生产环境中 Web 服务器的类路径中,这样对密码的访问由对生产机器的访问控制。 在 web.xml 中存储属性(带有参数名称的上下文参数),此文件也是您运行代码的环境的一部分,而不是随代码一起分发 - 对该文件的访问由对机器。 使用 JNDI 并在您的应用服务器中配置该资源。【讨论】:
我有类似的情况,我们希望在属性文件中加密密码,因为我们的应用程序的一部分与我们的另一个应用程序一起安装在客户端的服务器上。此代理使用其他应用程序的数据库。我们不希望我们的客户有权访问该应用程序的数据库。因此,存在需要在属性文件中加密密码的情况。 这是一个我没有考虑过的有趣场景,谢谢。 它仍然只给出了安全的外观和温暖的模糊性,因为任何加密的密码最终都可以被确定的一方解密。但它会阻止休闲派对,它可能已经足够了。 还有另一种情况需要考虑,即应用程序是独立的。我曾经在一家公司工作,该公司的软件与上述情况完全相同,但它是一个独立的桌面应用程序 =)【参考方案4】:创建一个实现Datasource
接口的包装类,它将其方法调用委托给底层数据源,但在此之前解密密码。
【讨论】:
感谢 Abhinav 的建议。现在我可以使用 CustomBasicDataSource 来实现这一点。【参考方案5】:如果你使用tomcat连接池作为数据源,这里有一个实现
http://www.jdev.it/encrypting-passwords-in-tomcat/
创建一个扩展 org.apache.tomcat.jdbc.pool.DataSourceFactory 的类并在 server.xml 中配置它
更新:
较新的方法是使用Jasypt:http://www.jasypt.org/encrypting-texts.html
【讨论】:
以上是关于对 spring applicationContext.xml 中使用的数据源使用编码密码的主要内容,如果未能解决你的问题,请参考以下文章