From 2ac48e20a4e11cefcd66180cd0ddd5a10fcac239 Mon Sep 17 00:00:00 2001 From: ZhouYongyou <128128010+zhouyongyou@users.noreply.github.com> Date: Thu, 6 Nov 2025 23:58:27 +0800 Subject: [PATCH] =?UTF-8?q?refactor(crypto):=20simplify=20to=20local=20enc?= =?UTF-8?q?ryption=20only=20(remove=20KMS)=20##=20=F0=9F=8E=AF=20=E7=B0=A1?= =?UTF-8?q?=E5=8C=96=E6=96=B9=E6=A1=88=EF=BC=88=E7=A4=BE=E5=8D=80=E5=8F=8B?= =?UTF-8?q?=E5=A5=BD=EF=BC=89=20###=20=E7=A7=BB=E9=99=A4=E9=9B=B2=E7=AB=AF?= =?UTF-8?q?=20KMS=20-=20=E2=9D=8C=20=E5=88=AA=E9=99=A4=20crypto/aliyun=5Fk?= =?UTF-8?q?ms.go=20-=20=E2=9D=8C=20=E4=B8=8D=E5=8C=85=E5=90=AB=20GCP=20KMS?= =?UTF-8?q?=20-=20=E2=9C=85=20=E5=83=85=E4=BF=9D=E7=95=99=E6=9C=AC?= =?UTF-8?q?=E5=9C=B0=20AES-256-GCM=20=E5=8A=A0=E5=AF=86=20###=20=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=20SQLite=20=E9=A9=85=E5=8B=95=20-=20=E2=9C=85=20moder?= =?UTF-8?q?nc.org/sqlite=EF=BC=88=E7=B4=94=20Go=EF=BC=8C=E7=84=A1=20CGO?= =?UTF-8?q?=EF=BC=89=20-=20=E2=9C=85=20=E8=88=87=E4=B8=8A=E6=B8=B8?= =?UTF-8?q?=E4=BF=9D=E6=8C=81=E4=B8=80=E8=87=B4=20##=20=F0=9F=93=A6=20?= =?UTF-8?q?=E4=BF=9D=E7=95=99=E6=A0=B8=E5=BF=83=E5=8A=9F=E8=83=BD=20?= =?UTF-8?q?=E2=9C=85=20crypto/encryption.go=20=20=20=20=20=20=20=20-=20RSA?= =?UTF-8?q?=20+=20AES=20=E5=8A=A0=E5=AF=86=20=E2=9C=85=20crypto/secure=5Fs?= =?UTF-8?q?torage.go=20=20=20=20-=20=E6=95=B8=E6=93=9A=E5=BA=AB=E5=8A=A0?= =?UTF-8?q?=E5=AF=86=E5=B1=A4=20=E2=9C=85=20api/crypto=5Fhandler.go=20=20?= =?UTF-8?q?=20=20=20=20=20-=20API=20=E7=AB=AF=E9=BB=9E=20=E2=9C=85=20web/s?= =?UTF-8?q?rc/lib/crypto.ts=20=20=20=20=20=20=20-=20=E5=89=8D=E7=AB=AF?= =?UTF-8?q?=E5=8A=A0=E5=AF=86=20=E2=9C=85=20scripts/migrate=5Fencryption.g?= =?UTF-8?q?o=20-=20=E6=95=B8=E6=93=9A=E9=81=B7=E7=A7=BB=20##=20?= =?UTF-8?q?=F0=9F=9A=80=20=E9=83=A8=E7=BD=B2=E6=96=B9=E5=BC=8F=20```bash?= =?UTF-8?q?=20#=20=E5=83=85=E9=9C=80=E4=B8=80=E5=80=8B=E7=92=B0=E5=A2=83?= =?UTF-8?q?=E8=AE=8A=E9=87=8F=20export=20NOFX=5FMASTER=5FKEY=3D$(openssl?= =?UTF-8?q?=20rand=20-base64=2032)=20go=20run=20main.go=20```=20##=20?= =?UTF-8?q?=E2=9C=85=20=E5=84=AA=E9=BB=9E=20-=20=E2=9C=85=20=E9=9B=B6?= =?UTF-8?q?=E9=9B=B2=E6=9C=8D=E5=8B=99=E4=BE=9D=E8=B3=B4=20-=20=E2=9C=85?= =?UTF-8?q?=20=E7=B0=A1=E5=96=AE=E6=98=93=E9=83=A8=E7=BD=B2=20-=20?= =?UTF-8?q?=E2=9C=85=20=E9=81=A9=E5=90=88=E7=A4=BE=E5=8D=80=E7=94=A8?= =?UTF-8?q?=E6=88=B6=20-=20=E2=9C=85=20=E4=BF=9D=E6=8C=81=E6=A0=B8?= =?UTF-8?q?=E5=BF=83=E5=AE=89=E5=85=A8=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crypto/aliyun_kms.go | 216 ---------------------------------- scripts/migrate_encryption.go | 4 +- 2 files changed, 2 insertions(+), 218 deletions(-) delete mode 100644 crypto/aliyun_kms.go diff --git a/crypto/aliyun_kms.go b/crypto/aliyun_kms.go deleted file mode 100644 index f90d9378..00000000 --- a/crypto/aliyun_kms.go +++ /dev/null @@ -1,216 +0,0 @@ -package crypto - -import ( - "encoding/base64" - "fmt" - "os" - - kms "github.com/aliyun/alibaba-cloud-sdk-go/services/kms" -) - -// AliyunKMSManager 阿里雲 KMS 管理器 -type AliyunKMSManager struct { - client *kms.Client - keyID string // 主密鑰 ID -} - -// NewAliyunKMSManager 創建阿里雲 KMS 管理器 -func NewAliyunKMSManager() (*AliyunKMSManager, error) { - // 從環境變數讀取配置 - accessKeyID := os.Getenv("ALIYUN_ACCESS_KEY_ID") - accessKeySecret := os.Getenv("ALIYUN_ACCESS_KEY_SECRET") - regionID := os.Getenv("ALIYUN_REGION_ID") // 如 cn-hangzhou - keyID := os.Getenv("ALIYUN_KMS_KEY_ID") // 主密鑰 ID - - if accessKeyID == "" || accessKeySecret == "" { - return nil, fmt.Errorf("阿里雲憑證未配置,請設置環境變數 ALIYUN_ACCESS_KEY_ID 和 ALIYUN_ACCESS_KEY_SECRET") - } - - if keyID == "" { - return nil, fmt.Errorf("KMS 密鑰 ID 未配置,請設置環境變數 ALIYUN_KMS_KEY_ID") - } - - // 創建 KMS 客戶端 - client, err := kms.NewClientWithAccessKey(regionID, accessKeyID, accessKeySecret) - if err != nil { - return nil, fmt.Errorf("創建 KMS 客戶端失敗: %w", err) - } - - return &AliyunKMSManager{ - client: client, - keyID: keyID, - }, nil -} - -// Encrypt 使用 KMS 加密數據 -func (m *AliyunKMSManager) Encrypt(plaintext string) (string, error) { - request := kms.CreateEncryptRequest() - request.Scheme = "https" - request.KeyId = m.keyID - request.Plaintext = plaintext - - response, err := m.client.Encrypt(request) - if err != nil { - return "", fmt.Errorf("KMS 加密失敗: %w", err) - } - - return response.CiphertextBlob, nil -} - -// Decrypt 使用 KMS 解密數據 -func (m *AliyunKMSManager) Decrypt(ciphertext string) (string, error) { - request := kms.CreateDecryptRequest() - request.Scheme = "https" - request.CiphertextBlob = ciphertext - - response, err := m.client.Decrypt(request) - if err != nil { - return "", fmt.Errorf("KMS 解密失敗: %w", err) - } - - // Base64 解碼 - plaintext, err := base64.StdEncoding.DecodeString(response.Plaintext) - if err != nil { - return "", fmt.Errorf("解碼失敗: %w", err) - } - - return string(plaintext), nil -} - -// GenerateDataKey 生成數據密鑰(用於本地加密,KMS 僅管理主密鑰) -func (m *AliyunKMSManager) GenerateDataKey() (plaintext, ciphertext string, err error) { - request := kms.CreateGenerateDataKeyRequest() - request.Scheme = "https" - request.KeyId = m.keyID - request.KeySpec = "AES_256" // 256-bit AES 密鑰 - - response, err := m.client.GenerateDataKey(request) - if err != nil { - return "", "", fmt.Errorf("生成數據密鑰失敗: %w", err) - } - - // 明文密鑰(用於加密數據) - plaintextBytes, _ := base64.StdEncoding.DecodeString(response.Plaintext) - plaintext = string(plaintextBytes) - - // 密文密鑰(保存到數據庫,用於後續解密) - ciphertext = response.CiphertextBlob - - return plaintext, ciphertext, nil -} - -// CreateKey 創建新的 KMS 主密鑰(僅管理員操作) -func (m *AliyunKMSManager) CreateKey(description string) (string, error) { - request := kms.CreateCreateKeyRequest() - request.Scheme = "https" - request.Description = description - request.KeyUsage = "ENCRYPT/DECRYPT" - request.Origin = "Aliyun_KMS" // 阿里雲託管 - - response, err := m.client.CreateKey(request) - if err != nil { - return "", fmt.Errorf("創建 KMS 密鑰失敗: %w", err) - } - - return response.KeyMetadata.KeyId, nil -} - -// EnableKeyRotation 啟用自動密鑰輪換(每年自動輪換) -func (m *AliyunKMSManager) EnableKeyRotation() error { - request := kms.CreateEnableKeyRotationRequest() - request.Scheme = "https" - request.KeyId = m.keyID - - _, err := m.client.EnableKeyRotation(request) - if err != nil { - return fmt.Errorf("啟用密鑰輪換失敗: %w", err) - } - - return nil -} - -// ==================== 與現有加密系統集成 ==================== - -// EncryptionManagerWithKMS 混合加密管理器(本地 + KMS) -type EncryptionManagerWithKMS struct { - localEM *EncryptionManager - kmsEM *AliyunKMSManager - useKMS bool // 是否使用 KMS -} - -// NewEncryptionManagerWithKMS 創建混合加密管理器 -func NewEncryptionManagerWithKMS() (*EncryptionManagerWithKMS, error) { - // 初始化本地加密 - localEM, err := GetEncryptionManager() - if err != nil { - return nil, err - } - - // 嘗試初始化 KMS(如果配置了環境變數) - kmsEM, err := NewAliyunKMSManager() - useKMS := err == nil - - if useKMS { - fmt.Println("✅ 阿里雲 KMS 已啟用") - } else { - fmt.Println("⚠️ 阿里雲 KMS 未配置,使用本地加密") - } - - return &EncryptionManagerWithKMS{ - localEM: localEM, - kmsEM: kmsEM, - useKMS: useKMS, - }, nil -} - -// EncryptForDatabase 加密數據(自動選擇 KMS 或本地) -func (m *EncryptionManagerWithKMS) EncryptForDatabase(plaintext string) (string, error) { - if m.useKMS { - // 使用 KMS 加密 - encrypted, err := m.kmsEM.Encrypt(plaintext) - if err != nil { - // KMS 失敗時降級到本地加密 - fmt.Printf("⚠️ KMS 加密失敗,降級到本地加密: %v\n", err) - return m.localEM.EncryptForDatabase(plaintext) - } - return "kms:" + encrypted, nil // 添加前綴標識 - } - - // 使用本地加密 - return m.localEM.EncryptForDatabase(plaintext) -} - -// DecryptFromDatabase 解密數據(自動檢測 KMS 或本地) -func (m *EncryptionManagerWithKMS) DecryptFromDatabase(ciphertext string) (string, error) { - // 檢測是否為 KMS 加密 - if len(ciphertext) > 4 && ciphertext[:4] == "kms:" { - if !m.useKMS { - return "", fmt.Errorf("數據使用 KMS 加密,但 KMS 未配置") - } - return m.kmsEM.Decrypt(ciphertext[4:]) - } - - // 本地解密 - return m.localEM.DecryptFromDatabase(ciphertext) -} - -// MigrateToKMS 將現有本地加密數據遷移到 KMS -func (m *EncryptionManagerWithKMS) MigrateToKMS(localEncrypted string) (string, error) { - if !m.useKMS { - return "", fmt.Errorf("KMS 未啟用") - } - - // 1. 本地解密 - plaintext, err := m.localEM.DecryptFromDatabase(localEncrypted) - if err != nil { - return "", err - } - - // 2. KMS 加密 - kmsEncrypted, err := m.kmsEM.Encrypt(plaintext) - if err != nil { - return "", err - } - - return "kms:" + kmsEncrypted, nil -} diff --git a/scripts/migrate_encryption.go b/scripts/migrate_encryption.go index ae446777..f17fbe7e 100644 --- a/scripts/migrate_encryption.go +++ b/scripts/migrate_encryption.go @@ -8,7 +8,7 @@ import ( "nofx/crypto" - _ "github.com/mattn/go-sqlite3" + _ "modernc.org/sqlite" ) func main() { @@ -38,7 +38,7 @@ func main() { } // 3. 打開數據庫 - db, err := sql.Open("sqlite3", dbPath) + db, err := sql.Open("sqlite", dbPath) if err != nil { log.Fatalf("❌ 打開數據庫失敗: %v", err) }