背景
最近在做一款資料産品,涉及到資料源。既然是資料源,肯定有URL(含port資訊),使用者名和密碼。頁面上面,雖然有前端元件mask處理,不能複制出來。但是對于稍微懂點技術的同學,都知道去檢視控制台。在我們的産品設計裡面,産品同學沒有考慮到這種安全機制問題;也就是說,在控制台,可以看到明文密碼。
思路
前端隻能做mask處理,控制台看到的資料是後端接口傳回的,故而需要後端來解決這個問題。
不難想到,後端接口在傳回密碼等私密資訊前,加密處理一下;前端拿到什麼資料,就給後端傳輸什麼資料;後續需要使用此密碼資料時,後端需要解密一下。即:加密,再解密。
解決
資料源管理菜單的功能大緻如下,針對每個資料源可以驗證其連通性:
點選連接配接測試時,報錯:
datasource test error
java.lang.Exception: java.lang.Exception: ru.yandex.clickhouse.except.ClickHouseException: ClickHouse exception, code: 193, host: 10.20.30.40, port: 8123; Code: 193, e.displayText() = DB::Exception: Wrong password for user default (version 19.9.5.36)
at com.xy.cloudiview.common.dataprovider.impl.JdbcDataProvider.check(JdbcDataProvider.java:324)
at com.xy.cloudiview.common.services.DataProviderService.testConnection(DataProviderService.java:98)
at com.xy.cloudiview.web.controller.datasource.DataSourceController.checkDatasource(DataSourceController.java:248)
實在是莫名其妙,木有辦法,隻能斷點調試,傳回給前端2個字段:password,encryptedPassword,然後對比一下encryptedPassword解密後的password和最原始的password是否相同。
好家夥,截圖來了:
我們看到斷點調試得到的密碼都是
root
;但,使用
String.equals()
對比發現兩者不相等。簡單來說,就是如下的截圖:
使用
String.contentEquals()
對比,發現兩者依舊不相等。
測試代碼如下:
public static void main(String[] args) {
String s1 = "root";
String s2 = DecodeUtil.encrypt(s1);
String s3 = DecodeUtil.desEncrypt(s2);
System.out.println("s2: " + s2 + "\ns3: " + s3 + "\ns1 == s3 ?: " + s1.equals(s3));
}
見了鬼了。
如果足夠仔細的話,會發現第二個截圖裡面,左邊的加密後再解密的密碼的長度是16,即:
char[16]
;右邊的原始密碼的長度是4,即:
char[4]
。
驗證如下:
實際上隻需要占用4位,
trim()
一下呢?
再對比一下:
解決問題。
後續
在我們的業務場景中,資料源是可以查詢,新增,編輯,複制,删除的。如果是新增一個資料源,此時使用者輸入的密碼就是明文密碼。
- 前端增加一個标志字段:
const [modalType, setModalType] = useState<'update' | 'add' | 'copy' | 'select'>('add');
const testClick = () => {
formModal.validateFields().then((values: any) => {
const {config, sourceName, sourceType} = values;
setTestLoading(true)
test({
name: sourceName,
type: sourceType,
// 新增入參
modalType,
config,
}).then((res: any) => {
message[res.status](`${res.msg}`, 1)
setTestLoading(false)
}).catch(() => {
setTestLoading(false)
})
});
};
- 後端判斷一下:
// 新增資料源時無需解密
if (!dataSource.getString("modalType").equals("add")) {
// 解密一定要trim()
config.put("password", DecodeUtil.desEncrypt(config.getString("password")).trim());
}