fix: read imported member records with retained legacy data keys
Deploy olons-admin production / deploy (push) Successful in 7m14s
Deploy olons-admin production / deploy (push) Successful in 7m14s
This commit is contained in:
@@ -195,6 +195,8 @@ token:
|
|||||||
# 业务敏感字段保护。生产环境必须替换为独立的高强度密钥,并通过密钥管理系统注入。
|
# 业务敏感字段保护。生产环境必须替换为独立的高强度密钥,并通过密钥管理系统注入。
|
||||||
security:
|
security:
|
||||||
dataKey: "change-me-before-production"
|
dataKey: "change-me-before-production"
|
||||||
|
# 迁移前的 HotGo dataKey,仅用于兼容读取,不能删除仍有存量密文使用的密钥。
|
||||||
|
legacyDataKeys: []
|
||||||
# 与 C 端收款资料使用相同配置;历史主密钥只用于读取,不修改原密文。
|
# 与 C 端收款资料使用相同配置;历史主密钥只用于读取,不修改原密文。
|
||||||
financeMasterKey: ""
|
financeMasterKey: ""
|
||||||
financeLegacyMasterKeys: []
|
financeLegacyMasterKeys: []
|
||||||
|
|||||||
@@ -65,6 +65,13 @@ func DecryptField(ctx context.Context, encoded string) (string, error) {
|
|||||||
if key, keyErr := fieldKey(ctx); keyErr == nil {
|
if key, keyErr := fieldKey(ctx); keyErr == nil {
|
||||||
keys = append(keys, key)
|
keys = append(keys, key)
|
||||||
}
|
}
|
||||||
|
// Imported HotGo records can use an older dataKey; never use these keys for new writes.
|
||||||
|
for _, secret := range g.Cfg().MustGet(ctx, "security.legacyDataKeys", []string{}).Strings() {
|
||||||
|
if secret = strings.TrimSpace(secret); secret != "" {
|
||||||
|
sum := sha256.Sum256([]byte(secret))
|
||||||
|
keys = append(keys, sum[:])
|
||||||
|
}
|
||||||
|
}
|
||||||
for _, key := range keys {
|
for _, key := range keys {
|
||||||
block, keyErr := aes.NewCipher(key)
|
block, keyErr := aes.NewCipher(key)
|
||||||
if keyErr != nil {
|
if keyErr != nil {
|
||||||
|
|||||||
@@ -81,6 +81,28 @@ func TestDecryptFieldKeepsLegacyHotGoDataReadable(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDecryptFieldReadsImportedHotGoKeyWithoutChangingCurrentKey(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
setFieldTestConfig(t, map[string]interface{}{"dataKey": "imported-original-data-key"})
|
||||||
|
encoded, err := EncryptField(ctx, "迁移前的资料")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
setFieldTestConfig(t, map[string]interface{}{"dataKey": "current-data-key", "legacyDataKeys": []string{"imported-original-data-key"}, "financeMasterKey": "current-finance-master-key-with-at-least-32-characters"})
|
||||||
|
plain, err := DecryptField(ctx, encoded)
|
||||||
|
if err != nil || plain != "迁移前的资料" {
|
||||||
|
t.Fatalf("imported record unreadable: %v", err)
|
||||||
|
}
|
||||||
|
current, err := EncryptField(ctx, "当前资料")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
plain, err = DecryptField(ctx, current)
|
||||||
|
if err != nil || plain != "当前资料" {
|
||||||
|
t.Fatalf("current key was not preserved: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func setFieldTestConfig(t *testing.T, security map[string]interface{}) {
|
func setFieldTestConfig(t *testing.T, security map[string]interface{}) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
data, err := json.Marshal(map[string]interface{}{"security": security})
|
data, err := json.Marshal(map[string]interface{}{"security": security})
|
||||||
|
|||||||
Reference in New Issue
Block a user