Sécurité des applications Go : top 10 des vulnérabilités en pratique

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Sécurité des applications Go : top 10 des vulnérabilités en pratique



Go (Golang) est un langage réputé pour ses performances et ses mécanismes de sécurité intégrés. Cependant, comme tout outil, il ne protège pas complètement le développeur contre les erreurs. De nombreuses vulnérabilités surviennent non pas à cause du langage lui-même, mais d'une mauvaise utilisation de ses fonctionnalités : travail avec les goroutines, les canaux, les pointeurs ou les bibliothèques tierces.



Dans cet article, nous analyserons les 10 vulnérabilités les plus courantes dans les applications Go. Chaque point contient un exemple de code réel, une explication du problème et un conseil pratique pour le résoudre. Ce contenu sera utile aussi bien aux développeurs Go débutants qu'aux ingénieurs expérimentés souhaitant rafraîchir leurs connaissances.



1. Injections SQL par concaténation de chaînes

L'erreur classique par excellence : la construction d'une requête SQL en concaténant des chaînes avec des données utilisateur. Go fournit d'excellents pilotes (par exemple, database/sql), mais ne protège pas contre les erreurs stupides.



Code vulnérable :

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

Un attaquant peut transmettre admin' OR '1'='1 et obtenir tous les utilisateurs.



Solution : Utilisez toujours des requêtes paramétrées.

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 (condition de concurrence) dans les goroutines

Go est un langage avec un puissant support de la concurrence, mais sans synchronisation, l'accès aux données partagées depuis différentes goroutines entraîne un comportement indéfini.



Code vulnérable :

var counter int

func increment() { for i := 0; i < 1000; i++ { counter++ // non atomique }}

func main() { go increment() go increment() time.Sleep(time.Second) fmt.Println(counter) // résultat imprévisible}


Solution : Utilisez des mutex (sync.Mutex) ou des opérations atomiques (sync/atomic).

var mu sync.Mutexvar counter int

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


3. Fuite de goroutines (goroutine leak)

Si une goroutine lancée se bloque indéfiniment (par exemple, en attendant des données dans un canal qui ne sera jamais fermé), elle « fuit », consommant de la mémoire.



Code vulnérable :

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

Si le canal jobs n'est pas fermé, les goroutines resteront suspendues indéfiniment.



Solution : Utilisez un contexte (context.Context) pour annuler les opérations et contrôlez toujours la durée de vie des goroutines.

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. Mauvaise gestion des erreurs (panic/recover)

Utiliser panic() pour gérer des erreurs ordinaires est une mauvaise pratique. Si une panic n'est pas interceptée, l'application plante. Mais abuser de recover() peut également masquer des problèmes critiques.



Code vulnérable :

                

Blogs

Book Recommendations