fix: 修复多个安全缺陷和功能问题

- 移除加密相关代码(服务端和所有客户端)
- 修复 JWT 验证未检查签名算法的问题
- 修复重置密码使用不安全随机数的问题
- 实现 Logout 服务端失效机制
- 修复历史版本对比 diff 颜色标记错误
- 修复占位符解析循环引用风险
- 添加用户禁用状态检查
- 更新 bug 清单文档
This commit is contained in:
2026-03-10 21:07:22 +08:00
parent f41d53da41
commit 932db9fbdc
27 changed files with 292 additions and 721 deletions
+2 -28
View File
@@ -18,8 +18,6 @@ type Client struct {
cache *Cache
listener *Listener
configs map[string]string
secret string
globalSecret string
lastTime int64
mu sync.RWMutex
httpClient *http.Client
@@ -157,14 +155,6 @@ func (c *Client) fetchAll() error {
}
}
// extract secrets
if s, ok := result["kenaito.config.encrypt-secret"]; ok {
c.secret, _ = s.(string)
}
if s, ok := result["kenaito.config.global-encrypt-secret"]; ok {
c.globalSecret, _ = s.(string)
}
// extract timestamp
if ts, ok := result["latest.fetch.timestamp"]; ok {
if tsStr, ok := ts.(string); ok {
@@ -234,17 +224,9 @@ func (c *Client) fetchChanged() error {
}
if len(wrapper.Data) > 0 {
// decrypt values
changed := make(map[string]string)
for k, v := range wrapper.Data {
decrypted, err := decryptConfig(c.secret, v)
if err != nil && c.globalSecret != "" {
decrypted, err = decryptConfig(c.globalSecret, v)
}
if err != nil {
decrypted = v
}
changed[k] = decrypted
changed[k] = v
}
// update local configs
@@ -275,15 +257,7 @@ func (c *Client) applyConfigs(data map[string]interface{}) {
if !ok {
continue
}
// decrypt if needed - try app secret first, then global secret
decrypted, err := decryptConfig(c.secret, strVal)
if err != nil && c.globalSecret != "" {
decrypted, err = decryptConfig(c.globalSecret, strVal)
}
if err != nil {
decrypted = strVal
}
c.configs[k] = decrypted
c.configs[k] = strVal
}
}
-62
View File
@@ -1,62 +0,0 @@
package client
import (
"crypto/aes"
"crypto/cipher"
"crypto/md5"
"encoding/base64"
"encoding/hex"
"fmt"
"strings"
)
const CryptPrefix = "{Cipher}"
func decryptConfig(secret string, data string) (string, error) {
if !strings.HasPrefix(data, CryptPrefix) {
return data, nil
}
encrypted := strings.TrimPrefix(data, CryptPrefix)
return decryptWithAES(secret, encrypted)
}
func decryptWithAES(key string, data string) (string, error) {
secretKey := md5.Sum([]byte(key))
aesKey := hex.EncodeToString(secretKey[:])[16:]
cipherText, err := base64.StdEncoding.DecodeString(data)
if err != nil {
return "", err
}
block, err := aes.NewCipher([]byte(aesKey))
if err != nil {
return "", err
}
if len(cipherText)%aes.BlockSize != 0 {
return "", fmt.Errorf("ciphertext is not a multiple of block size")
}
plainText := make([]byte, len(cipherText))
mode := cipher.NewCBCDecrypter(block, make([]byte, aes.BlockSize))
mode.CryptBlocks(plainText, cipherText)
plainText, err = pkcs7Unpad(plainText, aes.BlockSize)
if err != nil {
return "", err
}
return string(plainText), nil
}
func pkcs7Unpad(data []byte, blockSize int) ([]byte, error) {
if len(data) == 0 {
return nil, fmt.Errorf("empty data")
}
padding := int(data[len(data)-1])
if padding > blockSize || padding == 0 {
return nil, fmt.Errorf("invalid padding")
}
return data[:len(data)-padding], nil
}