---
title: "Go Security: Boas Práticas de Segurança"
url: "https://golang.com.br/tutoriais/go-security/"
markdown_url: "https://golang.com.br/tutoriais/go-security.MD"
description: "Aprenda boas práticas de segurança para aplicações Go. Guia completo sobre validação de input, autenticação, autorização, vulnerabilidades comuns e OWASP para Go."
date: "2026-02-11"
author: ""
---

# Go Security: Boas Práticas de Segurança

Aprenda boas práticas de segurança para aplicações Go. Guia completo sobre validação de input, autenticação, autorização, vulnerabilidades comuns e OWASP para Go.


# Go Security: Boas Práticas de Segurança


## Introdução

Segurança em aplicações Go é fundamental para proteger dados sensíveis, prevenir ataques e garantir conformidade com regulamentações como LGPD e GDPR. Embora Go seja uma linguagem segura por design (memory safety, type safety), **vulnerabilidades de segurança ainda ocorrem** principalmente devido a práticas de codificação inadequadas.

Neste guia, você vai aprender as **melhores práticas de segurança** para desenvolver aplicações Go robustas e protegidas contra as ameaças mais comuns.

## Princípios de Segurança em Go

### 1. Segurança por Padrão (Secure by Default)

```go
// ❌ INSEGURO: Configurações inseguras por padrão
http.ListenAndServe(":8080", nil) // Sem timeout, sem TLS

// ✅ SEGURO: Configurações seguras por padrão
srv := &http.Server{
    Addr:         ":8443",
    Handler:      handler,
    ReadTimeout:  5 * time.Second,
    WriteTimeout: 10 * time.Second,
    IdleTimeout:  120 * time.Second,
    TLSConfig:    &tls.Config{
        MinVersion: tls.VersionTLS12,
        CurvePreferences: []tls.CurveID{
            tls.X25519,
            tls.CurveP256,
        },
        CipherSuites: []uint16{
            tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
            tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
            tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
            tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
        },
    },
}
log.Fatal(srv.ListenAndServeTLS("cert.pem", "key.pem"))
```

### 2. Princípio do Menor Privilégio

```go
// ❌ INSEGURO: Rodando com privilégios excessivos
// Aplicação com root pode comprometer todo o sistema

// ✅ SEGURO: Executar com usuário não-privilegiado
import "os/user"

func dropPrivileges() error {
    // Criar usuário dedicado para a aplicação
    // useradd -r -s /bin/false goapp
    
    usr, err := user.Lookup("goapp")
    if err != nil {
        return err
    }
    
    uid, _ := strconv.Atoi(usr.Uid)
    gid, _ := strconv.Atoi(usr.Gid)
    
    if err := syscall.Setgid(gid); err != nil {
        return err
    }
    if err := syscall.Setuid(uid); err != nil {
        return err
    }
    
    return nil
}
```

## Validação de Input

A validação inadequada de input é a **causa #1 de vulnerabilidades**. Sempre valide dados vindos de fontes externas.

### Validação com go-playground/validator

```go
package main

import (
    "fmt"
    "github.com/go-playground/validator/v10"
)

type User struct {
    Name     string `validate:"required,min=2,max=100"`
    Email    string `validate:"required,email"`
    Age      int    `validate:"gte=18,lte=120"`
    Password string `validate:"required,min=8,containsany=~!@#$%^&*"`
    Website  string `validate:"omitempty,url"`
}

func validateUser(user *User) error {
    validate := validator.New()
    
    // Validar estrutura
    if err := validate.Struct(user); err != nil {
        if validationErrors, ok := err.(validator.ValidationErrors); ok {
            for _, err := range validationErrors {
                fmt.Printf("Campo '%s' falhou na validação: %s\n", 
                    err.Field(), err.Tag())
            }
        }
        return err
    }
    
    return nil
}

func main() {
    user := &User{
        Name:     "Jo",
        Email:    "invalid-email",
        Age:      16,
        Password: "123",
    }
    
    if err := validateUser(user); err != nil {
        fmt.Println("Validação falhou:", err)
    }
}
```

### Sanitização de Input

```go
import (
    "html"
    "strings"
    "github.com/microcosm-cc/bluemonday"
)

// Sanitizar HTML para prevenir XSS
func sanitizeHTML(input string) string {
    p := bluemonday.UGCPolicy()
    return p.Sanitize(input)
}

// Escape para evitar XSS em templates
func escapeForHTML(input string) string {
    return html.EscapeString(input)
}

// Sanitizar strings
func sanitizeString(input string) string {
    // Remover caracteres de controle
    sanitized := strings.Map(func(r rune) rune {
        if r >= 32 && r != 127 {
            return r
        }
        return -1
    }, input)
    
    // Trim espaços
    return strings.TrimSpace(sanitized)
}
```

### Validação de Arquivos Upload

```go
func handleFileUpload(w http.ResponseWriter, r *http.Request) {
    // Limitar tamanho do upload (10MB)
    r.Body = http.MaxBytesReader(w, r.Body, 10<<20)
    
    file, header, err := r.FormFile("upload")
    if err != nil {
        http.Error(w, "Arquivo muito grande", http.StatusBadRequest)
        return
    }
    defer file.Close()
    
    // Validar extensão
    allowedExts := map[string]bool{
        ".jpg": true, ".jpeg": true, ".png": true, ".gif": true,
    }
    ext := strings.ToLower(filepath.Ext(header.Filename))
    if !allowedExts[ext] {
        http.Error(w, "Tipo de arquivo não permitido", http.StatusBadRequest)
        return
    }
    
    // Validar tipo MIME real
    buffer := make([]byte, 512)
    n, _ := file.Read(buffer)
    contentType := http.DetectContentType(buffer[:n])
    
    allowedTypes := map[string]bool{
        "image/jpeg": true, "image/png": true, "image/gif": true,
    }
    if !allowedTypes[contentType] {
        http.Error(w, "Tipo de conteúdo inválido", http.StatusBadRequest)
        return
    }
    
    // Gerar nome de arquivo seguro
    filename := uuid.New().String() + ext
    filepath := filepath.Join("/uploads", filename)
    
    // Salvar arquivo
    dst, err := os.Create(filepath)
    if err != nil {
        http.Error(w, "Erro ao salvar arquivo", http.StatusInternalServerError)
        return
    }
    defer dst.Close()
    
    // Copiar conteúdo
    file.Seek(0, 0)
    if _, err := io.Copy(dst, file); err != nil {
        http.Error(w, "Erro ao processar arquivo", http.StatusInternalServerError)
        return
    }
    
    fmt.Fprintf(w, "Arquivo salvo: %s", filename)
}
```

## Autenticação Segura

### Hashing de Senhas com bcrypt

```go
import "golang.org/x/crypto/bcrypt"

// HashPassword cria um hash seguro da senha
func HashPassword(password string) (string, error) {
    // Custo 12 é um bom equilíbrio entre segurança e performance
    bytes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
    return string(bytes), err
}

// CheckPasswordHash verifica se a senha corresponde ao hash
func CheckPasswordHash(password, hash string) bool {
    err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
    return err == nil
}

// Uso
func main() {
    password := "senha-super-secreta-123!"
    
    hash, err := HashPassword(password)
    if err != nil {
        log.Fatal(err)
    }
    
    match := CheckPasswordHash(password, hash)
    fmt.Println("Senha correta:", match) // true
}
```

### JWT (JSON Web Tokens)

```go
import "github.com/golang-jwt/jwt/v5"

type Claims struct {
    UserID   uint   `json:"user_id"`
    Username string `json:"username"`
    jwt.RegisteredClaims
}

func generateToken(userID uint, username string) (string, error) {
    claims := Claims{
        UserID:   userID,
        Username: username,
        RegisteredClaims: jwt.RegisteredClaims{
            ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)),
            IssuedAt:  jwt.NewNumericDate(time.Now()),
            Issuer:    "minha-app",
        },
    }
    
    token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
    return token.SignedString([]byte(os.Getenv("JWT_SECRET")))
}

func validateToken(tokenString string) (*Claims, error) {
    token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) {
        // Verificar algoritmo
        if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
            return nil, fmt.Errorf("método de assinatura inesperado: %v", token.Header["alg"])
        }
        return []byte(os.Getenv("JWT_SECRET")), nil
    })
    
    if err != nil {
        return nil, err
    }
    
    if claims, ok := token.Claims.(*Claims); ok && token.Valid {
        return claims, nil
    }
    
    return nil, errors.New("token inválido")
}
```

### Middleware de Autenticação

```go
func AuthMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        authHeader := r.Header.Get("Authorization")
        if authHeader == "" {
            http.Error(w, "Token não fornecido", http.StatusUnauthorized)
            return
        }
        
        // Extrair Bearer token
        parts := strings.SplitN(authHeader, " ", 2)
        if len(parts) != 2 || parts[0] != "Bearer" {
            http.Error(w, "Formato de token inválido", http.StatusUnauthorized)
            return
        }
        
        claims, err := validateToken(parts[1])
        if err != nil {
            http.Error(w, "Token inválido", http.StatusUnauthorized)
            return
        }
        
        // Adicionar claims ao contexto
        ctx := context.WithValue(r.Context(), "user", claims)
        next.ServeHTTP(w, r.WithContext(ctx))
    })
}

// Uso
http.Handle("/api/protected", AuthMiddleware(http.HandlerFunc(protectedHandler)))
```

## Autorização e Controle de Acesso

### RBAC (Role-Based Access Control)

```go
type Role string

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

type Permission string

const (
    PermRead   Permission = "read"
    PermWrite  Permission = "write"
    PermDelete Permission = "delete"
)

var rolePermissions = map[Role][]Permission{
    RoleAdmin:  {PermRead, PermWrite, PermDelete},
    RoleUser:   {PermRead, PermWrite},
    RoleGuest:  {PermRead},
}

func hasPermission(role Role, perm Permission) bool {
    perms, exists := rolePermissions[role]
    if !exists {
        return false
    }
    
    for _, p := range perms {
        if p == perm {
            return true
        }
    }
    return false
}

// Middleware de autorização
func RequirePermission(perm Permission) func(http.Handler) http.Handler {
    return func(next http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            user := r.Context().Value("user").(*Claims)
            // Buscar role do usuário no banco...
            role := getUserRole(user.UserID)
            
            if !hasPermission(role, perm) {
                http.Error(w, "Acesso negado", http.StatusForbidden)
                return
            }
            
            next.ServeHTTP(w, r)
        })
    }
}
```

## Proteção Contra Vulnerabilidades Comuns

### SQL Injection

```go
// ❌ INSEGURO: Concatenação de strings
query := fmt.Sprintf("SELECT * FROM users WHERE email = '%s'", email)
db.Query(query) // Vulnerável a SQL Injection

// ✅ SEGURO: Prepared statements
db.Query("SELECT * FROM users WHERE email = ?", email)

// ✅ SEGURO: Com sqlx
var user User
err := db.Get(&user, "SELECT * FROM users WHERE email = $1", email)

// ✅ SEGURO: Com GORM
db.Where("email = ?", email).First(&user)
```

### XSS (Cross-Site Scripting)

```go
// ❌ INSEGURO: Renderização direta
template.Execute(w, map[string]string{
    "Name": userInput, // Vulnerável a XSS
})

// ✅ SEGURO: Auto-escape de templates
type PageData struct {
    Name    string
    Content template.HTML // Só use para conteúdo confiável
}

tmpl := template.Must(template.New("page").Parse(`
    <h1>{{.Name}}</h1> <!-- Auto-escapado -->
    <div>{{.Content}}</div> <!-- HTML permitido -->
`))

// ✅ SEGURO: CSP Headers
func securityHeaders(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Content-Security-Policy", 
            "default-src 'self'; "+
            "script-src 'self' 'unsafe-inline'; "+
            "style-src 'self' 'unsafe-inline';")
        w.Header().Set("X-Content-Type-Options", "nosniff")
        w.Header().Set("X-Frame-Options", "DENY")
        w.Header().Set("X-XSS-Protection", "1; mode=block")
        w.Header().Set("Referrer-Policy", "strict-origin-when-cross-origin")
        next.ServeHTTP(w, r)
    })
}
```

### CSRF (Cross-Site Request Forgery)

```go
import "github.com/gorilla/csrf"

func main() {
    mux := http.NewServeMux()
    mux.HandleFunc("/", homeHandler)
    mux.HandleFunc("/transfer", transferHandler)
    
    // Proteger com CSRF
    csrfMiddleware := csrf.Protect(
        []byte(os.Getenv("CSRF_KEY")),
        csrf.Secure(true), // Apenas HTTPS em produção
    )
    
    log.Fatal(http.ListenAndServe(":8080", csrfMiddleware(mux)))
}

// No template HTML
// <input type="hidden" name="gorilla.csrf.Token" value="{{.csrfToken}}">
```

### Insecure Deserialization

```go
// ❌ INSEGURO: Deserialização sem validação
data, _ := ioutil.ReadFile("data.gob")
gob.NewDecoder(bytes.NewReader(data)).Decode(&obj)

// ✅ SEGURO: Validação de integridade
func safeUnmarshal(data []byte, signature []byte, key []byte, v interface{}) error {
    // Verificar HMAC
    mac := hmac.New(sha256.New, key)
    mac.Write(data)
    expectedMAC := mac.Sum(nil)
    
    if !hmac.Equal(signature, expectedMAC) {
        return errors.New("assinatura inválida")
    }
    
    return json.Unmarshal(data, v)
}
```

### Path Traversal

```go
// ❌ INSEGURO: Acesso direto a arquivos
http.ServeFile(w, r, "./uploads/"+filename)

// ✅ SEGURO: Validação de caminho
func safeFileHandler(w http.ResponseWriter, r *http.Request) {
    filename := r.URL.Query().Get("file")
    
    // Sanitizar e validar
    safePath := filepath.Clean(filename)
    if strings.Contains(safePath, "..") {
        http.Error(w, "Acesso negado", http.StatusForbidden)
        return
    }
    
    fullPath := filepath.Join("/app/uploads", safePath)
    
    // Verificar se está dentro do diretório permitido
    if !strings.HasPrefix(fullPath, "/app/uploads") {
        http.Error(w, "Acesso negado", http.StatusForbidden)
        return
    }
    
    http.ServeFile(w, r, fullPath)
}
```

## Segurança de Dependências

### Verificação de Vulnerabilidades

```bash
# Instalar govulncheck
go install golang.org/x/vuln/cmd/govulncheck@latest

# Verificar vulnerabilidades
govulncheck ./...

# Verificar dependências específicas
govulncheck -v ./...
```

### Gerenciamento Seguro de Secrets

```go
// ❌ INSEGURO: Hardcoded secrets
apiKey := "sk_live_1234567890abcdef"

// ✅ SEGURO: Environment variables
apiKey := os.Getenv("API_KEY")
if apiKey == "" {
    log.Fatal("API_KEY não configurada")
}

// ✅ SEGURO: Secret managers
import "github.com/aws/aws-sdk-go-v2/service/secretsmanager"

func getSecret(secretName string) (string, error) {
    cfg, err := config.LoadDefaultConfig(context.Background())
    if err != nil {
        return "", err
    }
    
    client := secretsmanager.NewFromConfig(cfg)
    result, err := client.GetSecretValue(context.Background(), 
        &secretsmanager.GetSecretValueInput{
            SecretId: aws.String(secretName),
        })
    
    if err != nil {
        return "", err
    }
    
    return *result.SecretString, nil
}
```

### Verificação de Checksums

```go
func verifyChecksum(filepath string, expectedHash string) error {
    file, err := os.Open(filepath)
    if err != nil {
        return err
    }
    defer file.Close()
    
    hash := sha256.New()
    if _, err := io.Copy(hash, file); err != nil {
        return err
    }
    
    computedHash := hex.EncodeToString(hash.Sum(nil))
    if computedHash != expectedHash {
        return fmt.Errorf("checksum mismatch: got %s, want %s", computedHash, expectedHash)
    }
    
    return nil
}
```

## Logging e Monitoramento de Segurança

```go
import "github.com/rs/zerolog/log"

func securityLogger() *zerolog.Logger {
    logger := zerolog.New(os.Stdout).With().
        Timestamp().
        Str("service", "api").
        Logger()
    
    return &logger
}

// Log de eventos de segurança
func logAuthEvent(userID uint, action string, success bool) {
    logger := securityLogger()
    
    event := logger.Info()
    if !success {
        event = logger.Warn()
    }
    
    event.
        Str("event_type", "auth").
        Str("action", action).
        Uint("user_id", userID).
        Bool("success", success).
        Str("ip", getClientIP()).
        Str("user_agent", getUserAgent()).
        Msg("auth event")
}

// Middleware de audit logging
func auditMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        start := time.Now()
        
        // Capturar response status
        wrapped := &responseWriter{ResponseWriter: w, statusCode: http.StatusOK}
        
        next.ServeHTTP(wrapped, r)
        
        log.Info().
            Str("method", r.Method).
            Str("path", r.URL.Path).
            Str("remote_addr", r.RemoteAddr).
            Int("status", wrapped.statusCode).
            Dur("duration", time.Since(start)).
            Msg("HTTP request")
    })
}
```

## OWASP Top 10 para Go

| # | Vulnerabilidade | Prevenção em Go |
|---|-----------------|-----------------|
| 1 | Broken Access Control | RBAC, middleware de autorização |
| 2 | Cryptographic Failures | bcrypt, TLS 1.2+, crypto/rand |
| 3 | Injection | Prepared statements, ORM |
| 4 | Insecure Design | Principio do menor privilégio |
| 5 | Security Misconfiguration | Configurações seguras por padrão |
| 6 | Vulnerable Components | govulncheck, dependabot |
| 7 | Auth Failures | bcrypt, JWT seguro, MFA |
| 8 | Data Integrity Failures | Assinaturas digitais, HMAC |
| 9 | Logging Failures | Structured logging, SIEM |
| 10 | SSRF | Validação de URLs, whitelist |

## Próximos Passos

Agora que você domina segurança em Go, explore:

1. **[Go e Kubernetes: Deploy de Containers](#go-kubernetes)** - Segurança em orquestração
2. **[Go Observability: Logs, Métricas e Traces](#go-observability)** - Monitore ameaças
3. **[Go Performance: Profiling e Otimização](#go-performance)** - Segurança com performance

## FAQ

### Go é seguro por padrão?

Go é **memory-safe** e **type-safe**, prevenindo vulnerabilidades comuns em C/C++. No entanto, vulnerabilidades de aplicação (SQL injection, XSS) ainda ocorrem e precisam de atenção do desenvolvedor.

### Como protejo contra timing attacks?

Use `subtle.ConstantTimeCompare` para comparações sensíveis:

```go
if subtle.ConstantTimeCompare([]byte(a), []byte(b)) == 1 {
    // Iguais
}
```

### Qual a melhor prática para senhas?

Use **bcrypt** com custo 12-14. Nunca use MD5, SHA1 ou SHA256 para senhas.

### Preciso usar HTTPS em desenvolvimento?

Para features como cookies Secure e HSTS, sim. Use `mkcert` para certificados locais confiáveis.

---

**Referências:**
- [OWASP Go Security Guide](https://owasp.org/www-project-go-security/)
- [Go Security Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Go_Security_Cheat_Sheet.html)
- [Go Cryptography](https://pkg.go.dev/golang.org/x/crypto)
