使用场景
在微服务架构中,配置管理是一个重要的问题。通常,我们会在配置文件中存放一些敏感信息,如数据库连接字符串、API 密钥等。这些敏感信息如果明文存储在配置文件中,存在较大的安全隐患。为了提高安全性,我们需要对这些敏感信息进行加密。jasypt-spring-boot
是一个简单而强大的库,可以帮助我们在 Spring Boot
应用中轻松实现配置文件的加密和解密。
开源地址:https://github.com/ulisesbocchio/jasypt-spring-boot
jasypt简介
- Jasypt(Java Simplified Encryption)是一个专注于简化Java加密操作的开源工具。它提供了一种简单而强大的方式来处理数据的加密和解密,使开发者能够轻松地保护应用程序中的敏感信息,如数据库密码、API密钥等。
- Jasypt的设计理念是简化加密操作,使其对开发者更加友好。它采用密码学强度的加密算法,支持多种加密算法,从而平衡了性能和安全性。其中,Jasypt的核心思想之一是基于密码的加密(Password Based Encryption,PBE),通过用户提供的密码生成加密密钥,然后使用该密钥对数据进行加密和解密。此外,Jasypt还引入了盐(Salt)的概念,通过添加随机生成的盐值,提高了加密的安全性,防止相同的原始数据在不同的加密过程中产生相同的结果,有效抵御彩虹表攻击。
- Jasypt的功能非常丰富,包括加密属性文件、Spring Framework集成、加密Hibernate数据源配置、URL加密的Apache Wicket集成等。它还可以与Acegi Security(即Spring Security)整合,用于加密任务与应用程序,如加密密码、敏感信息和数据通信,以及创建完整检查数据的sums等。此外,Jasypt还提供了一个开放的API,使得任何Java Cryptography Extension都可以使用它。
- 在Spring Boot应用中,Jasypt Spring Boot Starter是一个方便的集成工具,可以简化加密功能的配置。它支持多种加密算法,包括对称加密和非对称加密,可以根据实际需求选择合适的加密方式。通过使用Jasypt Spring Boot Starter,可以轻松地将加密功能集成到Spring Boot应用中,无需手动配置复杂的加密相关的代码和配置文件。
jasypt的优点
- 提供简单的单向(摘要)和双向加密技术。
- 用于任何JCE提供程序的开放API,而不仅仅是默认的Java VM提供程序。
- 为您的用户密码提供更高的安全性。
- 二进制加密支持。Jasypt允许对二进制文件(字节数组)进行摘要和加密。
- 数值加密支持。除了文本和二进制文件,它还允许对数值进行摘要和加密(BigInteger和BigDecimal,加密Hibernate持久性时支持其他数字类型)。
- 完全线程安全。
- 支持加密/摘要池,以在多处理器/多核系统中实现高性能。
- 包括库的轻量级(“精简”)版本,以便在移动平台等大小受限的环境中具有更好的可管理性。
SpringBoot
使用jasypt
1.建表语句、数据库数据
CREATE TABLE `emp` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(16) COLLATE utf8mb4_general_ci NOT NULL,
`gender` enum('male','female') COLLATE utf8mb4_general_ci NOT NULL,
`age` int NOT NULL,
`salary` float(10,2) DEFAULT NULL,
`dep` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL,
`notes` varchar(64) COLLATE utf8mb4_general_ci DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
INSERT INTO `mytools`.`emp` (`id`, `name`, `gender`, `age`, `salary`, `dep`, `notes`) VALUES (1, '关羽', 'male', 20, 8000.00, '技术部', NULL);
INSERT INTO `mytools`.`emp` (`id`, `name`, `gender`, `age`, `salary`, `dep`, `notes`) VALUES (2, '张飞', 'male', 25, 12000.00, '技术部', NULL);
INSERT INTO `mytools`.`emp` (`id`, `name`, `gender`, `age`, `salary`, `dep`, `notes`) VALUES (3, '赵云', 'male', 19, 6800.00, '技术部', NULL);
INSERT INTO `mytools`.`emp` (`id`, `name`, `gender`, `age`, `salary`, `dep`, `notes`) VALUES (4, '马超', 'male', 26, 11000.00, '技术部', NULL);
INSERT INTO `mytools`.`emp` (`id`, `name`, `gender`, `age`, `salary`, `dep`, `notes`) VALUES (5, '黄忠', 'female', 48, 15000.00, '技术部', NULL);
INSERT INTO `mytools`.`emp` (`id`, `name`, `gender`, `age`, `salary`, `dep`, `notes`) VALUES (6, '夏侯惇', 'male', 36, 34000.00, '技术部', NULL);
INSERT INTO `mytools`.`emp` (`id`, `name`, `gender`, `age`, `salary`, `dep`, `notes`) VALUES (7, '典韦', 'male', 19, 6500.00, '技术部', NULL);
INSERT INTO `mytools`.`emp` (`id`, `name`, `gender`, `age`, `salary`, `dep`, `notes`) VALUES (8, '吕布', 'female', 20, 9000.00, '技术部', NULL);
INSERT INTO `mytools`.`emp` (`id`, `name`, `gender`, `age`, `salary`, `dep`, `notes`) VALUES (9, '周瑜', 'female', 32, 36000.00, '技术部', NULL);
INSERT INTO `mytools`.`emp` (`id`, `name`, `gender`, `age`, `salary`, `dep`, `notes`) VALUES (10, '文丑', 'male', 27, 24000.00, '技术部', NULL);
INSERT INTO `mytools`.`emp` (`id`, `name`, `gender`, `age`, `salary`, `dep`, `notes`) VALUES (11, '刘备', 'male', 32, 4000.00, '市场部', NULL);
INSERT INTO `mytools`.`emp` (`id`, `name`, `gender`, `age`, `salary`, `dep`, `notes`) VALUES (12, '诸葛亮', 'male', 27, 2700.00, '市场部', NULL);
INSERT INTO `mytools`.`emp` (`id`, `name`, `gender`, `age`, `salary`, `dep`, `notes`) VALUES (13, '庞统', 'male', 37, 4200.00, '市场部', NULL);
INSERT INTO `mytools`.`emp` (`id`, `name`, `gender`, `age`, `salary`, `dep`, `notes`) VALUES (14, '徐庶', 'male', 36, 4000.00, '市场部', NULL);
INSERT INTO `mytools`.`emp` (`id`, `name`, `gender`, `age`, `salary`, `dep`, `notes`) VALUES (15, '荀彧', 'male', 25, 2400.00, '市场部', NULL);
INSERT INTO `mytools`.`emp` (`id`, `name`, `gender`, `age`, `salary`, `dep`, `notes`) VALUES (16, '荀攸', 'male', 25, 2400.00, '市场部', NULL);
INSERT INTO `mytools`.`emp` (`id`, `name`, `gender`, `age`, `salary`, `dep`, `notes`) VALUES (17, '鲁肃', 'male', 43, 4300.00, '市场部', NULL);
INSERT INTO `mytools`.`emp` (`id`, `name`, `gender`, `age`, `salary`, `dep`, `notes`) VALUES (18, '司马懿', 'female', 44, 5000.00, '市场部', NULL);
INSERT INTO `mytools`.`emp` (`id`, `name`, `gender`, `age`, `salary`, `dep`, `notes`) VALUES (19, '杨修', 'male', 19, 800.00, '市场部', NULL);
INSERT INTO `mytools`.`emp` (`id`, `name`, `gender`, `age`, `salary`, `dep`, `notes`) VALUES (20, '丁仪', 'male', 49, 3500.00, '市场部', NULL);
INSERT INTO `mytools`.`emp` (`id`, `name`, `gender`, `age`, `salary`, `dep`, `notes`) VALUES (21, '宋江', 'male', 30, 4000.00, '人事部', NULL);
INSERT INTO `mytools`.`emp` (`id`, `name`, `gender`, `age`, `salary`, `dep`, `notes`) VALUES (22, '吴用', 'male', 38, 3000.00, '人事部', NULL);
INSERT INTO `mytools`.`emp` (`id`, `name`, `gender`, `age`, `salary`, `dep`, `notes`) VALUES (23, '扈三娘', 'female', 42, 2500.00, '人事部', NULL);
INSERT INTO `mytools`.`emp` (`id`, `name`, `gender`, `age`, `salary`, `dep`, `notes`) VALUES (24, '顾大嫂', 'female', 38, 3300.00, '人事部', NULL);
INSERT INTO `mytools`.`emp` (`id`, `name`, `gender`, `age`, `salary`, `dep`, `notes`) VALUES (25, '孙二娘', 'female', 32, 2400.00, '人事部', NULL);
INSERT INTO `mytools`.`emp` (`id`, `name`, `gender`, `age`, `salary`, `dep`, `notes`) VALUES (26, '丁得孙', 'male', 32, 2800.00, '人事部', NULL);
INSERT INTO `mytools`.`emp` (`id`, `name`, `gender`, `age`, `salary`, `dep`, `notes`) VALUES (27, '柴进', 'male', 30, 4200.00, '财务部', NULL);
INSERT INTO `mytools`.`emp` (`id`, `name`, `gender`, `age`, `salary`, `dep`, `notes`) VALUES (28, '卢俊义', 'male', 44, 4000.00, '财务部', NULL);
2.在pom.xml引入依赖包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>3.5.5</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--jasypt依赖-->
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot-starter</artifactId>
<version>3.0.5</version>
</dependency>
jasypt-spring-boot-3.0.5
底层使用jasypt-1.9.3
。在引入jasypt-spring-boot后,相关依赖包会自动引入。
3.配置数据库文件(先不进行加密)
spring:
datasource:
url: jdbc:mysql://localhost:3306/mytools?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 123456
4.java代码
enrtity
package com.zhubayi.jasyptdemo.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
/**
* @author zhubayi
* @Description
*/
@TableName(value = "emp")
public class Emp {
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
@TableField(value = "`name`")
private String name;
@TableField(value = "gender")
private Object gender;
@TableField(value = "age")
private Integer age;
@TableField(value = "salary")
private Double salary;
@TableField(value = "dep")
private String dep;
@TableField(value = "notes")
private String notes;
/**
* @return id
*/
public Integer getId() {
return id;
}
/**
* @param id
*/
public void setId(Integer id) {
this.id = id;
}
/**
* @return name
*/
public String getName() {
return name;
}
/**
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* @return gender
*/
public Object getGender() {
return gender;
}
/**
* @param gender
*/
public void setGender(Object gender) {
this.gender = gender;
}
/**
* @return age
*/
public Integer getAge() {
return age;
}
/**
* @param age
*/
public void setAge(Integer age) {
this.age = age;
}
/**
* @return salary
*/
public Double getSalary() {
return salary;
}
/**
* @param salary
*/
public void setSalary(Double salary) {
this.salary = salary;
}
/**
* @return dep
*/
public String getDep() {
return dep;
}
/**
* @param dep
*/
public void setDep(String dep) {
this.dep = dep;
}
/**
* @return notes
*/
public String getNotes() {
return notes;
}
/**
* @param notes
*/
public void setNotes(String notes) {
this.notes = notes;
}
}
mapper
@Mapper
public interface EmpMapper extends BaseMapper<Emp> {
}
service
import com.zhubayi.jasyptdemo.entity.Emp;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* @author zhubayi
* @Description
*/
public interface EmpService extends IService<Emp>{
}
serviceImpl
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zhubayi.jasyptdemo.mapper.EmpMapper;
import com.zhubayi.jasyptdemo.entity.Emp;
import com.zhubayi.jasyptdemo.service.EmpService;
/**
* @author zhubayi
* @Description
*/
@Service
public class EmpServiceImpl extends ServiceImpl<EmpMapper, Emp> implements EmpService{
}
controller
package com.zhubayi.jasyptdemo.controller;
import com.zhubayi.jasyptdemo.entity.Emp;
import com.zhubayi.jasyptdemo.service.EmpService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* @author zhubayi
* @Description
*/
@RestController
@RequestMapping("/emp")
public class EmpController {
@Autowired
private EmpService empService;
@GetMapping("/list")
public List<Emp> list(){
return empService.list();
}
}
5.访问接口
地址:http://127.0.0.1:8080/emp/list
6.配置文件加密
jasypt:
encryptor:
# 采用的加密算法
algorithm: PBEWITHHMACSHA512ANDAES_256
# 盐粒
password: zhujjtest
property:
prefix: ENC(
suffix: )
iv-generator-classname: org.jasypt.iv.RandomIvGenerator
6.1通过测试获取加密后的数据
@Autowired
StringEncryptor stringEncryptor;
@Test
void contextLoads() {
String url = stringEncryptor.encrypt("jdbc:mysql://localhost:3306/mytools?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false");
String username = stringEncryptor.encrypt("root");
String password = stringEncryptor.encrypt("123456");
System.out.println("url="+url);
System.out.println("username="+username);
System.out.println("password="+password);
}
加密后的数据我们已经能够看到了,我现在把这些数据替换到我的application.yml
配置文件中。
spring:
datasource:
#url: jdbc:mysql://localhost:3306/mytools?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false
driver-class-name: com.mysql.cj.jdbc.Driver
#username: root
#password: 123456
url: ENC(G08+puraFnKtP+WHbADjcmocESS5BzqDUgh1D8I143HP/JgFLkq6gO8Jcnv7Nk60vgU00VPzz1SgeJa7KIv8yQNJK/OKDnZwZkxio/IOiirbBInNzEAv/Ef/ghCEezmavFQcg8+JA/KzZnsb4nHEY2zlmkyZVz4zKO208PUPNpUiv4QZKsgVbOIC6t0V8GZX)
username: ENC(LbX/6n3o6Qjw+DXpjYvKGpohvPChCrCQSke0tEowvz+Us3V8KpzwVg0iNjbjyzS8)
password: ENC(aFeYlEWNtZVBjEoZCM3Yw+ownuAs/kNNnwFvkZfMRza2PTgtCFOL4EWQV6vE4rsr)
重启项目再次访问http://127.0.0.1:8080/emp/list
6.2通过build插件
上方给出的方法,虽然我们将数据加密了,但是作为核心的“盐粒”我们却暴露了出来,如果我们不想将“盐粒”暴露呢?那么在你的pom
文件中添加下边的代码。
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-maven-plugin</artifactId>
<!--<version>3.0.5</version>-->
<configuration>
<path>file:src/main/resources/application.yml</path>
</configuration>
</plugin>
</plugins>
</build>
修改配置文件。
jasypt:
encryptor:
# 采用的加密算法
algorithm: PBEWITHHMACSHA512ANDAES_256
# 盐粒
property:
prefix: ENC(
suffix: )
iv-generator-classname: org.jasypt.iv.RandomIvGenerator
spring:
datasource:
url: DEC(jdbc:mysql://localhost:3306/mytools?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false)
username: DEC(root)
password: DEC(123456)
driver-class-name: com.mysql.cj.jdbc.Driver
在项目的根目录运行下方指令。后边的那一串就是你要是用的密钥,我是随便填的。
mvn jasypt:encrypt -Djasypt.encryptor.password=zhujjtest
之后再次点击你的配置文件查看。原始的数据已经被加密了,并且这个加密的“盐粒”只有你知道。
那么接下来在调用mapper
测试接口试试?这里会报红,因为你的配置文件是加密过的,你怎么可能直接去使用一个加密过的数据呢?你必须要先解密,但是你并没有在配置文件当中提供这个“盐粒”,所以你要通过其他的方式把这个“盐粒”添加进去。
idea里面添加
- 编辑启动配置
- 添加虚拟机选项
添加参数
-Djasypt.encryptor.password=zhujjtest
jar包方式添加
把项目打包
之后在target目录下找到我们打包好的项目,打开cmd窗口运行下方指令。(盐粒要改成你自己的)
java -jar 你自己起的包名.jar --jasypt.encryptor.password=zhujjtest
访问网址查看,成功获取到数据