Fundamentos de Seguridad en Go
9 ejemplos para empezar con Seguridad - 7 básicos y 2 intermedios.
Busca en todas las páginas de la documentación
9 ejemplos para empezar con Seguridad - 7 básicos y 2 intermedios.
mkdir seclab && cd seclab && go mod init example.com/seclab.openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -nodes -subj "/CN=localhost".go install golang.org/x/vuln/cmd/govulncheck@latest.Establece MinVersion para que los clientes no puedan negociar TLS 1.0 o 1.1.
package main
import (
"crypto/tls"
"net/http"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("ok"))
})
srv := &http.Server{
Addr: ":8443",
Handler: mux,
TLSConfig: &tls.Config{
MinVersion: tls.VersionTLS12,
},
}
srv.ListenAndServeTLS("cert.pem", "key.pem")
}tls.Config en el servidor se aplica a todos los handshakes TLS en ese listener.Relacionado: Configuración de crypto/tls y Gestión de Certificados - suites de cifrado y mTLS
Nunca codifiques claves API; cárgalas al inicio y falla si faltan.
package main
import (
"fmt"
"os"
)
func mustEnv(key string) string {
v := os.Getenv(key)
if v == "" {
fmt.Fprintf(os.Stderr, "missing required env %s\n", key)
os.Exit(1)
}
return v
}
func main() {
dbURL := mustEnv("DATABASE_URL")
_ = dbURL
}.env comprometidos.Relacionado: Seguridad para Servicios Go: Valores Predeterminados y Brechas - lo que la librería estándar no proporciona
Bloquea clientes que envían cabeceras demasiado lento.
package main
import (
"net/http"
"time"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("hi"))
})
srv := &http.Server{
Addr: ":8080",
Handler: mux,
ReadHeaderTimeout: 5 * time.Second,
}
srv.ListenAndServe()
}ReadHeaderTimeout es el timeout de servidor individual más importante para listeners públicos.ListenAndServe.ReadTimeout, WriteTimeout e IdleTimeout para una cobertura completa del ciclo de vida.Relacionado: Limitación de Tasa, CORS y Cabeceras de Seguridad - middleware de borde adicional
Rechaza payloads sobredimensionados antes del trabajo de decodificación JSON.
package main
import (
"io"
"net/http"
)
func createItem(w http.ResponseWriter, r *http.Request) {
r.Body = http.MaxBytesReader(w, r.Body, 1<<20) // 1 MiB
defer r.Body.Close()
body, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, "payload too large", http.StatusRequestEntityTooLarge)
return
}
_ = body
w.WriteHeader(http.StatusCreated)
}
func main() {
mux := http.NewServeMux()
mux.HandleFunc("POST /items", createItem)
http.ListenAndServe(":8080", mux)
}MaxBytesReader devuelve 413 cuando se excede el límite.Close el cuerpo para que las conexiones keep-alive puedan ser reutilizadas.Relacionado: Validación de Entrada y Manejo Seguro de HTML/JSON - validación de esquema después de las comprobaciones de tamaño
Compara claves API o HMACs sin salida temprana en el primer byte diferente.
package main
import (
"crypto/subtle"
"fmt"
)
func main() {
provided := []byte("secret-token")
expected := []byte("secret-token")
if subtle.ConstantTimeCompare(provided, expected) == 1 {
fmt.Println("match")
}
}== simple en cadenas puede filtrar información de tiempo a través de la comparación de cortocircuito.crypto/subtle.ConstantTimeCompare requiere slices de igual longitud; normaliza la longitud primero si es necesario.bcrypt o argon2).Escapa automáticamente el contenido del usuario en respuestas HTML.
package main
import (
"html/template"
"net/http"
)
func main() {
tmpl := template.Must(template.New("p").Parse(`<p>{{.}}</p>`))
http.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
name := r.URL.Query().Get("name")
tmpl.Execute(w, name)
})
http.ListenAndServe(":8080", nil)
}html/template escapa <, >, &, comillas, previniendo XSS reflejado en contexto HTML.text/template no escapa - úsalo solo para salida no HTML.Content-Type: application/json y codifica con encoding/json.Relacionado: Validación de Entrada y Manejo Seguro de HTML/JSON - reglas de validación y codificación
Escanea tu grafo de módulos en busca de vulnerabilidades conocidas.
cd seclab
govulncheck ./...Relacionado: Escaneo de Dependencias con govulncheck y SBOM - compuertas de CI y exportación de SBOM
Nunca uses http.DefaultClient desde manejadores de servidor.
package main
import (
"context"
"io"
"net/http"
"time"
)
func fetch(ctx context.Context, url string) ([]byte, error) {
client := &http.Client{Timeout: 10 * time.Second}
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
return nil, err
}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
return io.ReadAll(resp.Body)
}
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
_, _ = fetch(ctx, "https://example.com")
}Client.Timeout limita todo el intercambio, incluyendo TLS y la lectura del cuerpo.NewRequestWithContext respeta la cancelación cuando el llamador o el servidor se apagan.Rechaza solicitudes sin un token Bearer válido antes de que se ejecuten los manejadores.
package main
import (
"context"
"net/http"
"strings"
)
type ctxKey string
const userKey ctxKey = "user"
func auth(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
h := r.Header.Get("Authorization")
if !strings.HasPrefix(h, "Bearer ") {
http.Error(w, "unauthorized", http.StatusUnauthorized)
return
}
token := strings.TrimPrefix(h, "Bearer ")
if token == "" {
http.Error(w, "unauthorized", http.StatusUnauthorized)
return
}
ctx := context.WithValue(r.Context(), userKey, token)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
func main() {
mux := http.NewServeMux()
mux.Handle("/api/", auth(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("ok"))
})))
http.ListenAndServe(":8080", mux)
}Relacionado: Patrones de Autenticación y Autorización - JWT, RBAC y OAuth2
Versiones de Stack: Esta página fue escrita para Go 1.26.x (GC predeterminado Green Tea, go fix modernizers - verifica el parche en la compilación), chi (última versión - verifica en la compilación), gin (última versión - verifica en la compilación), echo (última versión - verifica en la compilación), google.golang.org/grpc (última versión - verifica en la compilación), sigs.k8s.io/controller-runtime (última versión - verifica en la compilación), kubebuilder (última versión - verifica en la compilación), tinygo (última versión - verifica los objetivos de la placa en la compilación), wazero (última versión - verifica en la compilación) y golangci-lint (última versión - verifica en la compilación).
Revisado por Chris St. John·Última actualización: 18 jul 2026