0Pricing
Linux Command Line & Bash Scripting Mastery · Lezione

Prevenire l'iniezione di comandi e argomenti

Metta tra virgolette, convalidi e passi tramite array gli input non attendibili per eliminare word splitting e iniezioni basate su eval.

Prevenire l'iniezione di comandi e argomenti è una lezione Linux Command Line & Bash Scripting Mastery gratuita su CoddyKit. Questa è la lezione 1 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Linux Command Line & Bash Scripting Mastery, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Linux Command Line & Bash Scripting Mastery include 4 lezioni in totale.

Perché si verificano gli attacchi di injection in Bash

Bash è un potente linguaggio di collegamento: passa il testo direttamente al kernel, ad altri programmi e alle subshell. Questa potenza diventa una responsabilità non appena un input non attendibile raggiunge un comando senza validazione o virgolette.

Quasi ogni injection in Bash è riconducibile a due cause principali:

  • Suddivisione in parole: le variabili senza virgolette vengono suddivise sugli spazi vuoti (IFS), trasformando un singolo valore logico in più token della shell.
  • Espansione dei glob: caratteri come *, ? e [ vengono espansi dalla shell prima ancora che il comando venga eseguito.

Un attaccante che controlla un nome di file, un nome utente, un parametro URL o una variabile d'ambiente può sfruttare entrambi i meccanismi per eseguire comandi arbitrari, leggere file o aumentare i privilegi.

Questa lezione mostra esattamente come si presentano queste vulnerabilità e, soprattutto, come eliminarle usando virgolette corrette, validazione degli input e passaggio degli argomenti tramite array.

La suddivisione in parole: la minaccia silenziosa

Quando Bash incontra una variabile senza virgolette, ne suddivide il valore in corrispondenza di ogni carattere elencato in $IFS (impostazione predefinita: spazio, tabulazione, nuova riga). Quello che sembra un unico argomento diventa una serie di argomenti.

Eseguite lo script qui sotto e osservate come un nome di file contenente uno spazio diventa due argomenti distinti per 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):"
ls

Mettete sempre le virgolette: la prima regola del Bash difensivo

La difesa più semplice ed efficace contro la suddivisione in parole consiste nel racchiudere sempre tra virgolette doppie le espansioni delle variabili.

  • "$var" — viene espansa in un unico token, preservando spazi, tabulazioni e nuove righe.
  • 'literal' — virgolette singole: nessuna espansione, utili per le stringhe fisse.
  • Non usate mai $var senza virgolette, a meno che non vi servano esplicitamente la suddivisione in parole e l'espansione dei glob.

Lo script qui sotto mostra la versione sicura dell'esempio precedente.

#!/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):'
ls

Injection tramite glob: quando * diventa un'arma

Le variabili senza virgolette sono inoltre soggette all'espansione dei percorsi (globbing). Se l'input controllato dall'utente contiene * o ?, Bash lo espande in base al filesystem prima dell'esecuzione del comando.

Un vettore d'attacco classico è un modulo web che imposta PATTERN=* mentre lo script esegue cp $PATTERN /tmp/leak/, copiando ogni file della directory corrente.

La correzione è identica: racchiudete la variabile tra virgolette doppie. Un "$PATTERN" tra virgolette viene passato letteralmente; la shell non esegue mai l'espansione dei glob su di esso.

#!/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_dst

Injection degli argomenti tramite parametri posizionali senza virgolette

Gli script che accettano argomenti dal chiamante sono bersagli privilegiati per le injection. Ogni parametro posizionale ($1, $2, ...) deve essere racchiuso tra virgolette in ogni punto in cui viene utilizzato.

Un modello particolarmente pericoloso consiste nel passare $@ o $* senza virgolette a un altro comando:

  • "$@" — espande ogni parametro posizionale come una parola separata e racchiusa individualmente tra virgolette. Usate sempre questa forma.
  • $@ o $* senza virgolette — soggetti alla suddivisione in parole e al globbing.
  • "$*" — unisce tutti i parametri in un'unica parola (quasi mai ciò che serve).
#!/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 dei comandi tramite eval e input non validato

eval analizza nuovamente il proprio argomento come codice della shell. Qualsiasi dato non attendibile che raggiunga eval può eseguire comandi arbitrari.

Modelli comuni pericolosi:

  • eval "$user_input"
  • eval echo \$$var (ricerca indiretta di una variabile)
  • Passaggio di dati dell'utente tramite bash -c "$input"

Regola: non passate mai input non attendibili a eval o bash -c. Usate invece alternative sicure di Bash:

  • Espansione indiretta: ${!varname} invece di eval echo \$$varname
  • Array associativi per la ricerca dinamica di coppie chiave-valore
  • Funzioni invece di stringhe di comando generate
#!/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
fi

Validazione degli input: allowlist invece di denylist

Rifiutare i caratteri noti come pericolosi (una denylist) è fragile: gli attaccanti possono trovare codifiche o caratteri che avete dimenticato. Usate invece una allowlist: accettate solo i caratteri che sapete essere sicuri.

Strategie di allowlist in Bash:

  • Corrispondenza con un'espressione regolare: [[ "$input" =~ ^[A-Za-z0-9_-]+$ ]]
  • Corrispondenza con un pattern: case "$input" in [A-Za-z0-9]*) ... ;; esac
  • Controllo tramite enumerazione: confronto con un insieme fisso di valori validi

Validate al confine, non appena l'input entra nello script, prima che raggiunga qualsiasi comando.

#!/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'   # REJECTED

Uso degli array per passare gli argomenti in modo sicuro

Quando dovete costruire dinamicamente un comando, ad esempio aggiungendo flag in modo condizionale o iterando sugli input, usate un array Bash invece di concatenare stringhe.

La concatenazione di stringhe elimina tutta la struttura; un array Bash conserva ogni argomento come elemento distinto, senza una nuova analisi da parte della shell.

  • Dichiarazione: args=()
  • Aggiunta: args+=(--flag "$value")
  • Esecuzione: command "${args[@]}"

"${args[@]}" espande ogni elemento come una parola separata e racchiusa individualmente tra virgolette, esattamente come "$@".

#!/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[@]}"

Il separatore --: protezione contro l'injection dei flag

Anche un argomento racchiuso correttamente tra virgolette può essere interpretato erroneamente come un'opzione se inizia con -. Considerate rm "$file" quando file='-rf .': le virgolette proteggono dalla suddivisione in parole, ma rm interpreta comunque -rf come una serie di flag.

La convenzione POSIX -- segnala la fine delle opzioni alla maggior parte delle utilità GNU/BSD. Tutto ciò che segue -- viene trattato come argomento posizionale, mai come flag.

#!/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_target

Sanificazione degli input per SQL e strumenti esterni

Quando gli script Bash invocano CLI per database (psql, mysql), curl con URL forniti dall'utente o strumenti simili, si applicano due livelli aggiuntivi:

  • Query parametrizzate: non interpolate mai i dati dell'utente nelle stringhe SQL. Passate i valori tramite -v in psql o --data-urlencode in curl.
  • Separate i dati dal codice: usate printf con una stringa di formato letterale; non permettete mai che l'input dell'utente sia la stringa di formato.

L'esempio qui sotto esegue una query sicura su PostgreSQL, mantenendo completamente fuori dal testo SQL il valore fornito dall'utente.

#!/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"

Lista di controllo per la messa in sicurezza: riunire tutti gli elementi

Uno script Bash sicuro e pronto per la produzione combina in una difesa coerente e stratificata tutte le tecniche di questa lezione. Ecco un modello minimo ma completo:

  • set -euo pipefail — esce in caso di errore, considera come errori le variabili non impostate e propaga gli errori nelle pipe.
  • Validate all'ingresso — usate un'allowlist per ogni input esterno prima che raggiunga qualsiasi comando.
  • Mettete tutto tra virgolette — "$var", "$@", "${array[@]}" — senza eccezioni, a meno che non vi serva la suddivisione.
  • Usate gli array per costruire dinamicamente i comandi.
  • Anteponete -- agli argomenti quando passate nomi di file o stringhe forniti dall'utente.
  • Non usate mai eval con dati non attendibili; preferite ${!var} per la ricerca indiretta.
  • Limitate i permessi — eseguite gli script con i privilegi minimi necessari; evitate sudo negli script che accettano input dell'utente.
#!/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[@]}"

Verifica delle conoscenze: virgolette e prevenzione delle injection

Verificate la vostra comprensione dei concetti chiave di questa lezione.

Riepilogo della lezione: prevenire l'injection di comandi e argomenti

Avete esaminato l'intero insieme di strumenti difensivi per gestire in sicurezza gli input Bash:

  • La suddivisione in parole e l'espansione dei glob sono i meccanismi fondamentali che trasformano le variabili non sicure in vettori di injection.
  • Racchiudete ogni variabile tra virgolette doppie ("$var", "$@", "${arr[@]}") per neutralizzare entrambe le minacce.
  • Usate "$@", mai $@ o $* senza virgolette, quando inoltrate gli argomenti.
  • Anteponete -- ai nomi di file forniti dall'utente per prevenire l'injection dei flag.
  • Applicate un'allowlist a tutti gli input esterni con un controllo tramite espressione regolare ([[ $v =~ ^pattern$ ]]) prima che raggiungano qualsiasi comando.
  • Costruite i comandi dinamici con gli array (cmd+=() → "${cmd[@]}"), mai tramite concatenazione di stringhe.
  • Eliminate eval e bash -c "$input"; usate ${!varname} per un'espansione indiretta sicura.
  • Aprite sempre gli script con set -euo pipefail e IFS=$'\n\t' per una base di sicurezza solida.

Applicate con coerenza fin dalla prima riga di ogni script, queste pratiche riducono quasi a zero la superficie d'attacco di Bash per le vulnerabilità della classe injection.

Domande Frequenti

La lezione «Prevenire l'iniezione di comandi e argomenti» è gratuita?

Sì — il testo completo di «Prevenire l'iniezione di comandi e argomenti» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Linux Command Line & Bash Scripting Mastery, passa a CoddyKit PRO. Il corso Linux Command Line & Bash Scripting Mastery include 4 lezioni in totale.

Cosa imparerò in «Prevenire l'iniezione di comandi e argomenti»?

Metta tra virgolette, convalidi e passi tramite array gli input non attendibili per eliminare word splitting e iniezioni basate su eval. Eserciti Linux Command Line & Bash Scripting Mastery con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare Linux Command Line & Bash Scripting Mastery?

Non è richiesta alcuna esperienza precedente. Linux Command Line & Bash Scripting Mastery su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 1 di 4.

Quanto tempo richiede la lezione «Prevenire l'iniezione di comandi e argomenti»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione Linux Command Line & Bash Scripting Mastery?

Sì. Ogni lezione Linux Command Line & Bash Scripting Mastery include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Prevenire l'iniezione di comandi e argomenti
  2. Gestire i segreti in sicurezza e mantenere pulito l'ambiente
  3. Esecuzione con privilegi minimi e disciplina nell'uso di sudo
  4. Analisi statica e audit con ShellCheck
← Torna a Linux Command Line & Bash Scripting Mastery