Skip to content

安全 ​

视角:本文讨论数据库访问与 SQL 注入等风险;更广的官方安全口径见安全与 crypto 笔记,文件/IO 侧见IO 安全笔记。

12.1 数据库安全的概念 ​

数据库安全涉及保护数据库中的数据免受未授权访问、数据泄露、篡改和破坏。主要包括以下几个方面:

  • 访问控制:限制对数据库的访问权限,确保只有授权用户可以访问数据。
  • 数据加密:保护数据在传输和存储过程中的安全,防止数据被窃取或篡改。
  • 防御注入攻击:防止SQL注入等常见攻击,确保数据安全。
  • 定期备份:定期备份数据库,以防止数据丢失。
  • 监控和审计:监控数据库活动,记录访问日志,以便追踪和审计。

12.2 防止SQL注入攻击 ​

SQL注入攻击是一种常见的攻击方式,攻击者通过构造恶意的SQL语句来篡改数据库查询,达到未授权访问或破坏数据的目的。防止SQL注入攻击的主要方法包括:

  • 使用预编译语句:使用预编译语句(Prepared Statements)可以避免SQL注入,因为查询和数据是分开的,数据中的恶意代码不会被执行。
示例:使用预编译语句防止SQL注入 ​
go
func GetUserByEmail(db *sql.DB, email string) (*User, error) {
    stmt, err := db.Prepare("SELECT id, name, email FROM users WHERE email = ?")
    if err != nil {
        return nil, err
    }
    defer stmt.Close()

    row := stmt.QueryRow(email)
    user := new(User)
    err = row.Scan(&user.ID, &user.Name, &user.Email)
    if err != nil {
        return nil, err
    }
    return user, nil
}

type User struct {
    ID    int
    Name  string
    Email string
}
  • 输入验证:对用户输入的数据进行严格验证,确保数据符合预期的格式和范围。
示例:简单的输入验证 ​
go
func validateEmail(email string) error {
    if !strings.Contains(email, "@") {
        return errors.New("invalid email address")
    }
    return nil
}
  • 最小权限原则:确保数据库用户只拥有执行其任务所需的最小权限,减少潜在的攻击面。

12.3 数据加密 ​

数据加密可以保护数据在传输和存储过程中的安全,防止数据被未授权访问和窃取。主要包括以下几种加密方式:

  • 传输层加密:使用SSL/TLS加密数据库连接,确保数据在传输过程中的安全。
示例:配置MySQL SSL连接 ​
go
package main

import (
    "crypto/tls"
    "database/sql"
    "log"

    "github.com/go-sql-driver/mysql"
)

func main() {
    dsn := "user:password@tcp(localhost:3306)/dbname?tls=custom"
    mysql.RegisterTLSConfig("custom", &tls.Config{
        InsecureSkipVerify: true,
        ServerName:         "localhost",
    })

    db, err := sql.Open("mysql", dsn)
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()
}
  • 存储层加密:对数据库中的敏感数据进行加密存储,确保即使数据文件被窃取,数据也无法被读取。
示例:使用AES加密数据 ​
go
import (
    "crypto/aes"
    "crypto/cipher"
    "crypto/rand"
    "encoding/hex"
    "io"
)

func encrypt(data, key string) (string, error) {
    block, err := aes.NewCipher([]byte(key))
    if err != nil {
        return "", err
    }

    ciphertext := make([]byte, aes.BlockSize+len(data))
    iv := ciphertext[:aes.BlockSize]
    if _, err := io.ReadFull(rand.Reader, iv); err != nil {
        return "", err
    }

    stream := cipher.NewCFBEncrypter(block, iv)
    stream.XORKeyStream(ciphertext[aes.BlockSize:], []byte(data))

    return hex.EncodeToString(ciphertext), nil
}

func decrypt(encrypted, key string) (string, error) {
    ciphertext, err := hex.DecodeString(encrypted)
    if err != nil {
        return "", err
    }

    block, err := aes.NewCipher([]byte(key))
    if err != nil {
        return "", err
    }

    iv := ciphertext[:aes.BlockSize]
    ciphertext = ciphertext[aes.BlockSize:]

    stream := cipher.NewCFBDecrypter(block, iv)
    stream.XORKeyStream(ciphertext, ciphertext)

    return string(ciphertext), nil
}

12.4 安全的数据库访问 ​

确保数据库访问的安全性可以通过以下措施:

  • 使用安全的密码:为数据库用户设置复杂且唯一的密码,并定期更改密码。
  • 限制IP访问:通过防火墙和数据库配置限制能够访问数据库的IP地址范围。
  • 启用审计日志:记录所有数据库访问和操作日志,监控和审计数据库活动。
  • 定期更新和补丁:定期更新数据库软件和操作系统,应用安全补丁,防止已知漏洞被利用。
示例:限制MySQL用户的IP访问 ​
sql
CREATE USER 'user'@'192.168.1.100' IDENTIFIED BY 'password';
GRANT ALL PRIVILEGES ON dbname.* TO 'user'@'192.168.1.100';

最要紧的一条是 SQL 注入:查询一律走参数占位符,不拼接用户输入。其余按需加:传输用 TLS,敏感字段加密存储,账号按最小权限创建,访问记录进审计日志。

参考资料 ​

同层页面 ​

相关页面 ​

Hello Golang