Objectifs
- Comprendre les risques de sécurité les plus courants en scripting Bash (injections, word splitting).
- Appliquer un “quoting” (usage des guillemets) strict pour prévenir ces failles.
- Valider les entrées externes pour éviter l’exécution de code arbitraire.
- Se méfier des commandes et variables dangereuses comme
evaletIFS.
Explications détaillées
Notions clés
Écrire des scripts Bash sûrs repose sur quelques principes fondamentaux, souvent négligés. Une simple erreur de guillemets peut transformer un script anodin en une faille de sécurité béante.
Le Quoting est la Sécurité Numéro 1
La grande majorité des vulnérabilités en shell viennent de variables non citées. Lorsque le shell rencontre une variable non entourée de guillemets doubles, il effectue deux opérations dangereuses :
- Word Splitting : Il découpe la valeur de la variable en plusieurs “mots” en se basant sur les espaces, tabulations et sauts de ligne.
- Glob Expansion : Il interprète les caractères jokers comme
*,?,[].
Exemple de catastrophe :
NOM_FICHIER="Mon rapport important.txt"
# Sans guillemets, la commande devient : rm Mon rapport important.txt
# rm essaiera de supprimer 3 choses : "Mon", "rapport", et "important.txt"
rm $NOM_FICHIER # DANGEREUX
# La bonne façon :
rm "$NOM_FICHIER" # Sûr, la commande voit un seul argument
Règle d’or : TOUJOURS citer les expansions de variables : "$VAR", "$@", "$(commande)".
Injection de Commandes
Si votre script utilise une entrée externe (argument, saisie utilisateur) pour construire une commande, un attaquant peut y injecter ses propres commandes.
# Script vulnérable
read -p "Entrez un nom de domaine à pinger : " HOST
ping -c 1 $HOST # DANGEREUX
Si l’utilisateur tape google.com; rm -rf ~, la commande deviendra ping -c 1 google.com; rm -rf ~, et le script effacera son dossier personnel.
Solution : Valider et nettoyer les entrées. Ne jamais faire confiance.
Chemins et la variable PATH
Si votre script appelle une commande simple comme ls, il utilise la variable PATH pour la trouver. Si un attaquant peut modifier le PATH pour y insérer un dossier contenant une version malveillante de ls, il peut exécuter du code arbitraire.
Solution : Dans les scripts très sensibles (exécutés en tant que root), utilisez des chemins absolus pour les commandes critiques : /bin/ls, /usr/bin/grep.
eval est le mal (eval is evil)
La commande eval prend une chaîne de caractères et l’exécute comme si elle avait été tapée dans le shell. C’est l’équivalent de donner les clés de votre système à une chaîne de caractères. Ne l’utilisez jamais avec des données dont vous ne contrôlez pas à 100% l’origine et le contenu.
Syntaxe / Usages
# Mauvais : vulnérable au word splitting et globbing
touch $FILENAME
# Bon : sûr
touch "$FILENAME"
# Mauvais : vulnérable à l'injection
read HOST
ssh root@$HOST
# Bon : validation (très basique)
read HOST
# Valide que HOST ne contient que des caractères "sûrs"
if [[ "$HOST" =~ ^[a-zA-Z0-9.-]+$ ]]; then
ssh "root@$HOST"
else
echo "Nom d'hôte invalide" >&2
exit 1
fi
Exemples
# Créez des fichiers pour voir le problème
touch "un fichier.txt" "deux.txt"
# Sans guillemets
FICHIERS=$(ls)
for f in $FICHIERS; do
echo "-> $f"
done
# Affiche "un", "fichier.txt", "deux.txt" sur des lignes séparées. Incorrect.
# Avec un tableau et des guillemets
FICHIERS_ARRAY=(*)
for f in "${FICHIERS_ARRAY[@]}"; do
echo "-> '$f'"
done
# Affiche "-> 'un fichier.txt'", "-> 'deux.txt'". Correct.
Bonnes pratiques de sécurité
set -euo pipefail: Commencez toujours vos scripts avec cette ligne.- Citez TOUT :
"$VAR","$@","$(cmd)". - Validez les entrées : Ne faites jamais confiance aux données venant de l’extérieur. Vérifiez les formats, les caractères autorisés.
- Utilisez des chemins absolus pour les commandes dans les scripts sensibles.
- N’utilisez pas
eval. Il y a presque toujours une meilleure solution (tableaux, fonctions).
Pièges courants
- Penser que le quoting est optionnel : C’est la porte d’entrée de la plupart des failles.
- Construire des commandes en concaténant des chaînes : C’est une invitation aux injections. Préférez passer les variables comme des arguments distincts à vos commandes.
- Parser la sortie de
ls: Ne le faites jamais.lsest un outil d’affichage pour les humains, pas pour les scripts.
Exercices
-
Le fichier nommé
*:- Dans un dossier vide, créez un fichier nommé
*. - Créez aussi deux autres fichiers,
a.txtetb.txt. - Exécutez
VAR="*"; echo $VAR. Que se passe-t-il ? - Maintenant, exécutez
VAR="*"; echo "$VAR". Quelle est la différence ?
- Dans un dossier vide, créez un fichier nommé
-
Script de recherche “sûr” :
- Écrivez un script
search.shqui prend un motif de recherche en premier argument et un nom de fichier en deuxième. - Le script doit exécuter
grep "$MOTIF" "$FICHIER". - Assurez-vous que le script fonctionne correctement même si le motif ou le nom de fichier contiennent des espaces ou des caractères spéciaux.
- Écrivez un script
-
Prévention d’injection :
- Créez un script qui prend un nom d’utilisateur en argument et affiche le contenu de son dossier personnel avec
ls. - Montrez comment un utilisateur malveillant pourrait passer un argument comme
toto; ls /rootpour essayer de lister un autre dossier. - Corrigez le script en validant que l’argument ne contient que des caractères alphanumériques.
- Créez un script qui prend un nom d’utilisateur en argument et affiche le contenu de son dossier personnel avec