Seguridad de aplicaciones Go: top 10 vulnerabilidades en la práctica

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Seguridad de aplicaciones Go: top 10 vulnerabilidades en la práctica



Go (Golang) es un lenguaje famoso por su rendimiento y mecanismos de seguridad integrados. Sin embargo, como cualquier herramienta, no protege al desarrollador de errores por completo. Muchas vulnerabilidades surgen no por el lenguaje en sí, sino por el uso incorrecto de sus capacidades: trabajo con gorutinas, canales, punteros o bibliotecas de terceros.



En este artículo analizaremos las 10 vulnerabilidades más comunes en aplicaciones Go. Cada punto contiene un ejemplo de código real, explicación del problema y un consejo práctico para solucionarlo. El material será útil tanto para desarrolladores Go principiantes como para ingenieros experimentados que deseen refrescar conocimientos.



1. Inyecciones SQL mediante concatenación de cadenas

El error más clásico: formar una consulta SQL concatenando cadenas con datos del usuario. Go proporciona excelentes drivers (por ejemplo, database/sql), pero no protege contra errores tontos.



Código vulnerable:

func getUser(db *sql.DB, username string) (*User, error) {    query := "SELECT id, name FROM users WHERE username = '" + username + "'"    rows, err := db.Query(query)    // ...}

Un atacante puede pasar admin' OR '1'='1 y obtener todos los usuarios.



Solución: Utilice siempre consultas parametrizadas.

func getUserSafe(db *sql.DB, username string) (*User, error) {    query := "SELECT id, name FROM users WHERE username = $1"    row := db.QueryRow(query, username)    // ...}


2. Race condition (condición de carrera) en gorutinas

Go es un lenguaje con potente soporte de concurrencia, pero sin sincronización, el acceso a datos compartidos desde diferentes gorutinas provoca un comportamiento indefinido.



Código vulnerable:

var counter int

func increment() { for i := 0; i < 1000; i++ { counter++ // no atómico }}

func main() { go increment() go increment() time.Sleep(time.Second) fmt.Println(counter) // resultado impredecible}


Solución: Utilice mutex (sync.Mutex) u operaciones atómicas (sync/atomic).

var mu sync.Mutexvar counter int

func incrementSafe() { for i := 0; i < 1000; i++ { mu.Lock() counter++ mu.Unlock() }}


3. Fuga de gorutinas (goroutine leak)

Si una gorutina iniciada se bloquea para siempre (por ejemplo, esperando datos en un canal que nunca se cerrará), se "fuga", consumiendo memoria.



Código vulnerable:

func process(jobs <-chan int) {    for j := range jobs {        go func(job int) {            time.Sleep(time.Hour) // trabajo largo            fmt.Println(job)        }(j)    }}

Si el canal jobs no se cierra, las gorutinas quedarán colgadas para siempre.



Solución: Utilice contexto (context.Context) para cancelar operaciones y controle siempre el tiempo de vida de las gorutinas.

func processSafe(ctx context.Context, jobs <-chan int) {    for j := range jobs {        select {        case <-ctx.Done():            return        default:            go func(job int) {                select {                case <-time.After(time.Hour):                    fmt.Println(job)                case <-ctx.Done():                    return                }            }(j)        }    }}


4. Manejo incorrecto de errores (panic/recover)

Usar panic() para manejar errores comunes es una mala práctica. Si panic no se captura, la aplicación se cae. Pero abusar de recover() también puede ocultar problemas críticos.



Código vulnerable:

                

Blogs

Book Recommendations