Golang中如何处理程序执行中的关键/安全信息

Golang中如何处理程序执行中的关键/安全信息 我正在开发一个应用程序,其中我将一些关键变量存储在 .env 文件中,但在启动可执行文件时,用户很容易访问 .env 文件,并且可以修改或删除它。那么,我该如何“隐藏”这些变量呢?在 Go 中是否有类似 .config 文件的东西可以创建,以使这些变量更安全?谢谢。

5 回复

这与Go语言无关。在Windows上,你可以使用 ATTRIB +H 来隐藏文件。这并不能对黑客隐藏文件,甚至除了最不熟练的用户外,对任何人都无法隐藏。类Unix文件系统通过以句点开头的文件名来“隐藏”文件。

更多关于Golang中如何处理程序执行中的关键/安全信息的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


这完全说得通;任何对这些配置文件具有写权限的进程都可以篡改它们。 你可以:

  • 为你的应用程序创建一个不同的用户,并通过该用户运行你的应用程序。
  • 事先加密配置文件。
  • 更改配置文件的文件访问权限。

如果你能告诉我应用程序的架构、它运行在哪个平台以及你是否使用了容器化技术,我将能够进一步帮助你。

该应用最初面向Windows平台,它会向用户请求用户名和密码,然后我将这些信息以加密形式保存在用户计算机上一个普通文件夹(以应用名称命名)内的.env文件中。虽然.env文件中的USER和PASSWORD是加密的,但为了进一步提升安全性,我希望将这个文件对用户/黑客隐藏起来。我的目标是构建一个独立应用,用户无需下载任何依赖项。现在,当用户首次运行.exe文件时,会生成一个文件夹,并将加密后的凭据写入.env文件。

在 Windows 上,你可以使用数据保护 API。 它基本上允许你将对称加密密钥和密码等机密信息存储在操作系统级别的受保护保险库中。

GitHub - billgraziano/dpapi: GO Wrapper for Windows DPAPI

GitHub - billgraziano/dpapi: GO Wrapper for Windows DPAPI

GO 语言封装的 Windows DPAPI。通过创建 GitHub 账户为 billgraziano/dpapi 的开发做出贡献。

在Go中保护敏感配置信息,可以通过以下方式实现:

1. 环境变量加密存储

使用加密的配置文件,运行时解密:

package main

import (
    "crypto/aes"
    "crypto/cipher"
    "crypto/rand"
    "encoding/base64"
    "encoding/json"
    "fmt"
    "io"
    "os"
)

type Config struct {
    APIKey    string `json:"api_key"`
    DBPass    string `json:"db_password"`
    SecretKey string `json:"secret_key"`
}

func encryptConfig(key []byte, config Config) (string, error) {
    data, _ := json.Marshal(config)
    
    block, err := aes.NewCipher(key)
    if err != nil {
        return "", err
    }
    
    gcm, err := cipher.NewGCM(block)
    if err != nil {
        return "", err
    }
    
    nonce := make([]byte, gcm.NonceSize())
    if _, err = io.ReadFull(rand.Reader, nonce); err != nil {
        return "", err
    }
    
    ciphertext := gcm.Seal(nonce, nonce, data, nil)
    return base64.StdEncoding.EncodeToString(ciphertext), nil
}

func decryptConfig(key []byte, encrypted string) (Config, error) {
    data, err := base64.StdEncoding.DecodeString(encrypted)
    if err != nil {
        return Config{}, err
    }
    
    block, err := aes.NewCipher(key)
    if err != nil {
        return Config{}, err
    }
    
    gcm, err := cipher.NewGCM(block)
    if err != nil {
        return Config{}, err
    }
    
    nonceSize := gcm.NonceSize()
    nonce, ciphertext := data[:nonceSize], data[nonceSize:]
    
    plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
    if err != nil {
        return Config{}, err
    }
    
    var config Config
    json.Unmarshal(plaintext, &config)
    return config, nil
}

2. 使用操作系统密钥环

通过系统级密钥管理服务存储敏感数据:

// 使用 go-keyring 库
package main

import (
    "fmt"
    "github.com/zalando/go-keyring"
)

func main() {
    // 存储密钥
    err := keyring.Set("myapp", "username", "api_key_here")
    if err != nil {
        fmt.Println("Error:", err)
    }
    
    // 读取密钥
    secret, err := keyring.Get("myapp", "username")
    if err != nil {
        fmt.Println("Error:", err)
    }
    fmt.Println("Secret:", secret)
}

3. 运行时从安全服务获取

从HashiCorp Vault或AWS Secrets Manager等安全服务动态获取:

package main

import (
    "fmt"
    "github.com/hashicorp/vault/api"
)

func getSecretFromVault() {
    config := &api.Config{
        Address: "https://vault.example.com",
    }
    
    client, err := api.NewClient(config)
    if err != nil {
        panic(err)
    }
    
    client.SetToken("your-vault-token")
    
    secret, err := client.Logical().Read("secret/data/myapp")
    if err != nil {
        panic(err)
    }
    
    if secret != nil && secret.Data != nil {
        data := secret.Data["data"].(map[string]interface{})
        apiKey := data["api_key"].(string)
        fmt.Println("API Key:", apiKey)
    }
}

4. 内存加密存储

使用安全内存区域存储敏感数据:

package main

import (
    "crypto/rand"
    "encoding/hex"
    "fmt"
    "syscall"
    "unsafe"
)

type secureBuffer struct {
    data []byte
}

func newSecureBuffer(size int) *secureBuffer {
    b := &secureBuffer{
        data: make([]byte, size),
    }
    // 锁定内存页,防止交换到磁盘
    syscall.Mlock(b.data)
    return b
}

func (b *secureBuffer) Write(data []byte) {
    copy(b.data, data)
}

func (b *secureBuffer) Clear() {
    for i := range b.data {
        b.data[i] = 0
    }
    syscall.Munlock(b.data)
}

func main() {
    secret := []byte("my_sensitive_data")
    buf := newSecureBuffer(len(secret))
    defer buf.Clear()
    
    buf.Write(secret)
    
    // 生成随机加密密钥
    key := make([]byte, 32)
    rand.Read(key)
    fmt.Println("Encryption Key:", hex.EncodeToString(key))
}

5. 配置文件权限控制

通过文件系统权限限制访问:

package main

import (
    "fmt"
    "io/ioutil"
    "os"
)

func createSecureConfig() {
    configData := []byte("API_KEY=secret_value\nDB_PASS=another_secret")
    
    // 创建只有所有者可读写的文件
    err := ioutil.WriteFile("config.secure", configData, 0600)
    if err != nil {
        panic(err)
    }
    
    // 验证文件权限
    info, _ := os.Stat("config.secure")
    fmt.Printf("File mode: %o\n", info.Mode().Perm())
}

6. 使用加密的TOML/YAML配置文件

结合加密和标准配置文件格式:

package main

import (
    "crypto/cipher"
    "crypto/aes"
    "crypto/rand"
    "encoding/base64"
    "fmt"
    "gopkg.in/yaml.v3"
    "io/ioutil"
)

type SecureConfig struct {
    EncryptedData string `yaml:"encrypted_data"`
}

func loadEncryptedYAML(filename string, key []byte) (map[string]string, error) {
    data, err := ioutil.ReadFile(filename)
    if err != nil {
        return nil, err
    }
    
    var secureConfig SecureConfig
    yaml.Unmarshal(data, &secureConfig)
    
    // 解密数据
    return decryptMap(key, secureConfig.EncryptedData)
}

选择方案应根据安全需求决定:对于高安全要求,推荐使用密钥环或安全服务(Vault);对于中等需求,可使用加密配置文件配合环境变量传递解密密钥。

回到顶部