`
ispring
  • 浏览: 359405 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

扩展Spring——外部属性文件安全(二)

阅读更多
编写支持加密属性文件的实现类
    通过以上分析,我们设计一个支持加密属性文件的增强型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()方法对字节数组进行加密或解密。
分享到:
评论

相关推荐

    ProSpring——Spring专业开发指南

    《ProSpring——Spring专业开发指南》是一本深入探讨Spring框架的专业书籍,旨在帮助开发者全面理解和掌握Spring的核心概念、功能及最佳实践。通过阅读本书,你可以深入理解Spring如何为Java应用程序提供强大的依赖...

    SSH笔记-通过property-placeholder使用外部属性文件

    本笔记将专注于Spring框架中的一个关键特性——通过`property-placeholder`使用外部属性文件,这在实际项目中非常常见,能够有效地实现配置的解耦和管理。 首先,让我们理解`property-placeholder`的概念。在Spring...

    Spring——IOC(控制反转)与DI(依赖注入).docx

    Spring框架中的IOC(控制反转)和DI(依赖注入)是两种关键的设计模式,它们极大地提升了软件的可维护性和可扩展性。控制反转是一种设计思想,它改变了传统的对象创建方式,将对象的创建和管理权从应用程序自身转移...

    Spring总结——田超凡.docx

    这些应用需要具备高度的安全性、性能以及可扩展性和维护性。Spring 框架针对这些需求提供了相应的解决方案,使开发者能够快速构建可维护、可扩展的系统。 【Spring 框架的核心价值】 1. **控制反转 (IoC/DI)**:...

    JavaEE精讲之Spring框架实战 ——学习笔记.zip

    1. **依赖注入**:Spring的DI允许开发者通过外部配置文件来管理对象之间的依赖关系,而不是在代码中硬编码这些依赖。这种方式使得代码更加灵活,易于测试和维护,因为对象的创建和配置是解耦的。 2. **面向切面编程...

    Spring依赖注入——java项目中使用spring注解方式进行注入.rar

    依赖注入是一种设计模式,其核心思想是将对象之间的依赖关系从代码中分离出来,由外部容器(如Spring框架)负责管理对象的创建和装配,而不是由对象自身负责。这样可以提高代码的可测试性、可维护性和灵活性。 二、...

    幻灯片——Spring.NET介绍(德文版)

    根据给定的文件信息,以下是对Spring.NET框架的详细介绍及相关知识点: ### 动机与背景 Spring.NET 是一个为.NET平台开发的应用程序框架,旨在简化企业级应用的开发过程。随着系统规模的增长,传统的“即兴”式...

    关于Spring的69个面试问答——终极列表

    10. **配置文件**:Spring的配置通常以XML文件形式存在,描述了对象的配置和相互关系。此外,Spring 3.0后引入了基于注解的配置,使得配置更加简洁。 11. **Spring IOC容器**:Spring的IOC容器负责实例化、配置和...

    10.客户端——Struts 2+Spring+EJB架构实现

    特别是,Spring 的 IoC 容器使得对象之间的依赖关系可以被外部容器管理,这样可以提高代码的解耦度和可测试性。同时,Spring AOP 使得开发者可以在不修改源代码的情况下添加跨切面关注点,如日志、事务处理等。 EJB...

    达内Spring教程.pdf格式

    在本教程中,我们将深入探讨Spring的核心技术——IOC(Inversion of Control,控制反转)和AOP(Aspect-Oriented Programming,面向切面编程)。 1. **Spring框架概述** Spring框架是一个全面的后端开发解决方案,...

    pro spring 中文版

    在深入探讨Spring框架之前,我们需要理解其核心概念之一——控制反转(Inversion of Control, IoC)。这一概念最初由Martin Fowler提出,并被赋予了一个更为贴切的名字——依赖注入(Dependency Injection, DI)。...

    spring boot admin server

    5. 自定义监控:用户可以通过扩展Spring Boot Actuator的端点或者自定义HealthIndicator来添加自己的监控项。 描述中提到的博文链接(由于无法访问,具体内容未知),可能提供了关于如何配置和使用Spring Boot ...

    spring-developing-java-applications-enterprise

    #### 二、Spring框架的特点 - **轻量级**:Spring框架的核心部分非常小,只有2MB左右,使得它非常容易下载和部署。 - **控制反转(IoC)**:Spring通过控制反转来管理对象之间的依赖关系,简化了Java应用程序的配置...

    跟我学spring

    【第二章】IoC(控制反转)是Spring框架的核心概念之一,它涉及到对象创建的控制权从程序代码转移到外部容器。IoC有多种实现方式,包括依赖注入(DI)。在Spring中,IoC容器负责创建对象,初始化它们,并管理它们的...

    Spring.3.x企业应用开发实战(完整版).part2

    5.3.1 使用外部属性文件 5.3.2 使用加密的属性文件 5.3.3 属性文件自身的引用 5.4 引用Bean的属性值 5.5 国际化信息 5.5.1 基础知识 5.5.2 MessageSource 5.5.3 容器级的国际化信息资源 5.6 容器事件 5.6.1 Spring...

    《Spring+in+action+中文版(第4版)》读书笔记

    Spring支持从外部文件中读取配置信息,这些配置信息可以是属性文件、JSON文件或其他格式。常见的注入方式包括: 1. **Java配置**:使用`@PropertySource`注解和`Environment`接口。 2. **XML配置**:使用`...

    springioc和spring aop

    Spring框架是Java开发中不可或缺的一部分,它通过提供两种核心特性——控制反转(IoC)和面向切面编程(AOP)来简化应用的构建。理解并掌握这两种技术对于任何Java开发者来说都至关重要。 **控制反转(IoC)**,也...

    JavaEE开发的颠覆者SpringBoot实战[完整版].part3

    涵盖使用Spring Boot 进行Java EE 开发的绝大数应用场景,包含:Web 开发、数据访问、安全控制、批处理、异步消息、系统集成、开发与部署、应用监控、分布式系统开发等。 第一部分 点睛Spring 4.x 第1 章 Spring ...

Global site tag (gtag.js) - Google Analytics