In this article
Comment écrire du code Go sécurisé
Parlons de l’importance d’écrire du code sécurisé en Go. Écrire du code sécurisé est une responsabilité fondamentale des développeurs, surtout dans un langage comme Go, largement utilisé pour créer des systèmes évolutifs et performants. La simplicité et les performances de Go en font un choix populaire pour les applications cloud natives, notamment en raison de son lien avec l’écosystème d’outils Kubernetes. Toutefois, les vulnérabilités peuvent compromettre ces avantages. Sécuriser votre code Go protège votre application et les données des utilisateurs, tout en préservant la confiance.
Quelles sont les vulnérabilités courantes qui affectent les applications écrites en Go ?
Présentation des vulnérabilités courantes dans les applications Go
Les applications Go sont exposées à différentes vulnérabilités susceptibles de compromettre leur intégrité, leur confidentialité et leur disponibilité (également connues sous le nom de triade CIA dans le jargon de la sécurité). Parmi les vulnérabilités les plus courantes, on trouve :
L’injection SQL se produit lorsque des entrées non fiables sont concaténées dans des requêtes SQL, permettant ainsi aux attaquants de manipuler leur exécution.
L’injection de commandes se produit lorsque les entrées utilisateur sont mal gérées dans des commandes shell, ce qui peut entraîner l’exécution de commandes arbitraires.
La falsification de requête côté serveur (SSRF) se produit lorsqu’une application récupère une URL fournie par l’utilisateur, ce qui peut permettre à des attaquants d’envoyer des requêtes à des services internes.
Le rôle d’outils comme Snyk Code dans la détection et la correction des vulnérabilités
Des outils comme Snyk Code jouent un rôle essentiel dans la détection et la correction des vulnérabilités des applications Go. Snyk Code analyse votre code source à la recherche de problèmes de sécurité et vous fournit des recommandations concrètes ainsi que des conseils de correction. En intégrant Snyk à votre workflow de développement, vous pouvez détecter les vulnérabilités plus tôt, réduire le risque de failles de sécurité et préserver la sécurité de votre base de code.
Exemple en Go : détecter une injection SQL avec Snyk Code
Prenons l’extrait de code Go suivant, vulnérable à une injection SQL :
package main
import (
"database/sql"
"fmt"
"log"
"net/http"
_ "github.com/lib/pq"
)
func main() {
http.HandleFunc("/user", func(w http.ResponseWriter, r *http.Request) {
username := r.URL.Query().Get("username")
db, err := sql.Open("postgres", "user=youruser dbname=yourdb sslmode=disable")
if err != nil {
log.Fatal(err)
}
defer db.Close()
query := fmt.Sprintf("SELECT * FROM users WHERE username = '%s'", username)
rows, err := db.Query(query)
if err != nil {
http.Error(w, "Database error", http.StatusInternalServerError)
return
}
defer rows.Close()
// Process rows...
})
log.Fatal(http.ListenAndServe(":8080", nil))
}Dans cet exemple, le paramètre username est directement inséré dans la requête SQL, ce qui la rend vulnérable à une injection SQL. Snyk Code peut détecter cette vulnérabilité et suggérer d’utiliser des requêtes paramétrées pour l’éviter :
query := "SELECT * FROM users WHERE username = $1"
rows, err := db.Query(query, username)1. Valider et assainir les entrées utilisateur en Go
La validation et l’assainissement des entrées sont essentiels pour protéger vos applications Go contre les vecteurs d’attaque courants, comme l’injection SQL et les attaques XSS (cross-site scripting). Ne faites jamais confiance aux entrées utilisateur, qu’elles proviennent de paramètres de requête, du corps d’une réponse JSON à une requête HTTP ou du contenu d’une base de données. Validez toujours les entrées par rapport aux schémas attendus, appliquez une logique d’assainissement si nécessaire et encodez les sorties en fonction du contexte.
Bonnes pratiques de validation des entrées en Go
Lorsque vous gérez des entrées utilisateur en Go, suivez ces bonnes pratiques :
Définissez des schémas d’entrée : utilisez des schémas stricts pour définir les entrées valides. Des bibliothèques comme
go-playground/validatorpeuvent vous aider à appliquer ces règles.Assainissez les entrées : supprimez ou échappez les caractères potentiellement dangereux des entrées utilisateur. Par exemple, encodez le HTML des entrées pour empêcher les attaques XSS. Cette pratique est notamment utile et prise en charge par les outils de moteur de template.
Utilisez des requêtes paramétrées : empêchez les injections SQL en utilisant des requêtes paramétrées plutôt que la concaténation de chaînes.
Encodez les sorties : encodez les sorties en fonction du contexte, par exemple en HTML pour les pages Web ou en JSON pour les réponses d’API.
Exemple en Go : liaison de paramètres pour prévenir les injections SQL
Une injection SQL est une grave vulnérabilité de sécurité au niveau de l’application, qui se produit lorsque les entrées utilisateur sont directement incluses dans des requêtes SQL. Pour l’éviter, utilisez des requêtes paramétrées :
import (
"database/sql"
_ "github.com/go-sql-driver/mysql"
)
func getUser(db *sql.DB, userID string) (User, error) {
var user User
err := db.QueryRow("SELECT id, name FROM users WHERE id = ?", userID).Scan(&user.ID, &user.Name)
if err != nil {
return user, err
}
return user, nil
}Dans cet exemple, le paramètre fictif ? de la requête SQL est remplacé en toute sécurité par le paramètre userID, ce qui empêche les attaques par injection SQL. Cette bonne pratique de sécurité aide le moteur de base de données à distinguer le sens initial de la requête des valeurs qu’elle utilise.
2. Éviter l’utilisation de sous-shells en Go
En Go, l’utilisation de sous-shells consiste à lancer des sous-processus à l’aide de fonctions comme exec.CommandContext() ou exec.Command(). Bien que ces fonctions offrent de la flexibilité, elles présentent également des risques de sécurité importants, notamment des vulnérabilités d’injection de commandes. Une injection de commandes se produit lorsqu’un attaquant manipule des données d’entrée pour exécuter des commandes arbitraires sur le système hôte. Cela peut entraîner un accès non autorisé aux données, leur corruption, voire une compromission plus grave du système.
Alternatives à l’utilisation de sous-shells en Go : API de bibliothèques natives, FFI, etc.
Pour atténuer les risques associés à l’utilisation de sous-shells, les développeurs devraient privilégier les API des bibliothèques natives de Go ou l’interface de fonctions externes (FFI) pour effectuer les tâches qui nécessiteraient autrement des commandes externes. La bibliothèque standard de Go est robuste et fournit de nombreux utilitaires pour manipuler des fichiers, traiter des images et bien plus encore, qui peuvent souvent remplacer le recours aux sous-shells.
Exemple en Go : injection de commandes lors du traitement d’images
Prenons l’exemple d’une entrée utilisateur utilisée pour manipuler un fichier image. Il illustre un piège courant susceptible d’entraîner une injection de commandes :
package main
import (
"os/exec"
)
func manipulateImage(targetFilename string) error {
convertCmd := fmt.Sprintf("convert %s -resize %sx%s %s", targetFilename, fileSize, fileSize, targetFilename)
_, err = exec.CommandContext(ctx, "sh", "-c", convertCmd).CombinedOutput()
}
Dans cet exemple, si targetFilename provient d’une entrée utilisateur, un attaquant pourrait injecter des commandes supplémentaires en créant un nom de fichier malveillant. Par exemple, un nom de fichier comme image.png; rm -rf /tmp pourrait exécuter une commande destructrice s’il n’est pas correctement assaini.
Le risque vient de l’utilisation directe des entrées utilisateur pour construire des commandes shell, mais aussi du fait que le code n’utilise pas d’arguments de commande préparés pour construire la commande. Pour atténuer ce risque, envisagez les stratégies suivantes :
Utilisez des bibliothèques natives : plutôt que de dépendre de programmes externes en ligne de commande, utilisez les bibliothèques natives de Go.
Validez et assainissez les entrées : validez et assainissez toujours les entrées utilisateur afin de vérifier qu’elles respectent les formats attendus. Vous empêcherez ainsi l’exécution d’entrées malveillantes. L’exemple de code vulnérable devrait éviter l’interpolation directe dans un shell via
sh -cet exécuter la commande directement. Cela peut toutefois entraîner des vulnérabilités d’injection d’arguments, qui doivent être correctement assainis et échappés.
3. Composer des URL de manière sécurisée
La nécessité de composer des URL sécurisées est directement liée à l’une des 10 principales vulnérabilités de sécurité de l’OWASP : la falsification de requête côté serveur (SSRF). La SSRF est une vulnérabilité de sécurité critique qui permet à un attaquant de manipuler un serveur pour lui faire envoyer des requêtes HTTP non prévues, par exemple vers des ressources internes, d’autres microservices privés ou tout autre service non autorisé. Cela peut entraîner un accès non autorisé à des services internes, l’exfiltration de données, voire l’exécution de code à distance. Pour comprendre la SSRF en détail, consultez la leçon Snyk Learn sur la SSRF.
Stratégies pour composer des URL sûres en Go
Lorsque vous composez des URL en Go, en particulier si des entrées utilisateur sont concernées, il est essentiel de mettre en œuvre des stratégies de protection contre la SSRF. Voici quelques bonnes pratiques :
Validez les URL : vérifiez toujours les URL fournies par l’utilisateur par rapport à une liste d’autorisation de domaines ou de formats approuvés et vérifiés. Vous vous assurez ainsi que seules des requêtes légitimes sont envoyées.
Analysez les URL : utilisez le package
net/urlde Go pour analyser et valider les URL. Vous pouvez ainsi décomposer une URL en différents éléments et vérifier chacun d’entre eux. À cette étape, par exemple, vous pouvez appliquer un contrôle de sécurité pour n’autoriser qu’un ensemble précis de protocoles pris en charge (https://), à l’exclusion dehttpet des autres protocoles.Limitez l’accès au réseau interne : veillez à ce que votre application n’envoie pas de requêtes à des adresses IP internes ou à des points de terminaison sensibles. Pour cela, utilisez des sidecars Kubernetes, des proxys HTTP, des passerelles d’API et d’autres contrôles de sécurité tenant compte du réseau.
Définissez des délais d’expiration et des limites : même si cette mesure n’est pas directement liée à la SSRF, définir des délais d’expiration adaptés et limiter la taille des réponses des requêtes sortantes aide à prévenir l’épuisement des ressources et l’exfiltration de volumes importants de données, afin de réduire l’impact d’une SSRF.
Exemple en Go : vulnérabilité SSRF due à des URL fournies par l’utilisateur
L’exemple suivant montre une manière non sécurisée de gérer des URL fournies par l’utilisateur, susceptible d’entraîner une vulnérabilité SSRF :
package main
import (
"net/http"
)
func fetchUserProfileImage(userURL string) (*http.Response, error) {
// Directly using user input to fetch remote data
resp, err := http.Get(userURL)
return resp, err
}Dans ce code, la fonction fetchUserProfileImage récupère une URL auprès de l’utilisateur et l’utilise directement dans une requête HTTP GET. Un attaquant peut exploiter cela pour envoyer des requêtes à des services internes.
Conclusion
Écrire du code Go sécurisé demande de la vigilance et le respect des bonnes pratiques. Voici les principaux contrôles de sécurité dont nous avons parlé pour sécuriser le développement en Go :
Validez et assainissez les entrées utilisateur qui circulent dans les chemins d’exécution du code Go.
Évitez les opérations en sous-shell et privilégiez les API et les FFI natives de Go lorsqu’elles existent.
Traitez avec la plus grande prudence les URL provenant d’entrées utilisateur afin de prévenir les vulnérabilités SSRF.
Utilisez Snyk Code pour effectuer une analyse de sécurité en continu
Passez à l’étape suivante pour sécuriser vos applications Go. Créez gratuitement un compte Snyk dès aujourd’hui et commencez à intégrer la sécurité à votre workflow de développement. Avec Snyk, vous pouvez créer des applications sécurisées en toute confiance et protéger vos utilisateurs.
Pour garantir la sécurité de votre code Go, utilisez Snyk Code. L’analyse de sécurité continue vous aide à détecter et à corriger les vulnérabilités de votre base de code avant qu’elles ne deviennent problématiques.
Découvrez Snyk Code en action dans mon IDE VS Code : il détecte les problèmes et utilise un moteur d’apprentissage automatique pour me proposer des améliorations afin d’écrire du code plus sécurisé en Golang :

Participez à Fetch the Flag 2026 !
Mettez vos compétences en sécurité à l’épreuve lors de notre événement Capture the Flag, les 12 et 13 février, de midi à midi (heure de l’Est).