
前言
不難發(fā)現(xiàn),以我們現(xiàn)在的開發(fā)習(xí)慣,無(wú)論是公司的項(xiàng)目還是個(gè)人的項(xiàng)目,都會(huì)選擇將源碼上傳到 Git 服務(wù)器(GitHub、Gitee 或是自建服務(wù)器),但只要將源碼提交到公網(wǎng)服務(wù)器就會(huì)存在源碼泄漏的風(fēng)險(xiǎn),而數(shù)據(jù)庫(kù)配置信息作為源碼的一部分,一旦出現(xiàn)源碼泄漏,那么數(shù)據(jù)庫(kù)中的所有數(shù)據(jù)都會(huì)公之于眾,其產(chǎn)生的不良后果無(wú)法預(yù)期。
于是為了避免這種問題的產(chǎn)生,我們至少要對(duì)數(shù)據(jù)庫(kù)的密碼進(jìn)行加密操作,這樣即使得到了源碼,也不會(huì)造成數(shù)據(jù)的泄露。
怎么實(shí)現(xiàn)加密?
對(duì)于 Java 項(xiàng)目來說,要想快速實(shí)現(xiàn)數(shù)據(jù)庫(kù)的加密,最簡(jiǎn)單可行的方案就是使用阿里巴巴提供的 Druid 來實(shí)現(xiàn)加密。
Druid基本介紹
Druid 是阿里巴巴開源平臺(tái)上的一個(gè)項(xiàng)目,整個(gè)項(xiàng)目由數(shù)據(jù)庫(kù)連接池、插件框架和 SQL 解析器組成,該項(xiàng)目主要是為了擴(kuò)展 JDBC 的一些限制,可以讓程序員實(shí)現(xiàn)一些特殊的需求,比如向密鑰服務(wù)請(qǐng)求憑證、統(tǒng)計(jì) SQL 信息、SQL 性能收集、SQL 注入檢查、SQL 翻譯等,程序員可以通過定制來實(shí)現(xiàn)自己需要的功能。
Druid 是目前最好的數(shù)據(jù)庫(kù)連接池,在功能、性能、擴(kuò)展性方面,都超過其他數(shù)據(jù)庫(kù)連接池,包括 DBCP、C3P0、BoneCP、Proxool、JBoss DataSource。除此以外,Druid 提供了強(qiáng)大的監(jiān)控和擴(kuò)展功能,當(dāng)然也包含了數(shù)據(jù)庫(kù)的加密功能。
Druid 已經(jīng)在阿里巴巴部署了超過 600 個(gè)應(yīng)用,經(jīng)過了很多生產(chǎn)環(huán)境大規(guī)模部署的嚴(yán)苛考驗(yàn)。
同時(shí) Druid 不僅僅是一個(gè)數(shù)據(jù)庫(kù)連接池,它包括四個(gè)部分:
Druid 是一個(gè) JDBC 組件,它包括三個(gè)部分:
基于 Filter-Chain 模式的插件體系。
DruidDataSource 高效可管理的數(shù)據(jù)庫(kù)連接池。
SQLParser
Druid開源地址
Druid的功能點(diǎn)
Druid 可以監(jiān)控?cái)?shù)據(jù)庫(kù)訪問性能,Druid 內(nèi)置提供了一個(gè)功能強(qiáng)大的 StatFilter 插件,能夠詳細(xì)統(tǒng)計(jì) SQL 的執(zhí)行性能,這對(duì)于線上分析數(shù)據(jù)庫(kù)訪問性能有幫助。
替換數(shù)據(jù)庫(kù)連接池 DBCP 和 C3P0,Druid 提供了一個(gè)高效、功能強(qiáng)大、可擴(kuò)展性好的數(shù)據(jù)庫(kù)連接池。
數(shù)據(jù)庫(kù)密碼加密,直接把數(shù)據(jù)庫(kù)密碼寫在配置文件中,這是不好的行為,容易導(dǎo)致安全問題。DruidDruiver 和 DruidDataSource 都支持 PasswordCallback。
SQL 執(zhí)行日志,Druid 提供了不同的 LogFilter,能夠支持 Common-Logging、Log4j 和 JdkLog,你可以按需要選擇相應(yīng)的 LogFilter,監(jiān)控你應(yīng)用的數(shù)據(jù)庫(kù)訪問情況。
擴(kuò)展 JDBC,如果我們要對(duì) JDBC 層有編程的需求,可以通過 Druid 提供的 Filter-Chain 機(jī)制,很方便編寫 JDBC 層的擴(kuò)展插件。
在這里我們僅需要通過它來對(duì)配置文件中的數(shù)據(jù)庫(kù)密碼進(jìn)行加密。
加密執(zhí)行流程
在沒有進(jìn)行密碼加密之前,項(xiàng)目的交互流程:?

在使用了密碼加密之后,項(xiàng)目的交互流程:?

Druid實(shí)現(xiàn)數(shù)據(jù)庫(kù)加密過程
1,添加Druid依賴
這里以SpringBoot項(xiàng)目為例,引入SpringBoot的集成依賴:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.14</version>
</dependency>
2,調(diào)用工具類生成密文
借助Druid中的ConfigTools工具類來加密數(shù)據(jù)庫(kù)對(duì)應(yīng)的密碼:
@Test
void method2() throws Exception {
//定義數(shù)據(jù)庫(kù)密碼,以123456為例
String password = "123456";
//調(diào)用druid的工具類來加密密碼
ConfigTools.main(new String[]{password});
}
執(zhí)行后即可得到如下結(jié)果:
privateKey:MIIBVgIBADANBgkqhkiG9w0BAQEFAASCAUAwggE8AgEAAkEAv5WmBXjC7ysGEz5455YGNiqf52HFTmF/+4efK1bxrXPGNt3idKYXapO3RktjATl2KQhVQo9v9JR98sC8ROrHCQIDAQABAkAtZh7jaQx4dG+KG+G2rzxllZAy2l5RBpW3WxoCwSWf/kfIyNjaNTEQXZAF9a+9JSaII3c8x6+K3vQccVyzoB8BAiEA9nVYs4lJqa4kczuG8J9jgy9LX9UK2vuZKUzMJ/BQ9zkCIQDHAHJU0NIa5McWWwziKhq6BI1Dfje6Jt2cIkFPpBL+UQIhAIkBkt27ZAe/luO4I7t/34H9uJj9hZtWYj5jQtqw7VGBAiEAtTnn5OvC23ELCYXjpreXXV4104hHccRhPwZHGiMelPECIQDp0g+5HMxLTI3EWuHlAOOZfiwCZy0S+uexT2xXGUL/wg==
publicKey:MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAL+VpgV4wu8rBhM+eOeWBjYqn+dhxU5hf/uHnytW8a1zxjbd4nSmF2qTt0ZLYwE5dikIVUKPb/SUffLAvETqxwkCAwEAAQ==
password:daOJOrMQgK7yxCkUW7FRhSmdDFZIqgMmmXfRw5FM/zsNM08Tgdu+I9I/bJ3akSf4w/fV0IjY/qjDE3jBw20tAA==
可以看到執(zhí)行結(jié)果包含3個(gè)部分的內(nèi)容:
privateKey:私鑰,暫時(shí)不會(huì)用到,用于密碼的加密;
publicKey:公鑰,用于密碼的解密;
password:密文,加密之后的密碼。
這里我們主要通過publicKey和password來實(shí)現(xiàn)對(duì)數(shù)據(jù)庫(kù)的加密,將明文密碼轉(zhuǎn)換為密文。
3,添加到y(tǒng)ml配置文件
得到執(zhí)行結(jié)果后,我們需要將公鑰和密文分別添加到項(xiàng)目的yml配置文件中
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
druid:
url: jdbc:mysql://localhost:3306/store_user?useSSL=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
username: root
#生成后的密文
password: daOJOrMQgK7yxCkUW7FRhSmdDFZIqgMmmXfRw5FM/zsNM08Tgdu+I9I/bJ3akSf4w/fV0IjY/qjDE3jBw20tAA==
filters: config
connect-properties:
config.decrypt: true
#生成的公鑰
config.decrypt.key: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAL+VpgV4wu8rBhM+eOeWBjYqn+dhxU5hf/uHnytW8a1zxjbd4nSmF2qTt0ZLYwE5dikIVUKPb/SUffLAvETqxwkCAwEAAQ==
mybatis-plus:
mapper-locations: classpath*:mapper/*.xml
configuration:
map-underscore-to-camel-case: true
auto-mapping-behavior: full
lazy-loading-enabled: true
aggressive-lazy-loading: false
type-aliases-package: com.yy.pojo #設(shè)置別名
注意:但是這樣并不完全安全,當(dāng)我們將密文和公鑰都寫入配置文件,這就會(huì)造成當(dāng)有人拿到密文和公鑰之后,就可以使用 Druid 將加密的密碼還原出來了,這就好比一把插著鑰匙的鎖是極不安全的。
因此我們正確的使用方式是:將公鑰找一個(gè)安全的地方保存起來,每次在項(xiàng)目啟動(dòng)時(shí)動(dòng)態(tài)的將公鑰設(shè)置到項(xiàng)目中,這樣就可以有效的保證密碼的安全了。,
4,優(yōu)化yml配置文件
接下來我們將 Spring Boot 的公鑰設(shè)置為配置項(xiàng),在項(xiàng)目運(yùn)行時(shí)再替換為具體的值,最終的安全配置信息如下:
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
druid:
url: jdbc:mysql://localhost:3306/store_user?useSSL=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
username: root
#生成后的密文
password: daOJOrMQgK7yxCkUW7FRhSmdDFZIqgMmmXfRw5FM/zsNM08Tgdu+I9I/bJ3akSf4w/fV0IjY/qjDE3jBw20tAA==
filters: config
connect-properties:
config.decrypt: true
#生成的公鑰
config.decrypt.key: ${spring.datasource.druid.publicKey}
這里為了保證安全,我們可以將公鑰被修改成“${spring.datasource.druid.publickey}”,這就相當(dāng)于使用占位符去替代公鑰,等項(xiàng)目啟動(dòng)時(shí)再更換上具體的值去執(zhí)行。
注意:“spring.datasource.druid.publickey”并非是固定不可變的 key,此 key 值用戶可自行定義。
啟動(dòng)測(cè)試
開發(fā)環(huán)境中只需要在 Idea 的啟動(dòng)參數(shù)中配置公鑰的值即可,如下圖所示:

當(dāng)我們輸入正確的公鑰值時(shí)程序可以正常運(yùn)行,當(dāng)輸入一個(gè)錯(cuò)誤的公鑰值時(shí)就會(huì)提示解碼失敗,如下圖所示:

生產(chǎn)環(huán)境下啟動(dòng)時(shí),我們可以動(dòng)態(tài)的設(shè)置公鑰的值即可。如下:
java -jar xxx.jar --spring.datasource.druid.publickey=公鑰值
最后測(cè)試數(shù)據(jù)庫(kù)操作,可以對(duì)數(shù)據(jù)庫(kù)數(shù)據(jù)進(jìn)行正常訪問,加密操作成功。

這樣,我們就完成 MySQL 密碼的加密了,當(dāng) Spring Boot 項(xiàng)目啟動(dòng)時(shí),Druid 的攔截器會(huì)使用密文和公鑰將密碼還原成真實(shí)的密碼以供項(xiàng)目使用,當(dāng)然這一切都無(wú)需人工干預(yù)(無(wú)需編寫任何代碼),Druid 已經(jīng)幫我們封裝好了,我們只需要通過以上配置即可。
后記
這里補(bǔ)充一句:上面提到了,我們不建議直接將公鑰值填在yml文件中,因?yàn)闀?huì)造成密碼泄露的風(fēng)險(xiǎn)是有理可循的。這里我們通過Druid工具類做個(gè)還原操作即可證實(shí)這一點(diǎn):
@Test
void method3() throws Exception {
String publicKey="MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAL+VpgV4wu8rBhM+eOeWBjYqn+dhxU5hf/uHnytW8a1zxjbd4nSmF2qTt0ZLYwE5dikIVUKPb/SUffLAvETqxwkCAwEAAQ==";
String pwd="daOJOrMQgK7yxCkUW7FRhSmdDFZIqgMmmXfRw5FM/zsNM08Tgdu+I9I/bJ3akSf4w/fV0IjY/qjDE3jBw20tAA==";
System.out.println(ConfigTools.decrypt(publicKey, pwd));
}
這樣就得到破譯后的原密碼了,這是很危險(xiǎn)的。文章來源:http://www.zghlxwxcb.cn/news/detail-636210.html

所以,當(dāng)公鑰,密文全部顯示配置后,密碼源是能夠被獲取的,那么我們數(shù)據(jù)庫(kù)加密就沒有什么意義了。雖然通過配置啟動(dòng)參數(shù)或jar包啟動(dòng)配置相對(duì)直接運(yùn)行會(huì)麻煩一點(diǎn),但是安全性得到了基本保證,還是可以滴~文章來源地址http://www.zghlxwxcb.cn/news/detail-636210.html
到了這里,關(guān)于Druid連接池實(shí)現(xiàn)數(shù)據(jù)庫(kù)加密的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!