作為程序員每天的開發工作都離不開跟數據庫打交道,而且我們的應用程序往往都會配置數據庫的鏈接,那你有沒有想過,任何一個能接觸到我們項目代碼的人員,都可以看到配置文件里面的賬號秘密?
相信很多人的項目里面配置文件都是類似這樣寫的
############### Mysql配置 ######################### spring.datasource.type=com.zaxxer.hikari.HikariDataSource spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://127.0.0.1:3306/abc?useUnicode=true&characterEncoding=utf-8&useTimezone=true&serverTimezone=GMT%2B8 spring.datasource.username=root spring.datasource.password=123456
spring.datasource.url 中配置了數據庫的鏈接地址和端口,spring.datasource.username 配置了賬號以及spring.datasource.password 中配置了密碼。
如果是這樣的寫法,無非就是在裸奔,任何一個能接觸到這個文件的人,都能夠用 MySQL 的客戶端工具進行數據庫的鏈接,里面的數據毫無安全可言。當然如果是本地或者測試環境都還可以,但是對于生產環境那是不能接受的,畢竟這樣的安全性太差了,一不小心被刪庫跑路還是有可能的。
相對而言,有一些經驗的數據庫運維人員是不會直接提供數據庫服務的 IP 地址和端口的,而是提供域名,通過在 url 地址上面配置相應的域名,然后通過解析域名讓其訪問數據庫服務,域名地址是不對外解析的,所以生產環境的主機以及開發人員的本機,需要進行 hosts 的配置,將域名對應IP 地址配置起來。
這種方式會比上面直接裸奔的形式好一點,外人拿到代碼,沒有 hosts 配置也是不能訪問數據庫的,難度相對來說高了一點。但是這樣也有個問題,那就是開發人員還是可以通過 MySQL 的客戶端進行數據的訪問,如果哪天心情不好,刪庫跑路也不是沒有可能,或者說私自泄露數據也是有機會的。
那么很多小明就問了,有沒有一種方式,可以有效的控制這種情況呢?讓盡量少了人接觸到數據庫的數據,但是同時也不能影響開發的進度,對于開發要友好。
有問題,就會有答案,這個時候我們就需要介紹一款神器了,那就是 jasypt。jasypt 可以幫助我們在配置文件中配置加密后的賬號和密碼,然后結合秘鑰,就可以完全控制數據庫的安全性。下面我們就來試一下吧。
首先有一個需要連接數據庫的 Spring Boot 服務,我們先看一下,在沒有引入 jasypt 的時候,是如何使用的,代碼如下:
############### Mysql配置 ######################### spring.datasource.type=com.zaxxer.hikari.HikariDataSource spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://127.0.0.1:3306/abc?useUnicode=true&characterEncoding=utf-8&useTimezone=true&serverTimezone=GMT%2B8 spring.datasource.username=root spring.datasource.password=123456 #客戶端等待連接池連接的最大毫秒數 spring.datasource.hikari.connection-timeout=20000 #最小空閑連接數 spring.datasource.hikari.minimum-idle=5 #最大連接池大小 spring.datasource.hikari.maximum-pool-size=20 #連接池中空閑的最長時間毫秒 spring.datasource.hikari.idle-timeout=30000 #池中連接關閉后的最長生命周期毫秒 spring.datasource.hikari.max-lifetime=1200000 spring.datasource.hikari.auto-commit=true spring.datasource.hikari.connection-test-query=SELECT 1
UserController.java
package com.controller; import com.mapper.UserEntity; import com.mapper.UserMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.Date; import java.util.List; @RestController @EnableAutoConfiguration @RequestMapping("/user") public class UserController { @Autowired private UserMapper userMapper; @RequestMapping("add") public int addUser(String name, String desc) throws Exception { int id, num = 0; UserEntity u = new UserEntity(0, name, desc, new Date()); num = userMapper.insert(u); id = u.getId(); return id; } @RequestMapping("getlist") public List<UserEntity> listUser() throws Exception { List<UserEntity> UserEntitys = userMapper.getAll(); System.out.println(UserEntitys.toString()); return UserEntitys; } }
UserMapper.java
package com.mapper; import org.apache.ibatis.annotations.*; import java.util.List; /** * @author ziyou */ public interface UserMapper { /** * 查詢操作示例 * * @return */ @Select("SELECT * FROM t_user;") @Results({ @Result(property = "id", column = "Id"), @Result(property = "Name", column = "Name"), @Result(property = "Desc", column = "Desc"), @Result(property = "CreateTime", column = "CreateTime") }) List<UserEntity> getAll(); /** * 插入操作示例 * 將自增ID綁定到實體,keyProperty是實體字段,keyColumn是數據庫字段 * * @param user * @return */ @Insert("INSERT INTO t_user(`Name`,`Desc`,CreateTime) VALUES(#{Name}, #{Desc}, #{CreateTime});") @Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "Id") int insert(UserEntity user); }
另外我們有一張表,表里面的數據是這樣的,接下來我們啟動服務,調用接口查詢表的數據,如下所示
說明在使用明文賬號密碼的時候,整個流程是沒有問題,接下來,我們引入 jasypt ,主要分下面三個步驟
1.引入 pom 依賴
<dependency> <groupId>com.github.ulisesbocchiogroupId> <artifactId>jasypt-spring-boot-starterartifactId> <version>1.18version> dependency>
2.編寫加密工具類
public class JasyptUtil { public static void main(String[] args) { String account = "root"; String password = "123456"; BasicTextEncryptor encryptor = new BasicTextEncryptor(); //秘鑰 //encryptor.setPassword(System.getProperty("jasypt.encryptor.password")); encryptor.setPassword("eug83f3gG"); //密碼進行加密 String newAccount = encryptor.encrypt(account); String newPassword = encryptor.encrypt(password); System.out.println("加密后賬號:" + newAccount); System.out.println("加密后密碼:" + newPassword); } }
因為我們要得到加密后的密文,所以我們先需要根據原始賬號密碼,以及我們指定的秘鑰來生成加密后的密文,這里我們假設本地和測試環境的秘鑰為eug83f3gG,通過上面的工具類,我們可以生成如下的密文
3.替換賬號密碼,我們將 application.properties 里面的賬號密碼用上面的密文替換,如下所示,使用 ENC()包住密文。
############### Mysql配置 ######################### spring.datasource.type=com.zaxxer.hikari.HikariDataSource spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://127.0.0.1:3306/abc?useUnicode=true&characterEncoding=utf-8&useTimezone=true&serverTimezone=GMT%2B8 spring.datasource.username=ENC(/YnTvPH7WnnqMHu+wKeccA==) spring.datasource.password=ENC(Xv829RzVs7pd2sv72/wsbg==)
這里說明三點
- 此時我們還不能正常啟動服務,因為就這樣的話是啟動不成功了,賬號和密碼是錯誤的,我們需要將秘鑰傳入,讓jasypt 給我們反向解析出正確的賬號和密碼才能進行數據庫的鏈接;
- 工具類中的秘鑰保持跟生產環境不一樣!!!
- 使用 ENC() 包住密文;
接下來我們可以將秘鑰通過兩種形式傳進程序中使用,一種是將秘鑰通過系統環境變量的形式進行配置,不過不建議;第二種是通過啟動參數將秘鑰進行傳入;這里我們使用第二種,在 SpringBoot 項目的啟動參數中,我們增加這樣的配置 -Djasypt.encryptor.password=eug83f3gG,然后我們再重啟應用,就可以啟動成功了。
啟動成功了再次訪問上面的接口,可以看到效果是一樣的。
后續在生產環境中,只需要在啟動參數中傳入與本地和測試環境不一樣的秘鑰,就可以有效的防止數據庫的賬號密碼被泄露了,就連開發人員都不知道是什么,只要配置的運維人員知道,這個安全性就高很多了,怎么樣小伙伴你學會了嗎?趕緊在自己的項目中用起來吧!
原文地址:https://mp.weixin.qq.com/s/gGO9tIbCaP9HEfny0tgwTg