From bc16c720cfc938fe7c275d25ea9ee2888e6b40ae Mon Sep 17 00:00:00 2001 From: ongtrieuhau Date: Tue, 27 Oct 2026 03:46:27 -0700 Subject: [PATCH] =?UTF-8?q?security:=20=C4=90=C3=B3ng=20g=C3=B3i=20v=C3=A0?= =?UTF-8?q?=20b=E1=BA=A3o=20v=E1=BB=87=20kh=C3=B3a=20gi=E1=BA=A3i=20m?= =?UTF-8?q?=C3=A3=20n=E1=BB=99i=20b=E1=BB=99=20trong=20binary,=20g?= =?UTF-8?q?=E1=BB=A1=20b=E1=BB=8F=20ho=C3=A0n=20to=C3=A0n=20kh=E1=BB=8Fi?= =?UTF-8?q?=20c=E1=BA=A5u=20h=C3=ACnh=20v=C3=A0=20t=C3=A0i=20li=E1=BB=87u?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config.json | 1 - config/config.go | 32 ++--------------------- docs/HUONG_DAN_CAI_DAT_TRIEN_KHAI_DEMO.md | 7 +++-- handlers/admin.go | 13 +-------- license/license.go | 25 ++++++++++-------- license/license_test.go | 4 +-- 6 files changed, 22 insertions(+), 60 deletions(-) diff --git a/config.json b/config.json index bfa8c69..6de7e0e 100644 --- a/config.json +++ b/config.json @@ -42,7 +42,6 @@ "current_version": "v1.0.2" }, "license": { - "crypto_key": "ENC(R8h55AZzKMVH6QO+X/mBHvoMBLSBOZ9HCXSH2CbLrEwCUgGzFf7aJ5p8VCv7DZAMY6TkJQemYZIcXRS0)", "key": "U2FsdGVkX18Zsq52FPbB7FS1QM7CwWh+t1Esi96gUMFILJD0vZXM69uQBC4sP7TjLVOiJPZt0KIq17iql+hXehLCVSbCEhwKKm+zNab+u2Swah63A52hz0KMJXddLRZ6vanmP2goLTzY7749HsFVRDq+3bdbi8fdUZCpAsSTEiqC2cRTpF5WVh0SHt1wX/i42YSQgOYPeXQtg+lRx/URk4p7lYSVQOYWXglp99kO+Va1ADoNcTgrfz3aaAxAkj0S" } } \ No newline at end of file diff --git a/config/config.go b/config/config.go index c99a906..b0421bd 100644 --- a/config/config.go +++ b/config/config.go @@ -47,8 +47,7 @@ type UpdaterConfig struct { } type LicenseConfig struct { - CryptoKey string `json:"crypto_key"` // stored as ENC(...) - Key string `json:"key"` // stored ciphertext U2FsdGVk... + Key string `json:"key"` // stored ciphertext U2FsdGVk... } type AppConfig struct { @@ -61,7 +60,6 @@ type AppConfig struct { DecryptedDBPassword string `json:"-"` DecryptedUpdaterToken string `json:"-"` DecryptedAdminPassword string `json:"-"` - DecryptedCryptoKey string `json:"-"` } var ( @@ -162,8 +160,7 @@ func DefaultConfig() *AppConfig { CurrentVersion: "v1.0.2", }, License: LicenseConfig{ - CryptoKey: "BAD5A05F330D5B8CDDFCA9E7ECDC840B", - Key: "", + Key: "", }, } return cfg @@ -182,18 +179,15 @@ func LoadConfig(path string) (*AppConfig, error) { cfg.DecryptedAdminPassword = cfg.Server.AdminPassword cfg.DecryptedDBPassword = cfg.Database.Password cfg.DecryptedUpdaterToken = cfg.Updater.Token - cfg.DecryptedCryptoKey = cfg.License.CryptoKey // Encrypt for disk save encAdmin, _ := Encrypt(cfg.Server.AdminPassword) encDB, _ := Encrypt(cfg.Database.Password) encTok, _ := Encrypt(cfg.Updater.Token) - encCrypto, _ := Encrypt(cfg.License.CryptoKey) cfg.Server.AdminPassword = encAdmin cfg.Database.Password = encDB cfg.Updater.Token = encTok - cfg.License.CryptoKey = encCrypto data, _ := json.MarshalIndent(cfg, "", " ") _ = os.MkdirAll(filepath.Dir(configPath), 0755) @@ -217,24 +211,10 @@ func LoadConfig(path string) (*AppConfig, error) { decAdmin, _ := Decrypt(cfg.Server.AdminPassword) decDB, _ := Decrypt(cfg.Database.Password) decTok, _ := Decrypt(cfg.Updater.Token) - if cfg.License.CryptoKey == "" { - cfg.License.CryptoKey = "BAD5A05F330D5B8CDDFCA9E7ECDC840B" - } - decCrypto, _ := Decrypt(cfg.License.CryptoKey) - if decCrypto == "" { - decCrypto = "BAD5A05F330D5B8CDDFCA9E7ECDC840B" - } cfg.DecryptedAdminPassword = decAdmin cfg.DecryptedDBPassword = decDB cfg.DecryptedUpdaterToken = decTok - cfg.DecryptedCryptoKey = decCrypto - - // Ensure crypto key is stored encrypted on disk - if !strings.HasPrefix(cfg.License.CryptoKey, "ENC(") { - encCrypto, _ := Encrypt(cfg.License.CryptoKey) - cfg.License.CryptoKey = encCrypto - } // Auto-migrate legacy owner & repo if cfg.Updater.Owner == "" || cfg.Updater.Owner == "hdhiswork" { @@ -270,14 +250,6 @@ func SaveConfig(cfg *AppConfig) error { enc, _ := Encrypt(clone.Updater.Token) clone.Updater.Token = enc } - if clone.License.CryptoKey == "" { - clone.License.CryptoKey = "BAD5A05F330D5B8CDDFCA9E7ECDC840B" - } - if !strings.HasPrefix(clone.License.CryptoKey, "ENC(") { - clone.DecryptedCryptoKey = clone.License.CryptoKey - enc, _ := Encrypt(clone.License.CryptoKey) - clone.License.CryptoKey = enc - } data, err := json.MarshalIndent(&clone, "", " ") if err != nil { diff --git a/docs/HUONG_DAN_CAI_DAT_TRIEN_KHAI_DEMO.md b/docs/HUONG_DAN_CAI_DAT_TRIEN_KHAI_DEMO.md index 2241e14..9fb2d39 100644 --- a/docs/HUONG_DAN_CAI_DAT_TRIEN_KHAI_DEMO.md +++ b/docs/HUONG_DAN_CAI_DAT_TRIEN_KHAI_DEMO.md @@ -106,14 +106,13 @@ Mở tệp `config.json` bằng Notepad, VSCode hoặc `nano`: } ], "license": { - "crypto_key": "ENC(U2FsdGVkX18...)", - "active_key": "U2FsdGVkX18Zsq52FPbB7FS1QM7CwWh+t1Esi96gUMFILJD0vZXM69uQBC4sP7TjLVOiJPZt0KIq17iql+hXehLCVSbCEhwKKm+zNab+u2Swah63A52hz0KMJXddLRZ6vanmP2goLTzY7749HsFVRDq+3bdbi8fdUZCpAsSTEiqC2cRTpF5WVh0SHt1wX/i42YSQgOYPeXQtg+lRx/URk4p7lYSVQOYWXglp99kO+Va1ADoNcTgrfz3aaAxAkj0S" + "key": "U2FsdGVkX18Zsq52FPbB7FS1QM7CwWh+t1Esi96gUMFILJD0vZXM69uQBC4sP7TjLVOiJPZt0KIq17iql+hXehLCVSbCEhwKKm+zNab+u2Swah63A52hz0KMJXddLRZ6vanmP2goLTzY7749HsFVRDq+3bdbi8fdUZCpAsSTEiqC2cRTpF5WVh0SHt1wX/i42YSQgOYPeXQtg+lRx/URk4p7lYSVQOYWXglp99kO+Va1ADoNcTgrfz3aaAxAkj0S" } } ``` > [!NOTE] -> - Mật khẩu CSDL (`password`) và Passphrase giải mã (`crypto_key`) được hỗ trợ lưu dạng mã hóa `ENC(...)`. Nếu nhập dạng chuỗi thông thường (Plaintext), hệ thống vẫn tự động nhận diện và kết nối an toàn. +> - Mật khẩu CSDL (`password`) được hỗ trợ lưu dạng mã hóa `ENC(...)`. Nếu nhập dạng chuỗi thông thường (Plaintext), hệ thống vẫn tự động nhận diện và kết nối an toàn. > - Có thể thêm bao nhiêu CSDL tùy ý vào mảng `databases`. Người dùng có thể chuyển đổi linh hoạt ngay trên dropdown của thanh công cụ Web. --- @@ -123,7 +122,7 @@ Mở tệp `config.json` bằng Notepad, VSCode hoặc `nano`: ### 5.1 Quy cách và Cấu trúc Bản quyền Hệ thống sử dụng cơ chế bảo mật theo tiêu chuẩn thư viện `OTH.Adapter / HisPrivateCode`: - **Thuật toán**: OpenSSL EVP_BytesToKey (MD5 key derivation + AES-256-CBC). -- **Khóa dẫn xuất nội bộ**: `BAD5A05F330D5B8CDDFCA9E7ECDC840B`. +- **Cơ chế xác thực**: Khóa bí mật nội bộ được đóng gói và tích hợp tự động bên trong file thực thi binary/exe; khi triển khai người dùng hoặc kỹ thuật viên chỉ cần nhập duy nhất chuỗi token DECODE. - **Cấu trúc dữ liệu JSON sau giải mã**: ```json { diff --git a/handlers/admin.go b/handlers/admin.go index 0f04e7d..0ea6d0e 100644 --- a/handlers/admin.go +++ b/handlers/admin.go @@ -30,9 +30,6 @@ func HandleGetAdminConfig(w http.ResponseWriter, r *http.Request) { if respCfg.Updater.Token != "" { respCfg.Updater.Token = "••••••••" } - if respCfg.License.CryptoKey != "" { - respCfg.License.CryptoKey = "••••••••" - } _ = json.NewEncoder(w).Encode(map[string]interface{}{ "success": true, @@ -83,15 +80,7 @@ func HandleSaveAdminConfig(w http.ResponseWriter, r *http.Request) { input.Updater.Token = enc } - // Handle License Crypto Key - if input.License.CryptoKey == "" || input.License.CryptoKey == "••••••••" { - input.License.CryptoKey = current.License.CryptoKey - input.DecryptedCryptoKey = current.DecryptedCryptoKey - } else { - input.DecryptedCryptoKey = input.License.CryptoKey - enc, _ := config.Encrypt(input.License.CryptoKey) - input.License.CryptoKey = enc - } + // Handle License Key if input.License.Key == "" { input.License.Key = current.License.Key } diff --git a/license/license.go b/license/license.go index fb6a06a..1ef6143 100644 --- a/license/license.go +++ b/license/license.go @@ -114,13 +114,22 @@ func OpenSSLDecrypt(encryptedBase64 string, passphrase string) (string, error) { return string(plaintext[:len(plaintext)-padLen]), nil } +// internalSecretKey returns the internal private passphrase (DHCryptoJSKEY) +func internalSecretKey() string { + part1 := []byte{0x42, 0x41, 0x44, 0x35, 0x41, 0x30, 0x35, 0x46} + part2 := []byte{0x33, 0x33, 0x30, 0x44, 0x35, 0x42, 0x38, 0x43} + part3 := []byte{0x44, 0x44, 0x46, 0x43, 0x41, 0x39, 0x45, 0x37} + part4 := []byte{0x45, 0x43, 0x44, 0x43, 0x38, 0x34, 0x30, 0x42} + return string(append(append(append(part1, part2...), part3...), part4...)) +} + // ValidateAndParseLicense parses and evaluates the license ciphertext func ValidateAndParseLicense(encryptedKey string, cryptoKey string) (*LicenseInfo, error) { if strings.TrimSpace(encryptedKey) == "" { return nil, errors.New("chuỗi key bản quyền trống") } if strings.TrimSpace(cryptoKey) == "" { - cryptoKey = "BAD5A05F330D5B8CDDFCA9E7ECDC840B" + cryptoKey = internalSecretKey() } decryptedJSON, err := OpenSSLDecrypt(encryptedKey, cryptoKey) @@ -181,11 +190,6 @@ func InitLicense() { return } - cryptoKey := cfg.DecryptedCryptoKey - if cryptoKey == "" { - cryptoKey = "BAD5A05F330D5B8CDDFCA9E7ECDC840B" - } - if cfg.License.Key == "" { currentLicense = &LicenseInfo{ IsValid: false, @@ -195,7 +199,7 @@ func InitLicense() { return } - info, err := ValidateAndParseLicense(cfg.License.Key, cryptoKey) + info, err := ValidateAndParseLicense(cfg.License.Key, "") if err != nil { currentLicense = &LicenseInfo{ IsValid: false, @@ -231,12 +235,11 @@ func GetStatus() *LicenseInfo { // Activate saves and applies a new license key func Activate(encryptedKey string) (*LicenseInfo, error) { cfg := config.Get() - cryptoKey := cfg.DecryptedCryptoKey - if cryptoKey == "" { - cryptoKey = "BAD5A05F330D5B8CDDFCA9E7ECDC840B" + if cfg == nil { + return nil, errors.New("cấu hình chưa được khởi tạo") } - info, err := ValidateAndParseLicense(encryptedKey, cryptoKey) + info, err := ValidateAndParseLicense(encryptedKey, "") if err != nil { return nil, err } diff --git a/license/license_test.go b/license/license_test.go index f9eeb64..8dcce95 100644 --- a/license/license_test.go +++ b/license/license_test.go @@ -6,9 +6,9 @@ import ( func TestOpenSSLDecryptUserKey(t *testing.T) { cipherText := "U2FsdGVkX18Zsq52FPbB7FS1QM7CwWh+t1Esi96gUMFILJD0vZXM69uQBC4sP7TjLVOiJPZt0KIq17iql+hXehLCVSbCEhwKKm+zNab+u2Swah63A52hz0KMJXddLRZ6vanmP2goLTzY7749HsFVRDq+3bdbi8fdUZCpAsSTEiqC2cRTpF5WVh0SHt1wX/i42YSQgOYPeXQtg+lRx/URk4p7lYSVQOYWXglp99kO+Va1ADoNcTgrfz3aaAxAkj0S" - passphrase := "BAD5A05F330D5B8CDDFCA9E7ECDC840B" - info, err := ValidateAndParseLicense(cipherText, passphrase) + // Passing empty cryptoKey triggers internalSecretKey() automatically + info, err := ValidateAndParseLicense(cipherText, "") if err != nil { t.Fatalf("Validation failed: %v", err) }