SpringBoot使用jasypt加密密码等重要信息

笔者日常:这几天笔者换公司了,中途休息了几天,找工作又花了几天,博客这阵子有点落下了。


jasypt简单介绍

       jasypt是国外开发者(@author Daniel Fernández)写的一个对PropertySource资源进行加密保护的依赖工具。我们可以使用其来对一些敏感信息(如:配置文件中的各种账号密码)进行加密保护。


jasypt原理及加解密密钥位置方式说明

原理说明

       jasypt通过实现了BeanFactoryPostProcessor, ApplicationListener<ApplicationEvent>, Ordered接口的EnableEncryptablePropertiesBeanFactoryPostProcessor类对PropertySources进行识别及解密:当识别到某属性值是以jasypt.encryptor.property.prefix指定的前缀(默认值是ENC()开头,并且以jasypt.encryptor.property.suffix指定的后缀(默认值是))结尾的话,那么就会将对应的密文进行解密还原。解密分两种,对对称加密的解密(加密解密时使用相同的jasypt.encryptor.password即可),对非对称加密的解密(加密时使用公钥PublicKey加密,解密时使用私钥PrivateKey解密)。

注:我们在配置文件中填写账号密码时,需要直接填写密文(如何根据明文生成密文,见下文的示例)。

对称加密时,加解密密钥的设置位置及方式

对于对称加密在解密时,需要用到的password,可以在以下位置中进行设置。

  • System(系统)

  • properties file(属性文件)。如,在配置文件中配置:

  • command line arguments(命令行参数)。如,在启动jar包时通过-Djasypt.encryptor.password来指定:

  • environment variable(环境变量)。

    注:此方式和方式二几乎一样,不过方式二是直接将加解密密钥写在了配置文件中,而此方式则是从环境变量中读
            取加解密密钥。
    注:linux的环境变量在/etc/profile文件中进行设置;windows右击我的电脑……环境变量中进行设置。

  • ......

非对称加密时,加解密密钥的设置位置及方式

非对称加密在解密时,需要(在配置文件中)指定私钥,可以直接指定私钥字符串,也可以是.crt、.pem、.der等包含私钥的文件。

  • 直接字符串形式的私钥:

  • 或指定文件证书形式的私钥:


使用示例

准备工作:在pom.xml中,引入jasypt依赖:

<!-- https://mvnrepository.com/artifact/com.github.ulisesbocchio/jasypt-spring-boot-starter -->
<dependency>
    <groupId>com.github.ulisesbocchio</groupId>
    <artifactId>jasypt-spring-boot-starter</artifactId>
    <version>2.1.1</version>
</dependency>

jasypt(对称加密)简单使用示例

第一步设置对称加密的加解密密钥等信息。

# 指定前后缀,被前后缀包围的属性值密文,将会被jasypt识别,并进行解密
jasypt.encryptor.property.prefix=ENC@[
jasypt.encryptor.property.suffix=]

### 对称加密 加解密密钥
jasypt.encryptor.password=hello~JustryDeng!

注:设置前后缀不是必须的,但是对于对称加密来说,jasypt.encryptor.password是必须的,
        而jasypt.encryptor.password又可以不在配置文件中设置,可以在启动jar包时进行设置。

第二步使用对称加密,将重要的明文加密转换为密文。

/**
 * 对称加密, 根据密钥,【明文生成密文】示例
 *
 * @date 2019/7/13 5:04
 */
@Test
public void symmetricTest() {
    // 基础加密器
    BasicTextEncryptor textEncryptor = new BasicTextEncryptor();
    // 设置对称加密的 加解密 密钥
    textEncryptor.setPassword("hello~JustryDeng!");

    String info = "dengshuai";
    log.info("加密前" + info);
    // 加密
    String result = textEncryptor.encrypt(info);
    log.info("加密后" + result);
    // 解密
    String originInfo = textEncryptor.decrypt(result);
    log.info("解密后" + originInfo);
}

注:这里的密钥,一定要和第一步时指定的密钥一模一样。

本人运行方法后,控制台输出:

第三步以加密后得到的密文替换配置文件中原来的明文,并在密文前后加上第一步指定的前后缀。

原:

现:

spring.datasource.url=jdbc:mysql://localhost:3306/demo?characterEncoding=utf8&serverTimezone=GMT%2B8
spring.datasource.username=root
### 使用jasypt加密数据库连接密码示例
# 原密码是dengshuai,假设加密后为xxx,那么此处应填写
# jasypt.encryptor.property.prefix + xxx + jasypt.encryptor.property.suffix
# 本人指定的jasypt.encryptor.property.prefix为 ENC@[,jasypt.encryptor.property.suffix为]
# 对称加密示例
spring.datasource.password=ENC@[MgUhHHMeK3ou6/5Uf5fEt4WE+USpGxPz]
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.hikari.driver-class-name=com.mysql.cj.jdbc.Driver

第四步正常使用即可。

jasypt(非对称加密)简单使用示例

第一步生成一对非对称加密的公钥/私钥。

注:可使用keytool、openssl等工具生成.crt、.der等含公私钥的文件,也可以直接使用Java类
        KeyPairGenerator来生成,如:

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.HashMap;
import java.util.Map;

/**
 * RSA公钥/私钥 工具类
 *
 * 注:此工具类摘录自某个网友,具体的我忘记了,这是之前去网上找的,当时忘记把链接记下来了,深感抱歉。
 * @author JustryDeng
 * @date 2019/7/12 13:19
 */
@SuppressWarnings("unused")
public class KeypairUtil {

    private static final String KEY_ALGORITHM = "RSA";

    private static final String PUBLIC_KEY = "RSAPublicKey";

    private static final String PRIVATE_KEY = "RSAPrivateKey";

    /**
     * 获取公钥
     *
     * @param keyMap 公钥/私钥信息map
     * @return 公钥字符串
     */
    public static String getPublicKey(Map<String, Object> keyMap) {
        Key key = (Key) keyMap.get(PUBLIC_KEY);
        return encryptBase64(key.getEncoded());
    }

    /**
     * 获取私钥
     *
     * @param keyMap 公钥/私钥信息map
     * @return 私钥字符串
     */
    public static String getPrivateKey(Map<String, Object> keyMap) {
        Key key = (Key) keyMap.get(PRIVATE_KEY);
        return encryptBase64(key.getEncoded());
    }

    /**
     * 将byte[]型的密钥转换为String类
     *
     * @param key 公钥/私钥字节数组
     * @return 公钥/私钥字符串
     */
    private static String encryptBase64(byte[] key) {
        return new BASE64Encoder().encodeBuffer(key);
    }

    /**
     * 将String类型的密钥转换为byte[]
     *
     * @param key 公钥/私钥字符串
     * @return 公钥/私钥字节数组
     */
    public static byte[] decryptBase64(String key) throws Exception {
        return new BASE64Decoder().decodeBuffer(key);
    }

    /**
     * RSA是目前最有影响力的公钥加密算法,该算法基于一个十分简单的数论事实:将两个大素数相乘十分容易,
     * 但那时想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥,即公钥,而两个大素数
     * 组合成私钥。公钥是可发布的供任何人使用,私钥则为自己所有,供解密之用。
     * <p>
     * 解密者拥有私钥,并且将由私钥计算生成的公钥发布给加密者。加密都使用公钥进行加密,并将密文发送到
     * 解密者,解密者用私钥解密将密文解码为明文。
     * <p>
     * 以甲要把信息发给乙为例,首先确定角色:甲为加密者,乙为解密者。首先由乙随机确定一个KEY,称之为
     * 密匙,将这个KEY始终保存在机器B中而不发出来;然后,由这个 KEY计算出另一个KEY,称之为公匙。这
     * 个公钥的特性是几乎不可能通过它自身计算出生成它的私钥。接下来通过网络把这个公钥传给甲,甲收到公
     * 钥后,利用公钥对信息加密,并把密文通过网络发送到乙,最后乙利用已知的私钥,就对密文进行解码了。
     * 以上就是RSA算法的工作流程。
     * <p>
     * 算法实现过程为:
     * 1. 随意选择两个大的质数p和q,p不等于q,计算N=pq。
     * 2. 根据欧拉函数,不大于N且与N互质的整数個数為(p-1)(q-1)。
     * 3. 选择一个整数e与(p-1)(q-1)互质,并且e小于(p-1)(q-1)。
     * 4. 用以下这个公式计算d:d× e ≡ 1 (mod (p-1)(q-1))。
     * 5. 将p和q的记录销毁。
     * <p>
     * 以上内容中,(N,e)是公钥,(N,d)是私钥。
     * <p>
     * RSA算法的应用。
     * 1. RSA的公钥和私钥是由KeyPairGenerator生成的,获取KeyPairGenerator的实例后还需要设置其密钥位数。
     *    设置密钥位数越高,加密过程越安全,一般使用1024位。     *
     *    KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
     *    keyPairGen.initialize(1024);
     * 2.公钥和私钥可以通过KeyPairGenerator执行generateKeyPair()后生成密钥对KeyPair,
     *   通过KeyPair.getPublic()和KeyPair.getPrivate()来获取。
     *   动态生成密钥对,这是当前最耗时的操作,一般要2s以上。
     *   KeyPair keyPair = keyPairGen.generateKeyPair();
     *   公钥
     *   PublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
     *   私钥
     *   PrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
     * <p>
     * byte[] publicKeyData = publicKey.getEncoded();
     * byte[] privateKeyData = publicKey.getEncoded();
     * 公钥和私钥都有它们自己独特的比特编码,可以通过getEncoded()方法获取,返回类型为byte[]。
     * 通过byte[]可以再度将公钥或私钥还原出来。
     */
    public static Map<String, Object> initKey() throws Exception {
        // 获取密钥对生成器
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
        // 设置密钥位数
        keyPairGen.initialize(1024);
        // 生成密钥对
        KeyPair keyPair = keyPairGen.generateKeyPair();
        // 公钥
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        // 私钥
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        Map<String, Object> keyMap = new HashMap<>(4);
        keyMap.put(PUBLIC_KEY, publicKey);
        keyMap.put(PRIVATE_KEY, privateKey);
        return keyMap;
    }
    
//    public static void main(String[] args) throws Exception {
//        Map<String, Object> map = initKey();
//        System.out.println(getPublicKey(map) + ".");
//        System.out.println(getPrivateKey(map) + ".");
//    }
}

第二步设置非对称加密的用来对密文进行解密的私钥信息。

# 指定前后缀,被前后缀包围的属性值密文,将会被jasypt识别,并进行解密
jasypt.encryptor.property.prefix=ENC@[
jasypt.encryptor.property.suffix=]

### 非对称加密
# 非对称加密 私钥类型
jasypt.encryptor.privateKeyFormat=PEM
# 非对称加密 私钥
jasypt.encryptor.privateKeyString=MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIxd/gJdD/Ftlo1KQZ87w2HNvFERY4CELDfkn82bPS6LIVXn+JdM3sZkDherWRwBacigO5Qe33d2+A1Gkw/3yTAl/i5IgwAG54aXGmOhzmTCFNXGUEqyFxiWIyaoUNQZBfhw0mr6v+sB3VIpgT8WPbRdjFU/jM8JPDn45KZFrVsVAgMBAAECgYAewiX8LJpmxCXediwlEXqB/wxKE25jZhMueEnQSzk/7rryUS+3L+ANRzWTWDfhnCmrDfmgPpenXQmEFzf4osqSDh1TA+wlBXm2iMjVxz01uI0+CES+4I7AjmsVza4rmO8EUyadjoiBFHHDD3+VjWM+o7Pg33L6Hr5dPjEcXU5GrQJBAO8baqlc+1Qvbjb7CHx0U4tx+I204ehFYpQT5vqk89atxqLjMn8QgTA5cFZwQ5V7+uBR+6ZnTlDh3DDrVxZYCOcCQQCWSLoUkN5ljgsaoUMmlQA6vKFVlA/5Oaul574EDpLtiPZHva/u0pdP2fmnPQebe0sX5ThmeD3Aq0v/p/oX/NCjAkEAs+wah9UK3h9OvRqLGTNjhmO9l8xLzb8gXbLYNTUYsytSdFGoNssRm1steC3D/WEst82ZIm9MFDrQuRLuFkcqcwJAXZRx0qaW5bP6dB2gu+CiYPDeoXRuMenYWZmhd9M/aIwVl3ylldgqgn2f+KSHHSk8DGgeo6gSA+xmiY6mq9MwcwJAE03+ZGbTDJoqmSzOlg/P4ScIZH6dDyeycQB2aHKNblRFHEQEzw6+/bEZh5TxSbV4oBWUQGXRCMlkhRAA/A/oHw==

第三步使用公钥,将重要的明文加密转换为密文。

/**
 * 非对称加密, 利用公钥,将【明文生成密文】示例
 *
 * @date 2019/7/13 5:04
 */
@Test
public void asymmetricTest() {
    SimpleAsymmetricConfig config = new SimpleAsymmetricConfig();
    // 设置密钥类型
    config.setKeyFormat(AsymmetricCryptography.KeyFormat.PEM);
    // 设置用来加密的公钥(注:生成的公钥/私钥可能会有换行,保不保留换行都一样)
    config.setPublicKey("MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCMXf4CXQ/xbZaNSkGfO8NhzbxREWOAhCw35J/Nmz0uiyFV5/iXTN7GZA4Xq1kcAWnIoDuUHt93dvgNRpMP98kwJf4uSIMABueGlxpjoc5kwhTVxlBKshcYliMmqFDUGQX4cNJq+r/rAd1SKYE/Fj20XYxVP4zPCTw5+OSmRa1bFQIDAQAB");
    StringEncryptor encryptor = new SimpleAsymmetricStringEncryptor(config);

    String info = "dengshuai";
    log.info("加密前" + info);
    // 加密
    String result = encryptor.encrypt(info);
    log.info("加密后" + result);
    // 解密
    config.setPrivateKey("MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIxd/gJdD/Ftlo1KQZ87w2HNvFERY4CELDfkn82bPS6LIVXn+JdM3sZkDherWRwBacigO5Qe33d2+A1Gkw/3yTAl/i5IgwAG54aXGmOhzmTCFNXGUEqyFxiWIyaoUNQZBfhw0mr6v+sB3VIpgT8WPbRdjFU/jM8JPDn45KZFrVsVAgMBAAECgYAewiX8LJpmxCXediwlEXqB/wxKE25jZhMueEnQSzk/7rryUS+3L+ANRzWTWDfhnCmrDfmgPpenXQmEFzf4osqSDh1TA+wlBXm2iMjVxz01uI0+CES+4I7AjmsVza4rmO8EUyadjoiBFHHDD3+VjWM+o7Pg33L6Hr5dPjEcXU5GrQJBAO8baqlc+1Qvbjb7CHx0U4tx+I204ehFYpQT5vqk89atxqLjMn8QgTA5cFZwQ5V7+uBR+6ZnTlDh3DDrVxZYCOcCQQCWSLoUkN5ljgsaoUMmlQA6vKFVlA/5Oaul574EDpLtiPZHva/u0pdP2fmnPQebe0sX5ThmeD3Aq0v/p/oX/NCjAkEAs+wah9UK3h9OvRqLGTNjhmO9l8xLzb8gXbLYNTUYsytSdFGoNssRm1steC3D/WEst82ZIm9MFDrQuRLuFkcqcwJAXZRx0qaW5bP6dB2gu+CiYPDeoXRuMenYWZmhd9M/aIwVl3ylldgqgn2f+KSHHSk8DGgeo6gSA+xmiY6mq9MwcwJAE03+ZGbTDJoqmSzOlg/P4ScIZH6dDyeycQB2aHKNblRFHEQEzw6+/bEZh5TxSbV4oBWUQGXRCMlkhRAA/A/oHw==");
    String originInfo = encryptor.decrypt(result);
    log.info("解密后" + originInfo);
}

提示:本人这里为了看是否加密解密后得到的明文与加密前的明文一致,所以代码中把解密也写出来了。

本人运行方法后,控制台输出(此图过长,本人只截取了部分):

第四步以加密后得到的密文替换配置文件中原来的明文,并在密文前后加上第一步指定的前后缀。

原:

现:

spring.datasource.url=jdbc:mysql://localhost:3306/demo?characterEncoding=utf8&serverTimezone=GMT%2B8
spring.datasource.username=root
### 使用jasypt加密数据库连接密码示例
# 原密码是dengshuai,假设加密后为xxx,那么此处应填写
# jasypt.encryptor.property.prefix + xxx + jasypt.encryptor.property.suffix
# 本人指定的jasypt.encryptor.property.prefix为 ENC@[,jasypt.encryptor.property.suffix为]
# 非对称加密示例
spring.datasource.password=ENC@[Uji3dGx89KrSaQJmQaKO/SBgA+oUEBlvfkIzkxxbyFdGv9ddPrm7F277BJYZzi5R8UGd0hGy4Pcjva1C+B1H9GFQwm5cbpVCiAp41tcvBq+CHtgd+nuD2nTkqL5HaouGL1vCkGDMsRIozyrNK4re9TMX/6ZkF8B18hlm1uCBcAE=]
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.hikari.driver-class-name=com.mysql.cj.jdbc.Driver

第五步正常使用即可。

 

^_^ 如有不当之处,欢迎指正

^_^ 参考链接
              
https://github.com/ulisesbocchio/jasypt-spring-boot

^_^ 测试代码托管链接
              
https://github.com/JustryDeng/Com.../Abc_Jasypt_Demo

^_^ 本文已经被收录进《程序员成长笔记(五)》,笔者JustryDeng

  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Jasypt(Java Simplified Encryption)是一个Java加密库,它可以用来加密/解密文本、哈希密码等。Spring Boot提供了对Jasypt的支持,可以在应用程序中轻松使用Jasypt加密敏感信息。下面是使用Jasypt对MySQL配置文件进行加密的步骤: 1. 引入Jasypt依赖 在pom.xml文件中添加以下依赖: ```xml <dependency> <groupId>com.github.ulisesbocchio</groupId> <artifactId>jasypt-spring-boot-starter</artifactId> <version>2.2.0</version> </dependency> ``` 2. 配置加密 在application.properties或者application.yml中添加以下配置: ```properties jasypt.encryptor.password=your_password ``` 其中,your_password是用来加密敏感信息密码。 3. 加密MySQL配置信息 在application.properties或者application.yml中加入MySQL配置信息,如下: ```properties spring.datasource.url=jdbc:mysql://localhost:3306/test spring.datasource.username=root spring.datasource.password=root ``` 将密码部分使用Jasypt进行加密,如下: ```properties spring.datasource.url=jdbc:mysql://localhost:3306/test spring.datasource.username=root spring.datasource.password=ENC(加密后的密码) ``` 其中,加密后的密码可以使用Jasypt提供的加密工具进行加密。例如,我们可以使用以下命令生成加密后的密码: ``` java -cp jasypt-1.9.2.jar org.jasypt.intf.cli.JasyptPBEStringEncryptionCLI input="root" password="your_password" algorithm=PBEWithMD5AndDES ``` 其中,jasypt-1.9.2.jar是Jasypt的jar包,your_password是用来加密敏感信息密码。执行以上命令后,会输出加密后的密码。 4. 配置解密 在启动应用程序时,Spring Boot会自动解密加密的敏感信息。因此,我们不需要任何额外的配置来解密MySQL密码。只需将加密后的密码放入配置文件即可。 至此,我们已经成功地使用Jasypt对MySQL配置文件进行了加密
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值