Une bonne pratique pour renforcer la sécurité d’un système consiste à réduire les privilèges avec lesquels un programme s’exécute. Idéalement, un programme devrait tourner avec le minimum de privilèges possible.
Dans les systèmes UNIX-like, il est possible de changer l’utilisateur et le groupe sous lesquels un programme est exécuté. Voyons étape par étape comment réaliser cela en Golang.
Vérification que le programme s’exécute en tant que root
Tout d’abord, vérifiez si le programme s’exécute en tant que root. Cela est important car nous utiliserons des appels système qui exigent des privilèges de root. (Il existe d’autres façons d’accorder ces privilèges, mais nous en parlerons dans un autre article.)
Dans l’exemple ci-dessous, nous utilisons os.Getuid() pour vérifier que le programme s’exécute en tant que root. S’il n’en est pas ainsi, le programme se termine.
if os.Getuid() != 0 {
fmt.Println("exécutez en tant que root")
return
}
Évidemment, vous pouvez faire exactement l’inverse, c’est-à-dire inverser la condition pour que le programme ne tourne que s’il n’est pas root. Mais l’idée ici est que le programme s’auto-modifie pour passer à un autre utilisateur, alors poursuivons.
Vérification de l’ID utilisateur et de l’ID de groupe
Vous pouvez vérifier l’ID de l’utilisateur et celui du groupe à tout moment en utilisant les fonctions os.Getuid() et os.Getgid().
fmt.Printf(
"exécuté en tant que uid: %v, gid: %vn",
os.Getuid(),
os.Getgid(),
)
Passage à l’utilisateur « nobody »
À présent, allons modifier notre programme qui tourne comme root pour le faire passer à l’utilisateur nobody. Tout d’abord, récupérez les informations de l’utilisateur nobody avec la fonction user.Lookup.
u, err := user.Lookup("nobody")
if err != nil {
fmt.Println(err)
return
}
Avec les informations de l’utilisateur nobody, modifiez l’ID de l’utilisateur et l’ID du groupe sous lesquels le programme tourne en utilisant les appels système syscall.Setgid et syscall.Setuid.
uid, _ := strconv.Atoi(u.Uid)
gid, _ := strconv.Atoi(u.Gid)
// Ajuste l'ID du groupe
err = syscall.Setgid(gid)
if err != nil {
fmt.Println(err)
return
}
// Ajuste l'ID de l'utilisateur
err = syscall.Setuid(uid)
if err != nil {
fmt.Println(err)
return
}
A partir de ce moment, le programme s’exécute avec les privilèges de l’utilisateur nobody, c’est-à-dire avec le minimum de privilèges. Vous pouvez créer des utilisateurs spécifiques pour chaque service et exécuter le service avec le privilège exact correspondant au service.
Note : réduire les privilèges est une bonne pratique, mais cela n’empêche pas une attaque. Ce qu’elle réalise, c’est de diminuer les dégâts d’une attaque qui exploite une faille dans votre programme.
Le code complet est disponible sur GitHub.




