Chuyển tới nội dung chính

Bảo mật trong Go - Bảo vệ Ứng dụng của Bạn! 🛡️

Chào mừng bạn đến với bài học về bảo mật trong Go! Trong bài học này, chúng ta sẽ tìm hiểu cách bảo vệ ứng dụng của bạn khỏi các mối đe dọa bảo mật.

Kiểm tra Đầu vào 🔍

1. Kiểm tra Chuỗi

func validateInput(input string) error {
if len(input) == 0 {
return errors.New("không được để trống")
}
if len(input) > 100 {
return errors.New("độ dài vượt quá giới hạn")
}
if !regexp.MustCompile(`^[a-zA-Z0-9]+$`).MatchString(input) {
return errors.New("chứa ký tự không hợp lệ")
}
return nil
}

💡 Giải thích:

  • Kiểm tra độ dài chuỗi
  • Kiểm tra ký tự hợp lệ
  • Tránh dữ liệu độc hại

2. Ngăn chặn SQL Injection

// ✅ Đúng: Sử dụng tham số hóa
func getUser(db *sql.DB, id string) (*User, error) {
var user User
err := db.QueryRow("SELECT * FROM users WHERE id = $1", id).Scan(&user.ID, &user.Name)
if err != nil {
return nil, err
}
return &user, nil
}

// ❌ Sai: Nối chuỗi SQL
func getUser(db *sql.DB, id string) (*User, error) {
query := fmt.Sprintf("SELECT * FROM users WHERE id = %s", id)
// Dễ bị SQL injection
}

💡 Giải thích:

  • Sử dụng prepared statements
  • Tránh SQL injection
  • Bảo vệ database

Xác thực 🔐

1. Xác thực JWT

type Claims struct {
UserID string `json:"user_id"`
jwt.StandardClaims
}

func generateToken(userID string) (string, error) {
claims := Claims{
UserID: userID,
StandardClaims: jwt.StandardClaims{
ExpiresAt: time.Now().Add(24 * time.Hour).Unix(),
IssuedAt: time.Now().Unix(),
},
}

token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
return token.SignedString([]byte("secret"))
}

💡 Giải thích:

  • Tạo token JWT
  • Thêm thời gian hết hạn
  • Ký token an toàn

2. Mã hóa Mật khẩu

func hashPassword(password string) (string, error) {
bytes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
return string(bytes), err
}

func checkPassword(password, hash string) bool {
err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
return err == nil
}

💡 Giải thích:

  • Mã hóa mật khẩu an toàn
  • Sử dụng bcrypt
  • So sánh mật khẩu an toàn

Phân quyền 👥

1. Phân quyền theo Vai trò

type Role string
const (
RoleAdmin Role = "admin"
RoleUser Role = "user"
RoleGuest Role = "guest"
)

type User struct {
ID string
Role Role
}

func (u *User) CanAccess(resource string) bool {
switch u.Role {
case RoleAdmin:
return true
case RoleUser:
return resource != "admin"
case RoleGuest:
return resource == "public"
default:
return false
}
}

💡 Giải thích:

  • Định nghĩa vai trò
  • Kiểm tra quyền truy cập
  • Phân quyền rõ ràng

2. Phân quyền theo Hành động

type Permission struct {
Resource string
Action string
}

type User struct {
ID string
Permissions []Permission
}

func (u *User) HasPermission(resource, action string) bool {
for _, p := range u.Permissions {
if p.Resource == resource && p.Action == action {
return true
}
}
return false
}

💡 Giải thích:

  • Định nghĩa quyền chi tiết
  • Kiểm tra quyền linh hoạt
  • Dễ dàng mở rộng

Mã hóa Dữ liệu 🔒

1. Mã hóa AES

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

gcm, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}

nonce := make([]byte, gcm.NonceSize())
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
return nil, err
}

return gcm.Seal(nonce, nonce, data, nil), nil
}

💡 Giải thích:

  • Mã hóa dữ liệu an toàn
  • Sử dụng AES-GCM
  • Tạo nonce ngẫu nhiên

2. Mã hóa RSA

func generateKeyPair() (*rsa.PrivateKey, *rsa.PublicKey, error) {
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return nil, nil, err
}
return privateKey, &privateKey.PublicKey, nil
}

💡 Giải thích:

  • Tạo cặp khóa RSA
  • Độ dài khóa 2048 bit
  • An toàn cho mã hóa

HTTPS 🌐

1. Cấu hình TLS

func setupTLS() (*tls.Config, error) {
cert, err := tls.LoadX509KeyPair("cert.pem", "key.pem")
if err != nil {
return nil, err
}

return &tls.Config{
Certificates: []tls.Certificate{cert},
MinVersion: tls.VersionTLS12,
}, nil
}

💡 Giải thích:

  • Cấu hình TLS an toàn
  • Sử dụng TLS 1.2 trở lên
  • Bảo vệ kết nối

2. Header Bảo mật HTTP

func securityHeaders(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("X-Frame-Options", "DENY")
w.Header().Set("X-Content-Type-Options", "nosniff")
w.Header().Set("X-XSS-Protection", "1; mode=block")
w.Header().Set("Strict-Transport-Security", "max-age=31536000; includeSubDomains")
next.ServeHTTP(w, r)
})
}

💡 Giải thích:

  • Thêm header bảo mật
  • Ngăn chặn XSS
  • Bảo vệ khỏi clickjacking

Bảo mật File 📁

1. Kiểm tra File Upload

func validateFile(file multipart.File, header *multipart.FileHeader) error {
// Kiểm tra kích thước
if header.Size > 10<<20 { // 10MB
return errors.New("file quá lớn")
}

// Kiểm tra loại file
buff := make([]byte, 512)
_, err := file.Read(buff)
if err != nil {
return err
}

filetype := http.DetectContentType(buff)
if !strings.HasPrefix(filetype, "image/") {
return errors.New("loại file không hợp lệ")
}

return nil
}

💡 Giải thích:

  • Kiểm tra kích thước file
  • Kiểm tra loại file
  • Ngăn chặn file độc hại

2. Lưu trữ File An toàn

func saveFile(file multipart.File, filename string) error {
// Tạo tên file an toàn
ext := filepath.Ext(filename)
name := uuid.New().String()
secureFilename := name + ext

// Lưu vào thư mục an toàn
dst, err := os.Create(filepath.Join("uploads", secureFilename))
if err != nil {
return err
}
defer dst.Close()

_, err = io.Copy(dst, file)
return err
}

💡 Giải thích:

  • Tạo tên file ngẫu nhiên
  • Lưu vào thư mục an toàn
  • Tránh truy cập trực tiếp

Quản lý Phiên 🔑

1. Phiên An toàn

type Session struct {
ID string
UserID string
ExpiresAt time.Time
}

func createSession(userID string) (*Session, error) {
session := &Session{
ID: uuid.New().String(),
UserID: userID,
ExpiresAt: time.Now().Add(24 * time.Hour),
}

// Lưu vào cookie an toàn
cookie := &http.Cookie{
Name: "session",
Value: session.ID,
HttpOnly: true,
Secure: true,
SameSite: http.SameSiteStrictMode,
Expires: session.ExpiresAt,
}

return session, nil
}

💡 Giải thích:

  • Tạo phiên an toàn
  • Sử dụng cookie bảo mật
  • Thêm thời gian hết hạn

Best Practices (Cách sử dụng tốt nhất) ✅

  1. Kiểm tra đầu vào

    // ✅ Đúng
    if err := validateInput(input); err != nil {
    return err
    }

    // ❌ Sai
    // Không kiểm tra đầu vào
  2. Mã hóa mật khẩu

    // ✅ Đúng
    hashedPassword, err := hashPassword(password)

    // ❌ Sai
    // Lưu mật khẩu dạng text
  3. Sử dụng HTTPS

    // ✅ Đúng
    server := &http.Server{
    TLSConfig: tlsConfig,
    }

    // ❌ Sai
    // Không sử dụng HTTPS
  4. Quản lý phiên an toàn

    // ✅ Đúng
    cookie.Secure = true
    cookie.HttpOnly = true

    // ❌ Sai
    // Cookie không an toàn

Tiếp theo 🎯

Trong các bài học tiếp theo, chúng ta sẽ:

  • Tìm hiểu về testing
  • Học cách tối ưu hiệu suất
  • Khám phá các kỹ thuật nâng cao
  • Thực hành với các dự án thực tế

💡 Lời khuyên: Bảo mật là một quá trình liên tục. Luôn cập nhật và kiểm tra bảo mật của ứng dụng thường xuyên để bảo vệ dữ liệu và người dùng!

func forceHTTPS(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if !r.URL.IsAbs() && r.Header.Get("X-Forwarded-Proto") != "https" {
url := "https://" + r.Host + r.RequestURI
http.Redirect(w, r, url, http.StatusMovedPermanently)
return
}
next.ServeHTTP(w, r)
})
}

Rate Limiting

Rate limiter implementation

type RateLimiter struct {
ips map[string]*rate.Limiter
mu *sync.RWMutex
r rate.Limit
b int
}

Rate limit middleware

func rateLimit(next http.Handler) http.Handler {
limiter := rate.NewLimiter(rate.Every(time.Second), 10)

return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if !limiter.Allow() {
http.Error(w, "Too many requests", http.StatusTooManyRequests)
return
}
next.ServeHTTP(w, r)
})
}

Logging

Secure logging

func logSecurityEvent(event SecurityEvent) {
log.Printf("[SECURITY] %s - IP: %s - User: %s - Action: %s",
time.Now().Format(time.RFC3339),
event.IP,
event.UserID,
event.Action,
)
}

Audit logging

func auditLog(action string, user User) {
log.Printf("[AUDIT] %s - User: %s - Action: %s - Timestamp: %s",
user.ID,
user.Email,
action,
time.Now().Format(time.RFC3339),
)
}

Best Practices

  1. Luôn validate và sanitize input
  2. Sử dụng prepared statements cho database queries
  3. Implement proper authentication và authorization
  4. Sử dụng HTTPS
  5. Implement rate limiting
  6. Xử lý file upload an toàn
  7. Implement proper logging
  8. Sử dụng secure headers
  9. Implement CSRF protection
  10. Regular security audits