你的配置文件是不是还在使用下面这种落后的配置暴露一些密码:

  1. jdbc.url=jdbc:mysql://127.0.0.1:3305/afei

  2. jdbc.username=afei

  3. jdbc.password=123456

如果是,那么继续往下看。笔者今天介绍史上最优雅加密接入方式:jasypt

使用方式

用法一

先看用法有多简单,以 springboot 为例:

  1. Application.java 上增加注解 @EnableEncryptableProperties;

  2. 增加配置文件 jasypt.encryptor.password = Afei@2018 ,这是加密的秘钥;

  3. 所有明文密码替换为 ENC (加密字符串),例如ENC(XW2daxuaTftQ+F2iYPQu0g==) ;

  4. 引入一个MAVEN依赖;

maven坐标如下:


  1. <dependency>

  2. <groupId>com.github.ulisesbocchio</groupId>

  3. <artifactId>jasypt-spring-boot</artifactId>

  4. <version>2.0.0</version>

  5. </dependency>

简答的 4 步就搞定啦,是不是超简单?完全不需要修改任何业务代码。其中第三步的加密字符串的生成方式为:


  1. java -cp jasypt-1.9.2.jar org.jasypt.intf.cli.JasyptPBEStringEncryptionCLI input="123456" password=Afei@2018 algorithm=PBEWithMD5AndDES

其中:

  • input的值就是原密码。

  • password的值就是参数jasypt.encryptor.password指定的值,即秘钥。

用法二

其实还有另一种更简单的姿势:

  1. 增加配置文件 jasypt.encryptor.password = Afei@2018,这是加密的秘钥;

  2. 所有明文密码替换为 ENC (加密字符串),例如 ENC(XW2daxuaTftQ+F2iYPQu0g==);

  3. 引入一个MAVEN依赖;

maven 坐标如下:


  1. <dependency>

  2. <groupId>com.github.ulisesbocchio</groupId>

  3. <artifactId>jasypt-spring-boot-starter</artifactId>

  4. <version>2.0.0</version>

  5. </dependency>

相比第一种用法,maven 坐标有所变化。但是不需要显示增加注解 @EnableEncryptableProperties;

github地址

github:https://github.com/ulisesbocchio/jasypt-spring-boot 它 github 首页有详细的用法说明,以及一些自定义特性,例如使用自定义的前缀和后缀取代 ENC():


  1. jasypt.encryptor.property.prefix=ENC@[

  2. jasypt.encryptor.property.suffix=]

原理解密

既然是 springboot 方式集成,那么首先看 jasypt-spring-boot 的 spring.factories 的申明:


  1. org.springframework.context.ApplicationListener=\

  2. com.ulisesbocchio.jasyptspringboot.configuration.EnableEncryptablePropertiesBeanFactoryPostProcessor

这个类的部分核心源码如下:


  1. public class EnableEncryptablePropertiesBeanFactoryPostProcessor implements BeanFactoryPostProcessor, ApplicationListener<ApplicationEvent>, Ordered {

  2. @Override

  3. public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

  4. // 得到加密字符串的处理类(已经加密的密码通过它来解密)

  5. EncryptablePropertyResolver propertyResolver = beanFactory.getBean(RESOLVER_BEAN_NAME, EncryptablePropertyResolver.class);

  6. // springboot下的Environment里包含了所有我们定义的属性, 也就包含了application.properties中所有的属性

  7. MutablePropertySources propSources = environment.getPropertySources();

  8. // 核心,PropertySource的getProperty(String)方法委托给EncryptablePropertySourceWrapper

  9. convertPropertySources(interceptionMode, propertyResolver, propSources);

  10. }

  11. @Override

  12. public int getOrder() {

  13. // 让这个jasypt定义的BeanFactoryPostProcessor的初始化顺序最低,即最后初始化

  14. return Ordered.LOWEST_PRECEDENCE;

  15. }

  16. }

PropertySource 的 getProperty(String) 方法委托给EncryptablePropertySourceWrapper,那么当获取属性时,实际上就是调用 EncryptablePropertySourceWrapper 的 getProperty() 方法,在这个方法里我们就能对 value 进行解密了。

EncryptablePropertySourceWrapper 实现了接口EncryptablePropertyResolver,该定义如下:


  1. // An interface to resolve property values that may be encrypted.

  2. public interface EncryptablePropertyResolver {

  3. String resolvePropertyValue(String value);

  4. }

接口描述: Returns the unencrypted version of the value provided free on any prefixes/suffixes or any other metadata surrounding the encrypted value. Or the actual same String if no encryption was detected.

  • 如果通过 prefixes/suffixes 包裹的属性,那么返回解密后的值;

  • 如果没有被包裹,那么返回原生的值;

实现类的实现如下:


  1. @Override

  2. public String resolvePropertyValue(String value) {

  3. String actualValue = value;

  4. // 如果value是加密的value,则进行解密。

  5. if (detector.isEncrypted(value)) {

  6. try {

  7. // 解密算法核心实现

  8. actualValue = encryptor.decrypt(detector.unwrapEncryptedValue(value.trim()));

  9. } catch (EncryptionOperationNotPossibleException e) {

  10. // 如果解密失败,那么抛出异常。

  11. throw new DecryptionException("Decryption of Properties failed, make sure encryption/decryption passwords match", e);

  12. }

  13. }

  14. // 没有加密的value,返回原生value即可

  15. return actualValue;

  16. }

判断是否是加密的逻辑很简单: (trimmedValue.startsWith(prefix)&&trimmedValue.endsWith(suffix)),即只要 value 是以 prefixe/suffixe 包括,就认为是加密的 value。

总结

通过对源码的分析可知 jasypt 的原理很简单,就是讲原本 spring 中PropertySource 的 getProperty(String) 方法委托给我们自定义的实现。然后再自定义实现中,判断 value 是否是已经加密的 value ,如果是,则进行解密。如果不是,则返回原 value。

原文发布时间为:2018-09-13

本文作者:Java技术驿站

本文来自云栖社区合作伙伴“Java技术驿站”,了解相关信息可以关注“Java技术驿站”。

Get史上最优雅的加密方式!没有之一!的更多相关文章

  1. 史上最全HashMap遍历方式

    java Hashmap Map TreeMap 的几种遍历方式,全网最全,全网最强 package Collec2; import java.util.HashMap; import java.ut ...

  2. 史上最全的CSS hack方式一览

    做前端多年,虽然不是经常需要hack,但是我们经常会遇到各浏览器表现不一致的情况.基于此,某些情况我们会极不情愿的使用这个不太友好的方式来达到大家要求的页面表现.我个人是不太推荐使用hack的,要知道 ...

  3. [转]史上最全的CSS hack方式一览

    做前端多年,虽然不是经常需要hack,但是我们经常会遇到各浏览器表现不一致的情况.基于此,某些情况我们会极不情愿的使用这个不太友好的方式来达到大家要求的页面表现.我个人是不太推荐使用hack的,要知道 ...

  4. 史上最全的CSS hack方式一览 jQuery 图片轮播的代码分离 JQuery中的动画 C#中Trim()、TrimStart()、TrimEnd()的用法 marquee 标签的使用详情 js鼠标事件 js添加遮罩层 页面上通过地址栏传值时出现乱码的两种解决方法 ref和out的区别在c#中 总结

    史上最全的CSS hack方式一览 2013年09月28日 15:57:08 阅读数:175473 做前端多年,虽然不是经常需要hack,但是我们经常会遇到各浏览器表现不一致的情况.基于此,某些情况我 ...

  5. IDEA HTTP Client(史上最全)

    文章很长,建议收藏起来,慢慢读! 疯狂创客圈为小伙伴奉上以下珍贵的学习资源: 疯狂创客圈 经典图书 : <Netty Zookeeper Redis 高并发实战> 面试必备 + 大厂必备 ...

  6. 史上最全面的SignalR系列教程-2、SignalR 实现推送功能-永久连接类实现方式

    1.概述 通过上篇史上最全面的SignalR系列教程-1.认识SignalR文章的介绍,我们对SignalR技术已经有了一个全面的了解.本篇开始就通过SignalR的典型应用的实现方式做介绍,例子虽然 ...

  7. 史上最全面的SignalR系列教程-3、SignalR 实现推送功能-集线器类实现方式

    1.概述 通过前两篇 史上最全面的SignalR系列教程-1.认识SignalR 史上最全面的SignalR系列教程-2.SignalR 实现推送功能-永久连接类实现方式 文章对SignalR的介绍, ...

  8. GitHub上史上最全的Android开源项目分类汇总 (转)

    GitHub上史上最全的Android开源项目分类汇总 标签: github android 开源 | 发表时间:2014-11-23 23:00 | 作者:u013149325 分享到: 出处:ht ...

  9. 史上最全阿里 Java 面试题总结

    以下为大家整理了阿里巴巴史上最全的 Java 面试题,涉及大量 Java 面试知识点和相关试题. JAVA基础 JAVA中的几种基本数据类型是什么,各自占用多少字节. String类能被继承吗,为什么 ...

随机推荐

  1. qW3xT.2,解决挖矿病毒

    在阿里云使用redis,开启了6379端口,但是当时并没有对redis的密码进行设置. 在晚上一点左右.阿里云给我发短信,告诉我服务器出现紧急安全事件.建议登录云盾-态势感知控制台查看详情和处理. 于 ...

  2. MYSQL索引类型。MYSQLc储存引擎

                                                            MYSQL索引类型,MYSQLc储存引擎 MySQL索引创建与删除 MySQL存储引擎的 ...

  3. Spring Boot入门系列(十)如何使用拦截器,一学就会!

    前面介绍了Spring Boot 如何整合定时任务已经Spring Boot 如何创建异步任务,不清楚的朋友可以看看之前的文章:https://www.cnblogs.com/zhangweizhon ...

  4. java中查询某个类已经创建了多少个对象了

    这个代码主要是使用类的静态字段和构造函数,可以跟踪某个类所创建对象的个数.请写一个类,在任何时候都可以向它查询“你已经创建了多少个对象? 主要是在构造函数中用到了静态数据,进行显示已经构造了多少个类对 ...

  5. tornado实现不同app路由分发

    tornado实现app路由分发 from tornado import ioloop from tornado.httpserver import HTTPServer from tornado.w ...

  6. django实现自定义登陆验证

    django实现自定义登陆验证 自定义装饰器函数和类 from utils.http import HttpResponseUnauthorized from django.views import ...

  7. 初始WebApi(1)

    如果你要问我WebApi是干嘛,我只能说它是的给数据.哈哈哈哈哈,这几天也才刚刚了解了解关于WebApi的知识,今天就来谈谈吧. 1.创建WebApi项目 第一步:选择ASP.NET Web应用程序 ...

  8. python连接mysql中文数据编码

    系统是win7 x64 Python 2.7.6的site.py里面编码设定为 utf-8 py文件首行指定 #coding:utf-8 MySQL 5.5.38安装时指定代码为utf-8 peewe ...

  9. python3(三十七) filepath

    """ file path """ __author__on__ = 'shaozhiqi 2019/9/23' # !/usr/bin/e ...

  10. input相关

    input相关 在ios中输入英文首字母默认大写取消方法 <input autocapitalize="off" autocorrect="off" /& ...