DevOps-bootcamp · leksjon

Forebygging av kommando- og argumentinjisering

Sett anførselstegn rundt, valider og send upålitelig inndata som tabeller for å eliminere orddeling og eval-basert injisering.

Leksjon 1 av 413 trinn

Forebygging av kommando- og argumentinjisering er en gratis leksjon i DevOps-bootcamp på CoddyKit. Dette er leksjon 1 av 4. Du kan lese valgfritt 3 leksjoner fra denne læringsstien gratis i sin helhet – deretter låser CoddyKit PRO opp alle leksjoner, samt praktisk øving med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Den er en del av læringsløpet i DevOps-bootcamp, og fremdriften din synkroniseres mellom nettet og CoddyKit-appen. Kurset i DevOps-bootcamp inneholder totalt 4 leksjoner.

Hvorfor injeksjonsangrep oppstår i Bash

Bash er et kraftig limspråk — det sender tekst direkte til kjernen, andre programmer og underskall. Denne kraften blir en svakhet i det øyeblikket uklarert inndata når frem til en kommando uten validering eller sitering.

To grunnårsaker ligger bak nesten alle Bash-injeksjoner:

  • Orddeling: Usiterte variabler deles ved mellomromstegn (IFS), slik at én logisk verdi blir til flere skallsymboler.
  • Glob-ekspansjon: Tegn som *, ? og [ utvides av skallet før kommandoen i det hele tatt kjøres.

En angriper som kontrollerer et filnavn, et brukernavn, en URL-parameter eller en miljøvariabel, kan utnytte begge deler til å kjøre vilkårlige kommandoer, lese filer eller eskalere privilegier.

Denne leksjonen viser nøyaktig hvordan disse sårbarhetene oppstår — og, enda viktigere, hvordan De eliminerer dem med korrekt sitering, validering av inndata og argumentoverføring basert på tabeller.

Orddeling: Den usynlige trusselen

Når Bash ser en usitert variabel, deler det verdien ved alle tegn som er oppført i $IFS (standard: mellomrom, tabulator, linjeskift). Det som ser ut som ett argument, blir til flere.

Kjør skriptet nedenfor og se hvordan et filnavn med et mellomrom blir til to separate argumenter til 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

Siter alltid: Den første regelen for defensiv Bash

Det enkleste og mest effektive forsvaret mot orddeling er å alltid sette doble anførselstegn rundt variabelutvidelser.

  • "$var" — utvides til nøyaktig ett symbol og bevarer mellomrom, tabulatorer og linjeskift.
  • 'literal' — enkle anførselstegn: ingen utvidelser i det hele tatt, nyttig for faste strenger.
  • Bruk aldri $var usitert med mindre De uttrykkelig trenger orddeling og glob-ekspansjon.

Skriptet nedenfor viser den sikre versjonen av det forrige eksempelet.

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

Glob-injeksjon: Når * blir et våpen

Usiterte variabler utsettes også for banenavnsutvidelse (glob-ekspansjon). Hvis brukerbestemte inndata inneholder * eller ?, utvider Bash dem mot filsystemet før kommandoen kjøres.

En klassisk angrepsvektor er et nettskjema som setter PATTERN=*, mens skriptet kjører cp $PATTERN /tmp/leak/ — og dermed kopierer alle filer i gjeldende mappe.

Løsningen er den samme: sett doble anførselstegn rundt variabelen. En sitert "$PATTERN" sendes bokstavelig; skallet utfører ingen glob-ekspansjon på den.

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

Argumentinjeksjon via usiterte posisjonsparametere

Skript som mottar argumenter fra den som kaller dem, er attraktive mål for injeksjon. Hver posisjonsparameter ($1, $2, ...) må siteres overalt der den brukes.

Et spesielt farlig mønster er å sende $@ eller $* usitert til en annen kommando:

  • "$@" — utvider hver posisjonsparameter til et separat, individuelt sitert ord. Bruk alltid denne formen.
  • $@ eller $* usitert — utsettes for orddeling og glob-ekspansjon.
  • "$*" — slår sammen alle parametere til ett ord (sjelden det De ønsker).
#!/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"

Kommandoinjeksjon via eval og uvaliderte inndata

eval tolker argumentet på nytt som skallkode. Uklarerte data som når frem til eval, kan kjøre vilkårlige kommandoer.

Vanlige farlige mønstre:

  • eval "$user_input"
  • eval echo \$$var (indirekte variabeloppslag)
  • Å sende brukerdata gjennom bash -c "$input"

Regel: Send aldri uklarerte inndata til eval eller bash -c. Bruk sikre Bash-alternativer:

  • Indirekte utvidelse: ${!varname} i stedet for eval echo \$$varname
  • Assosiative tabeller for dynamiske oppslag av nøkkel og verdi
  • Funksjoner i stedet for genererte kommandostrenger
#!/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

Validering av inndata: Tillatelseslister fremfor blokkeringslister

Det er sårbart å avvise kjente farlige tegn (en blokkeringsliste) — angripere finner kodinger eller tegn De har glemt. Bruk i stedet en tillatelsesliste: godta bare tegn De vet er sikre.

Strategier for tillatelseslister i Bash:

  • Regex-samsvar: [[ "$input" =~ ^[A-Za-z0-9_-]+$ ]]
  • Mønstergjenkjenning: case "$input" in [A-Za-z0-9]*) ... ;; esac
  • Enum-sjekk: sammenlign med et fast sett av gyldige verdier

Valider ved grensen — så snart inndata kommer inn i skriptet — før den berører noen kommando.

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

Bruk av tabeller for sikker argumentoverføring

Når De må bygge en kommando dynamisk — for eksempel ved å legge til flagg betinget eller gå gjennom inndata i en løkke — bør De bruke en Bash-tabell i stedet for å sette sammen strenger.

Strengsammenslåing fjerner all struktur; en Bash-tabell bevarer hvert argument som et separat element uten ny tolking av skallet.

  • Deklarer: args=()
  • Legg til: args+=(--flag "$value")
  • Kjør: command "${args[@]}"

"${args[@]}" utvider hvert element som et separat, individuelt sitert ord — nøyaktig som "$@".

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

Separatoren --: Beskyttelse mot flagginjeksjon

Selv et korrekt sitert argument kan mistolkes som et alternativflagg hvis det begynner med -. Tenk på rm "$file" der file='-rf .': Siteringen beskytter mot orddeling, men rm tolker fortsatt -rf som flagg.

POSIX-konvensjonen -- signaliserer slutt på alternativer til de fleste GNU-/BSD-verktøy. Alt etter -- behandles som et posisjonsargument, aldri som et flagg.

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

Rensing av inndata for SQL og eksterne verktøy

Når Bash-skript kaller databaseklienter (psql, mysql), curl med brukerleverte URL-er eller lignende verktøy, gjelder to ekstra lag:

  • Parametriserte spørringer: Sett aldri brukerdata direkte inn i SQL-strenger. Send verdier via -v i psql eller --data-urlencode i curl.
  • Skill data fra kode: Bruk printf med en bokstavelig formatstreng; la aldri brukerdata være formatstrengen.

Eksempelet nedenfor spør PostgreSQL på en sikker måte og holder den brukerleverte verdien helt ute av SQL-teksten.

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

Sjekkliste for sikring: Sett alt sammen

Et Bash-skript med sikkerhet på produksjonsnivå kombinerer alle teknikkene fra denne leksjonen i et konsekvent, lagdelt forsvar. Her er en minimal, men komplett herdet mal:

  • set -euo pipefail — avslutt ved feil, behandle udefinerte variabler som feil, og viderefør feil i rør.
  • Valider ved innlesing — bruk en tillatelsesliste for alle eksterne inndata før de berører noen kommando.
  • Siter alt — "$var", "$@", "${array[@]}" — ingen unntak med mindre De trenger splitting.
  • Bruk tabeller til dynamisk bygging av kommandoer.
  • Sett -- foran argumenter når De sender brukerleverte filnavn eller strenger.
  • Bruk aldri eval med uklarerte data; foretrekk ${!var} for indirekte oppslag.
  • Begrens tillatelser — kjør skript med minimum nødvendige privilegier, og unngå sudo i skript som mottar brukerdata.
#!/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[@]}"

Kunnskapstest: Sitering og forebygging av injeksjon

Test forståelsen Deres av de viktigste begrepene i denne leksjonen.

Oppsummering av leksjonen: Forebygging av kommando- og argumentinjeksjon

De har gått gjennom et komplett defensivt verktøysett for sikker håndtering av inndata i Bash:

  • Orddeling og glob-ekspansjon er de grunnleggende mekanismene som gjør usikre variabler til injeksjonsvektorer.
  • Sett doble anførselstegn rundt alle variabler ("$var", "$@", "${arr[@]}") for å undertrykke begge truslene.
  • Bruk "$@" — aldri $@ eller $* usitert — når De videresender argumenter.
  • Sett -- foran brukerleverte filnavn for å hindre flagginjeksjon.
  • Bruk en tillatelsesliste for alle eksterne inndata med en regex-vakt ([[ $v =~ ^pattern$ ]]) før de når noen kommando.
  • Bygg dynamiske kommandoer med tabeller (cmd+=() → "${cmd[@]}"), aldri med strengsammenslåing.
  • Fjern eval og bash -c "$input"; bruk ${!varname} for sikker indirekte utvidelse.
  • Start alltid skript med set -euo pipefail og IFS=$'\n\t' som et herdet grunnlag.

Disse praksisene, brukt konsekvent fra første linje i hvert skript, reduserer Bash-angrepsflaten for injeksjonssårbarheter til nær null.

Gratis å komme i gang

Lær deg DevOps-bootcamp med en AI-veileder – gratis

Skriv og kjør ekte kode i nettleseren, få umiddelbar hjelp fra en AI-veileder som er tilgjengelig døgnet rundt, og fortsett der du slapp – på nettet eller i appen.

Kurs
142
Leksjoner
568

Ofte stilte spørsmål

Er leksjonen «Forebygging av kommando- og argumentinjisering» gratis?

Ja – du kan lese valgfritt 3 av leksjonene i læringsstien DevOps-bootcamp, inkludert «Forebygging av kommando- og argumentinjisering», gratis i sin helhet her på nettet. Deretter låser CoddyKit PRO opp alle leksjoner, samt interaktiv øving med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Kurset i DevOps-bootcamp inneholder totalt 4 leksjoner.

Hva lærer jeg i «Forebygging av kommando- og argumentinjisering»?

Sett anførselstegn rundt, valider og send upålitelig inndata som tabeller for å eliminere orddeling og eval-basert injisering. Du øver på DevOps-bootcamp med praktisk kode som du kjører direkte i nettleseren, mens en AI-veileder som er tilgjengelig døgnet rundt, svarer på spørsmålene dine mens du jobber deg gjennom leksjonen.

Trenger jeg erfaring for å begynne med DevOps-bootcamp?

Ingen tidligere erfaring er nødvendig. DevOps-bootcamp på CoddyKit er lagt opp for både nybegynnere og viderekomne, så De kan begynne her eller helt fra start og lære i Deres eget tempo. Dette er leksjon 1 av 4.

Hvor lang tid tar leksjonen «Forebygging av kommando- og argumentinjisering»?

De fleste CoddyKit-leksjoner tar omtrent 5–10 minutter. Hver leksjon er kort og interaktiv, slik at De gjør jevne fremskritt og kan fortsette akkurat der De slapp – både på nettet og i appen.

Kan jeg skrive og kjøre kode i denne DevOps-bootcamp-leksjonen?

Ja. Alle DevOps-bootcamp-leksjoner har en innebygd kodeeditor, slik at De kan skrive og kjøre ekte kode direkte i nettleseren og få umiddelbar tilbakemelding fra AI – uten lokal konfigurering.

Alle leksjonene i dette kurset

  1. Forebygging av kommando- og argumentinjisering
  2. Sikker håndtering av hemmeligheter og ryddige miljøer
  3. Kjøring med minste privilegium og sudo-disiplin
  4. Statisk analyse og revisjon med ShellCheck
← Tilbake til DevOps-bootcamp