Prévenir l’injection de commandes et d’arguments
Protégez, validez et transmettez sous forme de tableaux les entrées non fiables afin d’éliminer le découpage en mots et les injections fondées sur eval.
Prévenir l’injection de commandes et d’arguments est une leçon Linux Command Line & Bash Scripting Mastery gratuite sur CoddyKit. Ceci est la leçon 1 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage Linux Command Line & Bash Scripting Mastery, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours Linux Command Line & Bash Scripting Mastery comprend 4 leçons au total.
Pourquoi les attaques par injection se produisent dans Bash
Bash est un puissant langage de liaison : il transmet directement du texte au noyau, à d’autres programmes et à des sous-interpréteurs. Cette puissance devient un risque dès que des données d’entrée non fiables parviennent à une commande sans validation ni protection par des guillemets.
Deux causes fondamentales sont à l’origine de presque toutes les injections dans Bash :
- Découpage en mots : les variables qui ne sont pas entre guillemets sont découpées selon les espaces (
IFS), transformant une valeur logique en plusieurs éléments du shell. - Expansion des motifs : les caractères comme
*,?et[sont développés par le shell avant même l’exécution de la commande.
Un attaquant qui contrôle un nom de fichier, un nom d’utilisateur, un paramètre d’URL ou une variable d’environnement peut exploiter ces deux mécanismes pour exécuter des commandes arbitraires, lire des fichiers ou élever ses privilèges.
Cette leçon montre précisément comment ces vulnérabilités apparaissent et, surtout, comment les éliminer grâce à une protection correcte par des guillemets, à la validation des entrées et au passage des arguments au moyen de tableaux.
Le découpage en mots : la menace silencieuse
Lorsqu’il rencontre une variable qui n’est pas entre guillemets, Bash découpe sa valeur selon tout caractère répertorié dans $IFS (valeur par défaut : espace, tabulation, saut de ligne). Ce qui semble être un seul argument devient ainsi plusieurs arguments.
Exécutez le script ci-dessous et observez comment un nom de fichier contenant un espace devient deux arguments distincts pour rm.
#!/usr/bin/env bash
# Dangerous: unquoted variable
FILE='important file.txt'
# Create the file so the demo is self-contained
touch "$FILE"
echo "Files before:"
ls
# BUG: rm sees TWO arguments: 'important' and 'file.txt'
# If 'important' does not exist, rm prints an error but continues.
rm $FILE # <-- unquoted, word-split happens here
echo "Files after (unquoted rm):"
lsToujours protéger par des guillemets : première règle du Bash défensif
La défense la plus simple et la plus efficace contre le découpage en mots consiste à toujours entourer les expansions de variables de guillemets doubles.
"$var"— se développe en un seul élément exactement, en préservant les espaces, les tabulations et les sauts de ligne.'literal'— guillemets simples : aucune expansion, ce qui est utile pour les chaînes fixes.- N’utilisez jamais
$varsans guillemets, sauf si vous avez explicitement besoin du découpage en mots et de l’expansion des motifs.
Le script ci-dessous présente la version sûre de l’exemple précédent.
#!/usr/bin/env bash
set -euo pipefail
FILE='important file.txt'
touch "$FILE"
echo 'Files before:'
ls
# SAFE: double-quotes keep the filename as one token
rm "$FILE"
echo 'Files after (quoted rm):'
lsInjection par expansion de motifs : quand * devient une arme
Les variables qui ne sont pas entre guillemets sont également soumises à l’expansion des chemins (globulation). Si les données contrôlées par l’utilisateur contiennent * ou ?, Bash les développe selon le système de fichiers avant l’exécution de la commande.
Un vecteur d’attaque classique consiste en un formulaire Web qui définit PATTERN=*, puis en un script qui exécute cp $PATTERN /tmp/leak/ — copiant ainsi tous les fichiers du répertoire courant.
La correction est identique : entourer la variable de guillemets doubles. Une variable "$PATTERN" entre guillemets est transmise littéralement ; le shell n’effectue jamais d’expansion de motifs sur celle-ci.
#!/usr/bin/env bash
set -euo pipefail
# Simulate attacker-supplied input
PATTERN='*'
mkdir -p /tmp/safe_demo_src /tmp/safe_demo_dst
touch /tmp/safe_demo_src/secret1.txt /tmp/safe_demo_src/secret2.txt
cd /tmp/safe_demo_src
# UNSAFE: glob expands, copies every file
# cp $PATTERN /tmp/safe_demo_dst/
# SAFE: pattern is treated as a literal filename
cp "$PATTERN" /tmp/safe_demo_dst/ 2>&1 || echo 'No file named literally "*" — attack neutralised'
rm -rf /tmp/safe_demo_src /tmp/safe_demo_dstInjection d’arguments par des paramètres positionnels non protégés
Les scripts qui acceptent des arguments de l’appelant sont des cibles privilégiées pour les injections. Chaque paramètre positionnel ($1, $2, ...) doit être protégé par des guillemets partout où il est utilisé.
Une pratique particulièrement dangereuse consiste à transmettre $@ ou $* sans guillemets à une autre commande :
"$@"— développe chaque paramètre positionnel en un mot distinct et protégé individuellement par des guillemets. Utilisez toujours cette forme.$@ou$*sans guillemets — soumis au découpage en mots et à l’expansion des motifs."$*"— regroupe tous les paramètres en un seul mot (ce que vous souhaitez rarement).
#!/usr/bin/env bash
set -euo pipefail
# Safe wrapper: forward all arguments quoted
grep_wrapper() {
local pattern="$1"
shift
# "$@" preserves each file argument as one token
grep -rn "$pattern" "$@"
}
# Usage: ./script 'error msg' /var/log/syslog '/path with spaces/app.log'
echo 'Searching current script for "safe":'
grep_wrapper 'safe' "$0"Injection de commandes avec eval et des entrées non validées
eval réanalyse son argument comme du code shell. Toute donnée non fiable qui parvient à eval peut exécuter des commandes arbitraires.
Pratiques dangereuses courantes :
eval "$user_input"eval echo \$$var(recherche indirecte d’une variable)- Transmettre des données utilisateur via
bash -c "$input"
Règle : ne transmettez jamais de données d’entrée non fiables à eval ou à bash -c. Utilisez plutôt des solutions Bash sûres :
- Expansion indirecte :
${!varname}au lieu deeval echo \$$varname - Tableaux associatifs pour les recherches dynamiques clé-valeur
- Fonctions plutôt que chaînes de commandes générées
#!/usr/bin/env bash
set -euo pipefail
# Simulated attacker-supplied variable name
VARNAME='PATH; echo INJECTED'
# UNSAFE: eval lets attacker run 'echo INJECTED'
# eval "echo \$$VARNAME"
# SAFE: indirect expansion only resolves valid variable names
# First validate that VARNAME is a legal identifier
if [[ "$VARNAME" =~ ^[A-Za-z_][A-Za-z0-9_]*$ ]]; then
echo "Value: ${!VARNAME}"
else
echo "ERROR: invalid variable name: '$VARNAME'" >&2
exit 1
fiValidation des entrées : listes d’autorisation plutôt que listes d’interdiction
Rejeter les caractères connus comme dangereux (une liste d’interdiction) est fragile : les attaquants trouvent des encodages ou des caractères que vous avez oubliés. Préférez une liste d’autorisation : n’acceptez que les caractères que vous savez sûrs.
Stratégies de liste d’autorisation dans Bash :
- Correspondance avec une expression régulière :
[[ "$input" =~ ^[A-Za-z0-9_-]+$ ]] - Correspondance avec un motif :
case "$input" in [A-Za-z0-9]*) ... ;; esac - Vérification d’une énumération : comparer avec un ensemble fixe de valeurs valides
Validez à la frontière, dès que l’entrée arrive dans le script, avant qu’elle n’atteigne une commande quelconque.
#!/usr/bin/env bash
set -euo pipefail
validate_username() {
local name="$1"
# Allowlist: only lowercase letters, digits, underscore, hyphen; 1-32 chars
if [[ ! "$name" =~ ^[a-z0-9_-]{1,32}$ ]]; then
echo "ERROR: invalid username '${name}'" >&2
return 1
fi
echo "Username accepted: $name"
}
validate_username 'alice' # OK
validate_username 'bob_smith-2' # OK
validate_username 'root; rm -rf /' # REJECTED
validate_username '../etc/passwd' # REJECTEDUtiliser des tableaux pour transmettre les arguments en toute sécurité
Lorsque vous devez construire une commande dynamiquement — en ajoutant conditionnellement des options ou en parcourant des entrées — utilisez un tableau Bash au lieu de concaténer des chaînes.
La concaténation de chaînes effondre toute la structure ; un tableau Bash conserve chaque argument comme un élément distinct, sans nouvelle analyse par le shell.
- Déclarer :
args=() - Ajouter :
args+=(--flag "$value") - Exécuter :
command "${args[@]}"
"${args[@]}" développe chaque élément comme un mot distinct, protégé individuellement par des guillemets — exactement comme "$@".
#!/usr/bin/env bash
set -euo pipefail
# Build a find command safely with an array
BASEDIR='/tmp'
USER_PATTERN='*.log' # could come from user input (validate first!)
MAX_DAYS=7
cmd=(find "$BASEDIR" -type f -name "$USER_PATTERN" -mtime "+${MAX_DAYS}")
# Optionally add -delete only when requested
DELETE=false
if [[ "$DELETE" == 'true' ]]; then
cmd+=(-delete)
fi
echo "Running: ${cmd[*]}"
"${cmd[@]}"Le séparateur -- : se protéger contre l’injection d’options
Même un argument correctement protégé par des guillemets peut être interprété à tort comme une option s’il commence par -. Considérez rm "$file" avec file='-rf .' : les guillemets empêchent le découpage en mots, mais rm interprète toujours -rf comme des options.
La convention POSIX -- signale la fin des options à la plupart des utilitaires GNU/BSD. Tout ce qui suit -- est traité comme un argument positionnel, jamais comme une option.
#!/usr/bin/env bash
set -euo pipefail
# Simulate a dangerous filename supplied by the user
FILENAME='-rf /tmp/safe_demo_target'
mkdir -p /tmp/safe_demo_target
touch /tmp/safe_demo_target/keep_me.txt
echo 'Files before:'
ls /tmp/safe_demo_target/
# UNSAFE (flag injection — do NOT uncomment in real systems):
# rm "$FILENAME"
# SAFE: -- ends option processing; filename is treated literally
rm -- "$FILENAME" 2>&1 || echo "No such file (attack neutralised): $FILENAME"
echo 'Files after:'
ls /tmp/safe_demo_target/
rm -rf /tmp/safe_demo_targetAssainir les entrées pour SQL et les outils externes
Lorsque des scripts Bash invoquent des interfaces de ligne de commande de bases de données (psql, mysql), curl avec des URL fournies par l’utilisateur ou des outils similaires, deux couches supplémentaires s’appliquent :
- Requêtes paramétrées : n’insérez jamais de données utilisateur dans des chaînes SQL. Transmettez les valeurs via
-vdanspsqlou--data-urlencodedanscurl. - Séparer les données du code : utilisez
printfavec une chaîne de format littérale ; ne laissez jamais l’entrée utilisateur devenir la chaîne de format.
L’exemple ci-dessous interroge PostgreSQL en toute sécurité, en gardant la valeur fournie par l’utilisateur complètement à l’extérieur du texte SQL.
#!/usr/bin/env bash
set -euo pipefail
# Validate first: only allow alphanumeric usernames
USERNAME="${1:-alice}"
if [[ ! "$USERNAME" =~ ^[a-z0-9_]{1,32}$ ]]; then
echo 'ERROR: invalid username' >&2
exit 1
fi
# UNSAFE:
# psql -c "SELECT * FROM users WHERE name = '$USERNAME';"
# SAFE: pass value as a psql variable, never inside the SQL text
# psql -v username="$USERNAME" -c 'SELECT * FROM users WHERE name = :username;'
# Demonstrate the principle with printf (safe format string usage)
printf 'Query would use username: %s\n' "$USERNAME"Liste de vérification du renforcement : tout mettre en pratique
Un script Bash sécurisé, prêt pour la production, combine toutes les techniques de cette leçon dans une défense cohérente en plusieurs couches. Voici un modèle renforcé minimal, mais complet :
set -euo pipefail— quitter en cas d’erreur, traiter les variables non définies comme des erreurs et propager les échecs des tubes.- Valider dès l’entrée — appliquer une liste d’autorisation à toute entrée externe avant qu’elle n’atteigne une commande.
- Protéger tout par des guillemets —
"$var","$@","${array[@]}"— sans exception, sauf si vous avez besoin du découpage. - Utiliser des tableaux pour construire dynamiquement les commandes.
- Préfixer les arguments par
--lors du passage de noms de fichiers ou de chaînes fournis par l’utilisateur. - N’utilisez jamais
evalavec des données non fiables ; préférez${!var}pour une recherche indirecte. - Restreindre les permissions — exécuter les scripts avec les privilèges minimaux requis ; éviter
sudodans les scripts qui acceptent des entrées utilisateur.
#!/usr/bin/env bash
# Hardened template — safe argument injection prevention
set -euo pipefail
IFS=$'\n\t'
#--- 1. Validate inputs at the boundary ---
SEARCH_DIR="${1:-}"
PATTERN="${2:-}"
[[ -z "$SEARCH_DIR" || -z "$PATTERN" ]] && { echo 'Usage: script <dir> <pattern>' >&2; exit 1; }
[[ ! "$SEARCH_DIR" =~ ^[A-Za-z0-9/_.-]+$ ]] && { echo 'ERROR: unsafe directory path' >&2; exit 1; }
[[ ! "$PATTERN" =~ ^[A-Za-z0-9._-]+$ ]] && { echo 'ERROR: unsafe pattern' >&2; exit 1; }
#--- 2. Build command with an array ---
cmd=(find -- "$SEARCH_DIR" -type f -name "$PATTERN")
#--- 3. Execute — no string interpolation, no eval ---
echo "Executing: ${cmd[*]}"
"${cmd[@]}"Vérification des connaissances : protection par des guillemets et prévention des injections
Vérifiez votre compréhension des concepts clés de cette leçon.
Récapitulatif de la leçon : prévenir les injections de commandes et d’arguments
Vous avez étudié l’ensemble des outils défensifs permettant de gérer les entrées Bash en toute sécurité :
- Le découpage en mots et l’expansion des motifs sont les mécanismes fondamentaux qui transforment les variables dangereuses en vecteurs d’injection.
- Protégez chaque variable avec des guillemets doubles (
"$var","$@","${arr[@]}") pour neutraliser ces deux menaces. - Utilisez
"$@"— jamais$@ni$*sans guillemets — pour transmettre des arguments. - Préfixez les noms de fichiers fournis par l’utilisateur avec
--afin d’empêcher l’injection d’options. - Appliquez une liste d’autorisation à toutes les entrées externes avec une vérification par expression régulière (
[[ $v =~ ^pattern$ ]]) avant qu’elles n’atteignent une commande. - Construisez les commandes dynamiques avec des tableaux (
cmd+=()→"${cmd[@]}"), jamais par concaténation de chaînes. - Éliminez
evaletbash -c "$input"; utilisez${!varname}pour une expansion indirecte sûre. - Commencez toujours les scripts par
set -euo pipefailetIFS=$'\n\t'pour disposer d’une base renforcée.
Appliquées systématiquement dès la première ligne de chaque script, ces pratiques réduisent presque à zéro la surface d’attaque de Bash pour les vulnérabilités liées aux injections.
Questions Fréquemment Posées
La leçon « Prévenir l’injection de commandes et d’arguments » est-elle gratuite ?
Oui — le texte complet de « Prévenir l’injection de commandes et d’arguments » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours Linux Command Line & Bash Scripting Mastery, passe à CoddyKit PRO. Le cours Linux Command Line & Bash Scripting Mastery comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « Prévenir l’injection de commandes et d’arguments » ?
Protégez, validez et transmettez sous forme de tableaux les entrées non fiables afin d’éliminer le découpage en mots et les injections fondées sur eval. Tu pratiques Linux Command Line & Bash Scripting Mastery avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer Linux Command Line & Bash Scripting Mastery ?
Aucune expérience préalable n'est requise. Linux Command Line & Bash Scripting Mastery sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 1 sur 4.
Combien de temps prend la leçon « Prévenir l’injection de commandes et d’arguments » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon Linux Command Line & Bash Scripting Mastery ?
Oui. Chaque leçon Linux Command Line & Bash Scripting Mastery inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- Prévenir l’injection de commandes et d’arguments
- Gérer les secrets en toute sécurité et assainir l’environnement
- Exécuter avec le principe du moindre privilège et discipliner sudo
- Analyse statique et audit avec ShellCheck