Seguridad de aplicaciones Go: top 10 vulnerabilidades para principiantes
Go (Golang) es conocido por su rendimiento y mecanismos de seguridad integrados, como el tipado estricto y la gestión automática de memoria. Sin embargo, como cualquier otro lenguaje, no protege al desarrollador de errores lógicos, manejo incorrecto de entradas o configuraciones inseguras. En este artículo analizaremos las 10 principales vulnerabilidades que enfrentan los desarrolladores principiantes de Go y mostraremos cómo evitarlas.
1. Inyección SQL (SQL Injection)
La vulnerabilidad más común en aplicaciones web. Ocurre cuando la entrada del usuario se concatena directamente en una consulta SQL.
Código peligroso:
username := r.URL.Query().Get("username")query := fmt.Sprintf("SELECT * FROM users WHERE name='%s'", username)rows, err := db.Query(query)Código seguro (usando consultas parametrizadas):
username := r.URL.Query().Get("username")query := "SELECT * FROM users WHERE name=$1"rows, err := db.Query(query, username)Consejo: Siempre use placeholders ($1, ? o @p1) según su base de datos. Nunca construya consultas con fmt.Sprintf usando datos del usuario.
2. Cross-Site Scripting (XSS)
La vulnerabilidad ocurre cuando la aplicación muestra entrada de usuario sin validar en código HTML. En Go, esto sucede a menudo al usar html/template sin escape.
Código peligroso:
tmpl := template.Must(template.New("page").Parse("<h1>{{.}}</h1>"))tmpl.Execute(w, r.URL.Query().Get("name")) // <script>alert('xss')</script>El paquete integrado html/template escapa automáticamente la salida, por lo que en el caso estándar está protegido. Pero tenga cuidado con las funciones template.HTML — desactivan el escape.
Enfoque seguro: Use text/template solo para datos de texto, y para web use html/template. Evite usar template.HTML a menos que sea absolutamente necesario.
3. Race Conditions (Condiciones de carrera)
Go usa activamente gorutinas, y si varias gorutinas leen y escriben simultáneamente en una misma variable sin sincronización, ocurre una condición de carrera. Esto puede llevar a un estado incorrecto de la aplicación y fuga de datos.
Código peligroso:
var counter intfor i := 0; i < 1000; i++ { go func() { counter++ // ¡Inseguro! }()}Código seguro (usando mutex):
var ( counter int mu sync.Mutex)for i := 0; i < 1000; i++ { go func() { mu.Lock() counter++ mu.Unlock() }()}Consejo: Siempre use sync.Mutex, sync.RWMutex u operaciones atómicas (sync/atomic) al trabajar con datos compartidos. Ejecute pruebas con la bandera -race para detectar condiciones de carrera.
4. Path Traversal (Recorrido de rutas)
La vulnerabilidad permite a un atacante leer archivos fuera del directorio permitido usando caracteres ../.
Código peligroso:
filename := r.URL.Query().Get("file")data, _ := os.ReadFile("/data/" + filename) // /data/../../etc/passwdCódigo seguro (limpiando la ruta):
filename := r.URL.Query().Get("file")cleanPath := filepath.Clean("/data/" + filename)if !strings.HasPrefix(cleanPath, "/data/") { http.Error(w, "Invalid path", http.StatusBadRequest) return}data, _ := os.ReadFile(cleanPath)Consejo: Use