简 介
Jasypt 也即Java Simplified Encryption是Sourceforge.net上的一个开源项目。在当地时间11月23号的通告中,Jasypt 1.4的新特征包括:加密属性文件(encryptable properties files)、Spring Framework集成、加密Hibernate数据源配置、新的命令行工具、URL加密的Apache wicket集成以及升级文档。
根据Jasypt文档,该技术可用于加密任务与应用程序,例如加密密码、敏感信息和数据通信、创建完整检查数据的sums. 其他性能包括高安全性、基于标准的加密技术、可同时单向和双向加密的加密密码、文本、数字和二进制文件。Jasypt也可以与Acegi Security整合也即Spring Security。Jasypt亦拥有加密应用配置的集成功能,而且提供一个开放的API从而任何一个Java Cryptography Extension都可以使用Jasypt。
Jasypt还符合RSA标准的基于密码的加密,并提供了无配置加密工具以及新的、高可配置标准的加密工具。
1、该开源项目可用于加密任务与应用程序,例如加密密码、敏感信息和数据通信
2、还包括高安全性、基于标准的加密技术、可同时单向和双向加密的加密密码、文本、数字和二进制文件。
3、Jasypt还符合RSA标准的基于密码的加密,并提供了无配置加密工具以及新的、高可配置标准的加密工具。
4、加密属性文件(encryptable properties files)、Spring work集成、加密Hibernate数据源配置、新的命令行工具、URL加密的Apache wicket集成以及升级文档。
5、Jasypt也可以与Acegi Security整合也即Spring Security。Jasypt亦拥有加密应用配置的集成功能,而且提供一个开放的API从而任何一个Java Cryptography Extension都可以使用Jasypt。
Spring Boot使用jasypt处理加密问题
1.背景
现代互联网充斥着各种攻击、病毒、钓鱼、欺诈等手段,层出不穷。对于一个公司而已最基本的财富无非是代码和数据,“配置属性加密”的应用场景假设如果攻击者通过某些手段拿到部分敏感代码或配置,甚至是全部源代码和配置时,我们的基础设施账号依然不被泄漏。当然手段多种多种多样,比如以某台中毒的内网机器为肉机,对其他电脑进行ARP攻击抓去通信数据进行分析,或者获取某个账号直接拿到源代码或者配置,等等诸如此类。
2.思路
采用比较安全的对称加密算法;
对基础设施账号密码等关键信息进行加密;
构建时、运行时传入密钥,在加载属性前进行解密;
开发环境可以将密钥放置在代码中,测试、灰度、生产等环境放置在构建脚本或者启动脚本中;
如果自动化部署甚至可以有专门的程序来管理这些密钥(目前没有,暂不考虑);
3.技术框架
Jasypt是一个优秀的加密库,支持密码、Digest认证、文本、对象加密,此外密码加密复合RFC2307标准。http://www.jasypt.org/download.html
ulisesbocchio/jasypt-spring-boot,集成Spring Boot,在程序引导时对属性进行解密。https://github.com/ulisesbocchio/jasypt-spring-boot
4.处理过程
在项目中使用jasypt-1.9.4.jar包,能够实现对明文进行加密,对密文进行解密。配置相关加密信息,就能够实现在项目运行的时候,自动把配置文件中已经加密的信息解密成明文,供程序使用
使用说明
1.pom引入依赖
<dependency> <groupId>com.github.ulisesbocchio</groupId> <artifactId>jasypt-spring-boot-starter</artifactId> <version>2.1.1</version> </dependency>
2.配置文件application.yaml
#******************加解密相关配置******************* jasypt: encrytor: #用来加解密的salt值 password: 123456 #用来使用新的算法,默认为org.jasypt.salt.NoOPIVGenerator,这样的话我们就无法使用命令行中生成的密文 ivGeneratorClassname: org.jasypt.salt.RandomIVGenerator
参数解释:
- password:加密时候要使用salt值
- 对于ivGeneratorClassname,jasypt包中封装类默认为org.jasypt.salt.NoOpIVGenerator,这个时候我们如果使用Junit生成密文,那么只会生成24位密钥,与命令行中用命令生成的不一样,后面会详细讲解。
3.代码解析
首先我们需要知道的事加解密的方法,只有知道了如何加密才能够在配置文件中设置相关参数的密文,这里涉及到两种方式的加密:
3.1.命令行加密
如果我们项目上线了,需要修改配置文件中的信息,这个时候我们可能要通过命令行的方式去加密(前提:保证你的salt值和你的项目中定义的一致)
进入jasypt-1.9.4.jar文件夹,运行cmd命令:
加密: java -cp jasypt-1.9.4.jar org.jasypt.intf.cli.JasyptPBEStringEncryptionCLI input=pass1234 password=12345 algorithm=PBEWithMD5AndDES
参数说明:
- input:加上需要加密的明文
- password:加上salt值(需要和项目中的application.yaml的password 一致)
- algorithm:加上加密算法(默认使用的就是PBEWithMD5AndDES)
这个时候我们可以看到下面的加密结果:
D:\soft\worksoft\jar> java -cp jasypt-1.9.4.jar org.jasypt.intf.cli.JasyptPBEStringEncryptionCLI input=pass1234 password=12345 algorithm=PBEWithMD5AndDES ----ENVIRONMENT----------------- Runtime: Oracle Corporation Java HotSpot(TM) 64-Bit Server VM 25.111-b14 ----ARGUMENTS------------------- algorithm: PBEWithMD5AndDES input: pass1234 password: 12345 ----OUTPUT---------------------- 5KXYRZgB7CLVpXid457tHS3+ZdkDdRx/jdzE1TEa/l1V5qczBWR21Q== D:\soft\worksoft\jar>
下面的output中就是我们对明文pass1234使用salt值为12345加密的结果
解密:java -cp jasypt-1.9.4.jar org.jasypt.intf.cli.JasyptPBEStringDecryptionCLI input=pdFVCKrYnVOkTpeJ+081g70kzVWV2aLrTOK2EjrJkkSNMbu4C4IX+Q== password=12345 algorithm=PBEWithMD5AndDES
这个时候我们可以看到解密结果:
D:\soft\worksoft\jar>java -cp jasypt-1.9.4.jar org.jasypt.intf.cli.JasyptPBEStringDecryptionCLI input=5KXYRZgB7CLVpXid457tHS3+ZdkDdRx/jdzE1TEa/l1V5qczBWR21Q== password=12345 algorithm=PBEWithMD5AndDES ----ENVIRONMENT----------------- Runtime: Oracle Corporation Java HotSpot(TM) 64-Bit Server VM 25.111-b14 ----ARGUMENTS------------------- algorithm: PBEWithMD5AndDES input: 5KXYRZgB7CLVpXid457tHS3+ZdkDdRx/jdzE1TEa/l1V5qczBWR21Q== password: 12345 ----OUTPUT---------------------- pass1234 D:\soft\worksoft\jar>
3.2.在eclipse中用Junit运行代码对明文加密解密
前提已经在配置文件中配置了jasypt相关信息
jasypt提供了封装类StringEncryptor,可以通过代码来加解密,我们可以使用这个类运行相关方法
Junit相关代码:
import org.jasypt.encryption.StringEncryptor; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import static sun.plugin.javascript.navig.JSType.Embed; @RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest public class JasyptTest { @Autowired StringEncryptor encryptor; //加密 @Test public void getPass(){ String name = encryptor.encrypt("hello"); System.out.println("加密结果:"+name);//解密 @Test public void passDecrypt(){ String username = encryptor.decrypt("7uBC9fVLpL05ipEPzgsDT6Qcjuq9HvDYc0VUIgP4hY="); System.out.println("解密结果:"+username); } }
运行结果如下:
这个时候我们就得到了想要的密文,直接粘贴到配置文件中即可
使用方法如下:
I.在配置文件application.yaml相关位置把明文替换成密文,用ENC()包裹:
************** 加解密相关测试配置信息*************** test: code: username: ENC(pdFVCKrYnVOkTpeJ+081g70kzVWV2aLrTOK2EjrJkkSNMbu4C4IX+Q==)
II.在相应的位置直接读取使用即可,下面我们写一个controller类测试一下运行解密的效果:
import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @Controller public class JasyptController { @Value("${cmd.username}") private String cmdUsername; @RequestMapping("/hello") public String testJasypt() { return cmdUserName; } }
这个时候我们启动项目就能够看到我们再配置中设置的密文对应的明文。至此配置文件的加解密的使用方法就介绍完了。
4.补充说明
对于上述配置文件中的ivGeneratorClassname再进行一个详细的介绍
对于上述的Junit中使用的StringEncryptor封装类,他是可以通过读取配置文件中的信息进行加解密相关参数进行初始化,通过阅读源码,我们可以发现,初始化config的时候会跳转到如下的地方进行设置:
如果在配置参数中没有设置ivGeneratorClassname,那么默认就是org.jasypt.salt.NoOpIVGenerator,那么在运行加解密的时候就会生成一个24位的密文,如图:
但是我们可以看到上面用命令行生成的却比这个长,这个时候如果我们把命令行中生成的密文粘贴到配置文件中则springboot就会启动不了,Junit也会报错解析,把这个密文用命令解析发现也会报错。
这个说明命令行中的加解密不是通过StringEncryptor类来操作的,那是走那边的呢?
通过查阅资料我们发现了下面的代码:
package cn.linjk.ehome; import org.jasypt.encryption.pbe.StandardPBEStringEncryptor; import org.jasypt.encryption.pbe.config.EnvironmentPBEConfig; import org.junit.Test; public class JasyptTest { @Test public void testEncrypt() throws Exception { StandardPBEStringEncryptor standardPBEStringEncryptor = new StandardPBEStringEncryptor(); EnvironmentPBEConfig config = new EnvironmentPBEConfig(); config.setAlgorithm("PBEWithMD5AndDES"); // 加密的算法,这个算法是默认的 config.setPassword("12345"); // 加密的密钥 standardPBEStringEncryptor.setConfig(config); String plainText = "hello"; String encryptedText = standardPBEStringEncryptor.encrypt(plainText); System.out.println(encryptedText); } }
这个时候我们运行一下,得到下面的结果:
把这个密文用命令进行解密发现也是成功的,查看源码(下图):
命令行入口是:JasyptPBEStringDecryptionCLI,这个类里的main入口函数里调用了service.decrypt方法,跟进去是JasyptStatelessService.decrypt()方法如下:
再接着看StandardPBEStringEncryptor的initialize()方法,当没有设置ivGeneratorClassname那么默认就会new RandomIVGenerator,就是这一步导致了生成了不一样的密文:
综上所述,结合场景,如果我们是项目需要上线了,不方便运行Junit去生成密文,填入配置文件,需要用命令行对明文加密,那一定要在配置文件中设置ivGeneratorClassname值!!!
其他配置项
Key | Required | Default Value |
---|---|---|
jasypt.encryptor.password | True | 盐值,根密码 |
jasypt.encryptor.algorithm | False | PBEWithMD5AndDES |
jasypt.encryptor.keyObtentionIterations | False | 1000 |
jasypt.encryptor.poolSize | False | 1 |
jasypt.encryptor.providerName | False | SunJCE |
jasypt.encryptor.providerClassName | False | null |
jasypt.encryptor.saltGeneratorClassname | False | org.jasypt.salt.RandomSaltGenerator |
jasypt.encryptor.ivGeneratorClassname | False | org.jasypt.salt.NoOpIVGenerator |
jasypt.encryptor.stringOutputType | False | base64 |
jasypt.encryptor.proxyPropertySources | False | false |
- The only property required is the encryption password, the rest could be left to use default values. While all this properties could be declared in a properties file, the encryptor password should not be stored in a property file, it should rather be passed as system property, command line argument, or environment variable and as far as its name is jasypt.encryptor.password it'll work.
- The last property, jasypt.encryptor.proxyPropertySources is used to indicate jasyp-spring-boot how property values are going to be intercepted for decryption. The default value, false uses custom wrapper implementations of PropertySource, EnumerablePropertySource, and MapPropertySource. When true is specified for this property, the interception mechanism will use CGLib proxies on each specific PropertySource implementation. This may be useful on some scenarios where the type of the original PropertySource must be preserved.
- The property jasypt.encryptor.ivGeneratorClassname defaults to NoOpIVGenerator for backwards compatibility. However, if you would like to use the newer algorithms in Java 8+ (e.g. PBEWITHHMACSHA512ANDAES_256) you must set this value to org.jasypt.salt.RandomIVGenerator.
运维说明
为了方便运维人员对各类敏感密钥进行加密操作,提供了自动化脚本,方便生成相应的加密串。
密钥(盐值)存储说明
本身加解密过程都是通过
盐值
进行处理的,所以正常情况下盐值
和加密串
是分开存储的。盐值
应该放在系统属性
、命令行
或是环境变量
来使用,而不是放在配置文件。
命令行示例
java -jar xxx.jar --jasypt.encryptor.password=xxx &
环境变量示例
设置环境变量:
# 打开/etc/profile文件 vim /etc/profile # 文件末尾插入 export JASYPT_PASSWORD = xxxx
启动命令:
java -jar xxx.jar --jasypt.encryptor.password=${JASYPT_PASSWORD} &
bat脚本
为了方便,简单编写了一个bat脚本方便使用。
@echo off set/p input=待加密的明文字符串: set/p password=加密密钥(盐值): echo 加密中...... java -cp jasypt-1.9.2.jar org.jasypt.intf.cli.JasyptPBEStringEncryptionCLI input=%input% password=%password% algorithm=PBEWithMD5AndDES pause
注意:jasypt-1.9.2.jar
文件需要和bat脚本放在相同目录下。此包可直接在示例项目中直接下载。
使用示例:
注意:相应加密串,每次加密的结果是不同的。