# Profile_Encryption **Repository Path**: wubindong/Profile_Encryption ## Basic Information - **Project Name**: Profile_Encryption - **Description**: 通过学习jasypt框架实现加密配置中数据库密码 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2022-10-27 - **Last Updated**: 2025-07-16 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 工程简介 加密配置数据库密码 # 延伸阅读 ## 1. 学习资料 [数据库密码配置项都不加密?心也太大了吧!](https://www.bilibili.com/read/cv5770200)
[springboot使用jasypt对配置文件加密,加密数据库连接](https://blog.csdn.net/UnicornRe/article/details/122948098)
[Springboot项目中应用jasypt进行加解密](https://www.jianshu.com/p/611836e889ba)
## 2. 数据库设计 和配置信息 ### 2.1 创建数据库和用户 ```sql create table database_dev; create user 'student'@'%' identified by '123'; grant all privileges on database_dev.* to 'student'@'%'; ``` ### 2.2 创建数据表格 ```sql create table if not exists student( sname varchar(20) , sage int, sno int unsigned AUTO_INCREMENT primary key); ``` ### 2.3 常规连接数据库配置 ![image-20221027143652153](README.assets/image-20221027143652153.png) 但是根据参考文献可知,这是不安全的。 > 一个程序员把自己公司的项目代码上传到了自己的GitHub仓库里了,结果配置文件忘了处理,导致公司数据库泄露,关键问题是,这个公司还是个酒店管理公司 作者:CodeSheep https://www.bilibili.com/read/cv5770200 出处:bilibili ### 2.4 需要加密信息 哪些信息要加密呢? 一般来说,项目配置文件里,所有涉及信息安全的配置项(或字段)都应该做处理,典型的比如: 1) 用到的数据库、缓存的密码 2) 用到的中间件、消息队列的密码 3) 用到的各种第三方服务的Access_Key ......等等 ### 2.5 加密配置项需要依赖 ```xml com.github.ulisesbocchio jasypt-spring-boot-starter 3.0.4 ``` ### 2.6 让加密更安全 (配置信息) #### 1. 用自定义的前后缀 (本次选择) ```properties # 配置加密密钥 (通过配置文件创建) #jasypt.encryptor.password=CodeSheep # 加密字段就可以放在 自定义的 prefix 和 suffix 之间 jasypt.encryptor.property.prefix=^BONC[ jasypt.encryptor.property.suffix=] # 测试的数据库用户名&密码: student 123 spring.datasource.username=student spring.datasource.password=^BONC[+e42ZQMaDpGJwmEnaXT//zUl/CXRE0SfMD2OKri/zckVaFBaZ3xzEFSY1Stl1XYo] ``` #### 2. 使用自定义加密器 (本次选择) 上文实验加密时,使用的是默认的加密规则,这一点会让当自定义加密密钥泄漏时可能变得不安全。为此我们可以自定义加密规则。 //配置生成密钥的代码:对应jasypt.encryptor.password ```java package com.example.profile_encryption.config; import lombok.extern.slf4j.Slf4j; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import java.security.InvalidKeyException; import java.security.Key; import java.security.NoSuchAlgorithmException; import java.security.SignatureException; import java.util.Formatter; /** * HMAC(Hash Message Authentication Code,散列消息鉴别码) * 使用一个密钥生成一个固定大小的小数据块,即MAC,并将其加入到消息中,然后传输。接收方利用与发送方共享的密钥进行鉴别认证, */ @Slf4j public class ShaConfig { private static final String HASH_ALGORITHM = "HmacSHA256"; //加密接口 public static String getAfterSha(String str,String key){ String afterShaString = ""; try { afterShaString = hashMac(str, key); } catch (SignatureException e) { log.error("获取加密字符串失败,",e); } return afterShaString; } /** * hashMac Method that encrypt the data and convert into hex values... HMAC加密 * @param text 消息 * @param secretKey 密钥 * @return 加密后字符串 * @throws SignatureException */ public static String hashMac(String text, String secretKey) throws SignatureException { try { Key sk = new SecretKeySpec(secretKey.getBytes(), HASH_ALGORITHM); Mac mac = Mac.getInstance(sk.getAlgorithm()); mac.init(sk); // 初始化mac final byte[] hmac = mac.doFinal(text.getBytes()); return toHexString(hmac); } catch (NoSuchAlgorithmException e1) { throw new SignatureException( "error building signature, no such algorithm in device " + HASH_ALGORITHM); } catch (InvalidKeyException e) { throw new SignatureException( "error building signature, invalid key " + HASH_ALGORITHM); } } //toHexString Method... public static String toHexString(byte[] bytes) { StringBuilder sb = new StringBuilder(bytes.length * 2); Formatter formatter = new Formatter(sb); for (byte b : bytes) { formatter.format("%02x", b); } return sb.toString(); } } ``` //返回自定义加密器 ```java package com.example.profile_encryption.config; import org.jasypt.encryption.StringEncryptor; import org.jasypt.encryption.pbe.PooledPBEStringEncryptor; import org.jasypt.encryption.pbe.config.SimpleStringPBEConfig; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class EncryptorCfg { //加密算法 private static final String ALGRI = "PBEWITHHMACSHA512ANDAES_256"; //哈希迭代次数 private static final String ITERATIONS = "10000"; private static final String worKey = "work_key_value"; private static final String rootKey = "root_key_value"; private String buildKey() { return SHAConfig.getAfterSha(rootKey, worKey); } @Bean(name = "jasyptStringEncryptor") public StringEncryptor setConfig() { PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor(); SimpleStringPBEConfig config = new SimpleStringPBEConfig(); config.setPassword(buildKey());//自定义加密密钥, //config.setPassword("abcd1234");//自定义加密密钥, config.setAlgorithm(ALGRI);//设置加密算法 config.setKeyObtentionIterations(ITERATIONS);//设置应用于获取加密密钥的哈希迭代次数 config.setPoolSize("1");//设置要创建的加密程序池的大小 config.setProviderName("SunJCE");//设置要请求加密算法的安全提供程序的名称 config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");//设置 Sal 发生器 config.setIvGeneratorClassName("org.jasypt.iv.RandomIvGenerator");//设置 IV 发生器 config.setStringOutputType("base64");//设置字符串输出的编码形式 encryptor.setConfig(config); return encryptor; } } ``` 注意这里Bean的名字name是需要显式指定的(默认的名字是jasyptStringEncryptor),如果像这里一样用的自定义名字,则还需要在Spring Boot的application.properties配置文件中来指定bean的名字 #### 3. 不想用自定义的生产密钥,可以在运行时导入(供下次参考选择) 直接将加密密钥从配置文件中拿掉,取而代之的有三种方式: 方式一:直接作为程序启动时的命令行参数来带入 ![img](README.assets/71b32c76d3cdf1339ff208b9b0fdc12a5970016f.png@942w_87h_progressive.webp) 方式二:直接作为程序启动时的应用环境变量来带入 ![img](README.assets/3b8f4de577a534bf9fffe0bd206b520c5e831664.png@942w_83h_progressive.webp) 方式三:甚至可以作为系统环境变量的方式来带入 比方说,我们提前设置好系统环境变量JASYPT_ENCRYPTOR_PASSWORD = CodeSheep,则直接在Spring Boot的项目配置文件中做如下配置即可: ![img](README.assets/2f648c38f61dc0e85335b11c01d2d5e0b856a1ea.png@942w_81h_progressive.webp) ### 2.7 遇到问题 (缺少操作的发生的问题) ```text Description: Failed to bind properties under 'spring.datasource.password' to java.lang.String: Reason: either 'jasypt.encryptor.password', one of ['jasypt.encryptor.private-key-string', 'jasypt.encryptor.private-key-location'] for asymmetric encryption, or one of ['jasypt.encryptor.gcm-secret-key-string', 'jasypt.encryptor.gcm-secret-key-location', 'jasypt.encryptor.gcm-secret-key-password'] for AES/GCM encryption must be provided for Password-based or Asymmetric encryption Action: Update your application's configuration Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'studentController': Unsatisfied dependency expressed through field 'studentService'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'studentServiceImpl': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'studentMapper' defined in file [E:\IdeaPlace\backDemo\Profile_Encryption\target\classes\com\example\profile_encryption\mappers\StudentMapper.class]: Unsatisfied dependency expressed through bean property 'sqlSessionFactory'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'sqlSessionFactory' defined in class path resource [org/mybatis/spring/boot/autoconfigure/MybatisAutoConfiguration.class]: Unsatisfied dependency expressed through method 'sqlSessionFactory' parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Hikari.class]: Unsatisfied dependency expressed through method 'dataSource' parameter 0; nested exception is org.springframework.boot.context.properties.ConfigurationPropertiesBindException: Error creating bean with name 'spring.datasource-org.springframework.boot.autoconfigure.jdbc.DataSourceProperties': Could not bind properties to 'DataSourceProperties' : prefix=spring.datasource, ignoreInvalidFields=false, ignoreUnknownFields=true; nested exception is org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under 'spring.datasource.password' to java.lang.String ``` 解决方法:原来是缺少部分操作 1) 在启动类加入注解:@EnableEncryptableProperties ```java @EnableEncryptableProperties @SpringBootApplication(scanBasePackages = "com.example.profile_encryption") @MapperScan({"com.example.profile_encryption.**.*Mapper", "com.example.profile_encryption.mappers"}) public class ProfileEncryptionApplication{ //.... } ``` 2) 配置类EncryptorCfg的setConfig方法注解@Bean需要设置name的值 ```java @Component public class EncryptorCfg { //... @Bean(name = "jasyptStringEncryptor") public StringEncryptor setConfig() { PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor(); SimpleStringPBEConfig config = new SimpleStringPBEConfig(); config.setPassword(buildKey());//自定义加密密钥, 密文加盐 config.setAlgorithm(ALGRI);//设置加密算法 config.setKeyObtentionIterations(ITERATIONS);//设置应用于获取加密密钥的哈希迭代次数 config.setPoolSize("1");//设置要创建的加密程序池的大小 config.setProviderName("SunJCE");//设置要请求加密算法的安全提供程序的名称 config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");//设置 Sal 发生器 config.setIvGeneratorClassName("org.jasypt.iv.RandomIvGenerator");//设置 IV 发生器 config.setStringOutputType("base64");//设置字符串输出的编码形式 encryptor.setConfig(config); return encryptor; } } ```