- 浏览: 304762 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
popotang:
关注raphael,从中学习一下
基于jquery, raphael的WEB流程设计器 -
Getwaysun:
拜读了,写得非常好
iframe跨域session丢失问题 -
chen4w:
good!
Geoserver & Openlayers 学习笔记 -
holysky:
Caused by: org.springframework. ...
Spring对属性文件加密解密应用 -
holysky:
希望能解决一下!
Spring对属性文件加密解密应用
前言
在Spring的开发中,我们在很多情况下会使用占位符引用属性文件的属性值来简化我们的系统及使我们的系统具有更高的灵活性和通用性。这种配置
方式有两个明显的好处:
1、减少维护的工作量:资源的配置信息可以多应用共享,在多个应用使用同一资源的情况下,如果资源的地址、用户名等配置信息发生了更改,你只要调整属性文件就
可以了;
2、使部署更简单:Spring配置文件主要描述应用程序中的Bean,这些配置信息在开发完成后,应该就固定下来了,在部署应用时,需要根据部署环境调整是
就是数据源,邮件服务器的配置信息,将它们的配置信息独立到属性文件中,应用部署人员只需要调整资源属性文件即可,根本不需要关注内容复杂的Spring
配置文件。不仅给部署和维护带来了方便,也降低了出错的机率。
Spring为我们提供了一个BeanFactoryPostProcessorBean工厂后置处理器接口的实现
类:org.springframework.beans.factory.config.PropertyPlaceholderConfigurer,
它的主要功能是对引用了外部属性值的<bean>进行处理,将其翻译成真实的配置值。
一般的属性信息以明文的方式存放在属性文件中并没有什么问题,但如果是数据源或邮件服务器用户名密码等重要的信息,在某些场合,我们可能需要以密文的方式
保存。虽然Web应用的客户端用户看不到配置文件的,但有时,我们只希望特定的维护人员掌握重要资源的配置信息,而不是毫无保留地对所有可以进入部署机器
的用户开放。
对于这种具有高度安全性要求的系统(如电信、银行、重点人口库等),我们需要对资源连接等属性配置文件中的配置信息加密存放。然后让Spring容器启动
时,读入配置文件后,先进行解密,然后再进行占位符的替换。
很可惜,PropertyPlaceholderConfigurer只支持明文的属性文件。但是,我们可以充分利用Spring框架的扩展性,通过扩展
PropertyPlaceholderConfigurer类来达到我们的要求。本文将讲解使用加密属性文件的原理并提供具体的实现。
以传统的方式使用属性文件
一般情况下,外部属性文件用于定义诸如数据源或邮件服务器之类的配置信息。这里,我们通过一个简单的例子,讲解使用属性文件的方法。假设有一个
car.properties属性文件,文件内容如下:
brand=红旗CA72
maxSpeed=250
price=20000.00
该文件放在类路径的com/baobaotao/目录下,在Spring配置文件中利用PropertyPlaceholderConfigurer引入
这个配置文件,并通过占位符引用属性文件内的属性项,如代码清单 1所示:
代码清单 1 使用外部属性文件进行配置
<!-- ① 引入外部属性文件 --> <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <list> <value>classpath:com/baobaotao/car.properties</value> ② 指定属性文件地址 </list> </property> <property name="fileEncoding" value="utf-8"/> </bean> <!-- ③ 引用外部属性的值,对car进行配置 --> <bean id="car" class="com.baobaotao.place.Car"> <property name="brand" value="${brand}" /> <property name="maxSpeed" value="${maxSpeed}" /> <property name="price" value="${price}" /> </bean>
在①处,我们通过PropertyPlaceholderConfigurer这个BeanFactoryPostProcessor实现类引用外部的属
性文件,通过它的locations属性指定Spring配置文件中引用到的属性文件,在PropertyPlaceholderConfigurer内
部,locations是一个Resource数组,所以你可以在地址前添加资源类型前缀,如②处所示。如果需要引用多个属性文件,只需要在②处添加相
应<value>配置项即可。
分析PropertyPlaceholderConfigurer结构
我们知道Spring通过PropertyPlaceholderConfigurer提供对外部属性文件的支持,为了使用加密的属性文件,我们就需要分
析该类的工作机理,再进行改造。所以我们先来了解一下该类的结构(见附件1)。
其中PropertiesLoaderSupport类有一个重要的protected void
loadProperties(Properties
props)方法,查看它的注释,可以知道该方法的作用是将PropertyPlaceholderConfigurer
中locations属性所定义的属性文件的内容读取到props入参对象中。这个方法比较怪,Java很少通过入参承载返回值,但这个方法就是这样。
所以,我们只要简单地重载这个方法,在将资源文件的内容转换为Properties之前,添加一个解密的步骤就可以了。但
是,PropertiesLoaderSupport的设计有一个很让人遗憾的地方,它的locations属性是private的,只提供setter
没有提供getter。因此,无法在子类中获取PropertiesLoaderSupport中的locations(资源地址),所以我们得在子类重
新定义locations属性并覆盖PropertiesLoaderSupport中的setLocations()方法。
编写支持加密属性文件的实现类
通过以上分析,我们设计一个支持加密属性文件的增强型PropertyPlaceholderConfigurer,其代码如所示:
代码清单 2
import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.security.Key; import java.util.Properties; import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; import org.springframework.core.io.Resource; import org.springframework.util.DefaultPropertiesPersister; import org.springframework.util.PropertiesPersister; public class DecryptPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer ...{ private Resource[] locations; //① 重新定义父类中的这个同名属性 private Resource keyLocation; //② 用于指定密钥文件 public void setKeyLocation(Resource keyLocation) ...{ this.keyLocation = keyLocation; } public void setLocations(Resource[] locations) ...{ this.locations = locations; } public void loadProperties(Properties props) throws IOException ...{ if (this.locations != null) ...{ PropertiesPersister propertiesPersister = new DefaultPropertiesPersister(); for (int i = 0; i < this.locations.length; i++) ...{ Resource location = this.locations[i]; if (logger.isInfoEnabled()) ...{ logger.info("Loading properties file from " + location); } InputStream is = null; try{ is = location.getInputStream(); //③ 加载密钥 Key key = DESEncryptUtil.getKey(keyLocation.getInputStream()); //④ 对属性文件进行解密 is = DESEncryptUtil.doDecrypt(key, is); //⑤ 将解密后的属性流装载到props中 if(fileEncoding != null)...{ propertiesPersister.load(props,new InputStreamReader(is,fileEncoding)); }else { propertiesPersister.load(props ,is); } } finally{ if (is != null) is.close(); } } } } } }
对locations指定的属性文件流数据进行额外的解密工作,解密后再装载到props中。比起
PropertyPlaceholderConfigurer,我们只做了额外的一件事:装载前对属性资源进行解密。
在代码清单 2的③和④处,我们使用了一个DES解密的工具类对加密的属性文件流进行解密。
对文件进行对称加密的算法很多,一般使用DES对称加密算法,因为它速度很快,破解困难,DESEncryptUtil不但提供了DES解密功能,还提供
了DES加密的功能,因为属性文件在部署前必须经常加密:
代码清单 3 加密解密工具类
public class DESEncryptUtil ...{ public static Key createKey() throws NoSuchAlgorithmException {//创建一个密钥 Security.insertProviderAt(new com.sun.crypto.provider.SunJCE(), 1); KeyGenerator generator = KeyGenerator.getInstance("DES"); generator.init(new SecureRandom()); Key key = generator.generateKey(); return key; } public static Key getKey(InputStream is) { try{ ObjectInputStream ois = new ObjectInputStream(is); return (Key) ois.readObject(); } catch (Exception e) ...{ e.printStackTrace(); throw new RuntimeException(e); } } private static byte[] doEncrypt(Key key, byte[] data) {//对数据进行加密 try { Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding"); cipher.init(Cipher.ENCRYPT_MODE, key); byte[] raw = cipher.doFinal(data); return raw; } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } } public static InputStream doDecrypt(Key key, InputStream in) {//对数据进行解密 try { Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding"); cipher.init(Cipher.DECRYPT_MODE, key); ByteArrayOutputStream bout = new ByteArrayOutputStream(); byte[] tmpbuf = new byte[1024]; int count = 0; while ((count = in.read(tmpbuf)) != -1) { bout.write(tmpbuf, 0, count); tmpbuf = new byte[1024]; } in.close(); byte[] orgData = bout.toByteArray(); byte[] raw = cipher.doFinal(orgData); ByteArrayInputStream bin = new ByteArrayInputStream(raw); return bin; } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } } public static void main(String[] args) throws Exception {//提供了Java命令使用该工具的功能 if (args.length == 2 && args[0].equals("key")) {// 生成密钥文件 Key key = DESEncryptUtil.createKey(); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(args[1])); oos.writeObject(key); oos.close(); System.out.println("成功生成密钥文件。"); } else if (args.length == 3 && args[0].equals("encrypt")) {//对文件进行加密 File file = new File(args[1]); FileInputStream in = new FileInputStream(file); ByteArrayOutputStream bout = new ByteArrayOutputStream(); byte[] tmpbuf = new byte[1024]; int count = 0; while ((count = in.read(tmpbuf)) != -1) { bout.write(tmpbuf, 0, count); tmpbuf = new byte[1024]; } in.close(); byte[] orgData = bout.toByteArray(); Key key = getKey(new FileInputStream(args[2])); byte[] raw = DESEncryptUtil.doEncrypt(key, orgData); file = new File(file.getParent() + "\\en_" + file.getName()); FileOutputStream out = new FileOutputStream(file); out.write(raw); out.close(); System.out.println("成功加密,加密文件位于:"+file.getAbsolutePath()); } else if (args.length == 3 && args[0].equals("decrypt")) {//对文件进行解密 File file = new File(args[1]); FileInputStream fis = new FileInputStream(file); Key key = getKey(new FileInputStream(args[2])); InputStream raw = DESEncryptUtil.doDecrypt(key, fis); ByteArrayOutputStream bout = new ByteArrayOutputStream(); byte[] tmpbuf = new byte[1024]; int count = 0; while ((count = raw.read(tmpbuf)) != -1) { bout.write(tmpbuf, 0, count); tmpbuf = new byte[1024]; } raw.close(); byte[] orgData = bout.toByteArray(); file = new File(file.getParent() + "\\rs_" + file.getName()); FileOutputStream fos = new FileOutputStream(file); fos.write(orgData); System.out.println("成功解密,解密文件位于:"+file.getAbsolutePath()); } } }
解密工作主要涉及到两个类Cipher和Key,前者是加密器,可以通过init()方法设置工作模式和密钥,在这里,我们设置为解密工作模 式:Cipher.DECRYPT_MODE。Cipher通过doFinal()方法对字节数组进行加密或解密。
要完成属性文件的加密工作,首先,必须获取一个密钥文件,然后才能对明文的属性文件进行加密。如果需要调整属性文件的信息,你必须执行相反的过程,即用密
钥对加密后的属性文件进行解密,调整属性信息后,再将其加密。
DESEncryptUtil 工具类可以完成以上所提及的三个工作:
1、生成一个密钥文件
java com.baobaotao.DESEncryptUtil key D:\key.dat
第一个参数为key,表示创建密钥文件,第二个参数为生成密钥文件的保存地址。
2、用密钥文件对属性文件进行加密
java com.baobaotao.DESEncryptUtil encrypt d:\test.properties
d:\key.dat
第一个参数为encrypt,表示加密,第二个参数为需要加密的属性文件,第三个参数为密钥文件。如果加密成功,将生成
en_test.properties的加密文件。
3、用密钥文件对加密后的属性文件进行解密
java com.baobaotao.DESEncryptUtil decrypt d:\test.properties
d:\key.dat
第一个参数为decrypt,表示解密,第二个参数为需要解密的属性文件,第三个参数为密钥文件。如果加密成功,将生成
rs_test.properties的解密文件。
在Spring中配置加密属性文件
假设我们通过DESEncryptUtil
工具类创建了一个key.bat密钥,并对car.properties属性进行加密,生成加密文件en_car.properties。下面,我们通过
DecryptPropertyPlaceholderConfigurer增强类进行配置,让Spring容器支持加密的属性文件:
假设我们通过DESEncryptUtil
工具类创建了一个key.bat密钥,并对car.properties属性进行加密,生成加密文件en_car.properties。下面,我们通过
DecryptPropertyPlaceholderConfigurer增强类进行配置,让Spring容器支持加密的属性文件:
<bean class="com.baobaotao.place.DecryptPropertyPlaceholderConfigurer"> ① <property name="locations"> <list> <value>classpath:com/baobaotao/en_car.properties</value> </list> </property> <property name="keyLocation" value="classpath:com/baobaotao/key.dat" /> <property name="fileEncoding" value="utf-8" /> </bean> <bean id="car" class="com.baobaotao.place.Car"> ② <property name="brand" value="${brand}" /> <property name="maxSpeed" value="${maxSpeed}" /> <property name="price" value="${price}" /> </bean>
注意①处的配置,我们使用自己编写的DecryptPropertyPlaceholderConfigurer替代Spring的
PropertyPlaceholderConfigurer,由于前者对属性文件进行了特殊的解密处理,因此②处的car
Bean也可以引用到加密文件en_car.properties中的属性项。
小结
要Spring配置时,将一些重要的信息独立到属性文件中是比较常见的做法,Spring只支持明文存放的属性文件,在某些场合下,我们可以希望对属性文
件加密保存,以保证关键信息的安全。通过扩展PropertyPlaceholderConfigurer,在属性文件流加载后应用前进行解密就可以很好
地解决这个问题了。
评论
发表评论
-
10个强大的Ajax jQuery文件上传程序
2010-11-10 11:18 2292上传文件和图片是许多网站的一个常用功能,无论是让注册用户上传一 ... -
Parsing error processing resource path
2010-11-09 09:29 957ERROR - Parsing error processin ... -
Struts+Spring+Hibernate--SSH整合实例
2010-04-23 18:49 1986Struts+Spring+Hibernate--SSH整合实 ... -
Spring Ioc概述
2010-04-14 16:29 8351、Ioc概述 Ioc(控制反转)是Spring容器的内核, ... -
Spring中的数据库操作事务
2010-04-14 15:41 1239一、 Spring 中的事务 S ... -
Spring中的AOP面向切面编程和Spring对JDBC的支持
2010-04-14 15:35 1754一、Spring-AOP AOP面向切面编程(Asp ... -
Spring的基础操作、IOC(控制反转)以及DI(依赖注入)的原理
2010-04-14 15:08 2209大名鼎鼎的Spring 大家都听过, spring 是一 ... -
Spring 的优秀工具类盘点
2010-04-13 11:11 1095文件资源操作 文 件资源的操作是应用程序中常见的功 ... -
Hibernate HQL大全
2010-01-19 22:36 862Hibernate配备了一种非常强大的查询语言,这种语言看上去 ... -
hibernate悲观锁与乐观锁(一)
2009-03-11 14:38 9111.悲观锁 它指的是对数据被外界修改持保守态度。假定任何时刻 ... -
hibernate悲观锁与乐观锁(一)
2009-03-11 14:29 1032Hibernate支持两种锁机制: 即通常所说的“悲观锁(Pe ... -
Spring,hibernate,struts的面试笔试题
2009-03-10 21:28 12721、Action是不是线程安全 ... -
Struts、Spring、Hibernate (SSH) 整合实例
2009-03-10 12:41 1951首选创建web.xml 主要是配置Struts的ActionS ... -
Hibernate缓存机制
2009-03-10 12:26 754缓存是位于应用程序与物理数据源之间,用于临时存放复制数 ... -
hibernate二级缓存详解
2009-03-10 12:15 1172hibernate的session提供了一 ... -
Hibernate查询语言——HQL
2009-03-10 10:13 1053HQL: Hibernate查询语言 Hibernate ... -
Hibernate构架应用中常用保存方式区别
2009-03-09 22:23 807hibernate对于对象的保存 ... -
Spring 结合 Hibernate 配置 C3P0
2009-03-09 22:15 713applicationContext.xml 文件 ... -
Hibernate高级查询实战
2009-03-09 22:13 876大家知道,在Hibernate Framework中,提供了三 ... -
Hibernate 中配置C3P0连接池
2009-03-09 22:10 1049Hibernate自带的连接池算法相当不成熟。 它只是 ...
相关推荐
json接口的简单实例,可以直接运行看到效果。通过des加密解密进行服务器客户端的json接口通讯。应用httpclient组件...
主要给大家介绍了关于Spring MVC请求参数与响应结果全局加密和解密的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
Md5加密解密
文件包括源代码和安装包,源代码里包括自定义的RSA加密解密模型,方便复用。 程序采用了经典的MVC的设计方案,将底层的RSA加密解密功能封装为单独的组件,并定义了RSA的操作模型,提供视图和底层模型进行交互的外观...
JCE补丁下载
MD5 加密解密例子 j2ee struts spring hibernate MD5
网页展示,部分数据后台传输,后台使用spring boot ,类似在线网页加密解密,使用idea编译器,版本2018,版本似乎没什么关系。下载导入基本可以用。程序页面访问链接:http://localhost:8090/ecdc/index
该工具类使用于spring boot 开发,返回值为md5加密后的字符串,参数为字符串,一般用于加密密码。为了防止MD5加密的密码...本人上传的表单验证规则的js文件【版本为V1.0的js文件】有限制,建议配合这两个文件一起使用。
包含生成密匙,加密文件,用密钥k解密文件
这是一个简单的案例用来实现Spring中jdbc.properties属性文件进行密文处理,代码中的学生实体自己根据需要在数据库中进行创建
SpringCloud Conf 搭建配置中心二加密和解密对称加解密非对称加解密对称加解密Spring Cloud可以在本地进行预处理的解密,需要在JVM添加J
spring框架中关于RSA sha-256加密解密,加签验签工具类
给大家介绍了Spring cloud config 配置文件加密方式,非常不错,具有一定的参考借鉴价值,感兴趣的朋友跟随脚步之家小编一起学习吧
SpringBoot控制器统一的响应体加密与请求体解密的注解处理方式,支持MD5/SHA/AES/DES/RSA
No key was installed for encryption service
对其进行数据解密,以及返回参数加密,前端解密,完整原始文件,由于是城市表面常用的是这二种加解密方式,所以就写了这二种,每天会自动更换密密钥,后续我会陆续更新其他的加解密算法,技术点采用新的spring-...
开发工具Eclipse,数据库mySQL 框架springMVC+spring+myBatis
主要介绍了Spring Boot 实现配置文件加解密原理,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
rsa加解密
SpringBoot控制器统一的响应体编码/加密与请求体解密的注解处理方式,支持MD5/SHA/AES/DES/RSA