Linux-kommandolinjen og Bash-scripting på ekspertniveau · Lektion

Statisk analyse og audit med ShellCheck

Integrér ShellCheck i en sikkerhedsgate, og fortolk resultaterne for at sikre hvert script bedre.

Lektion 4 af 413 trin

Statisk analyse og audit med ShellCheck er en gratis Linux-kommandolinjen og Bash-scripting på ekspertniveau-lektion på CoddyKit. Dette er lektion 4 af 4. Du kan læse hele lektionen gratis nedenfor — og derefter øve dig praktisk i browseren med en indbygget kodeeditor og en AI-vejleder, der er tilgængelig døgnet rundt. Den er en del af læringsforløbet i Linux-kommandolinjen og Bash-scripting på ekspertniveau, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. Linux-kommandolinjen og Bash-scripting på ekspertniveau-kurset indeholder 4 lektioner i alt.

Hvad er ShellCheck, og hvorfor er det vigtigt

ShellCheck er et open source-værktøj til statisk analyse af shell-scripts. Det fortolker din Bash-kildekode (samt POSIX sh, dash og ksh) uden at køre den og rapporterer fejl, usikre konstruktioner, problemer med portabilitet og stilproblemer – hver med en unik regelkode som SC2086.

I en sikkerhedshærdet pipeline fungerer ShellCheck som en obligatorisk kontrol: Intet script leveres, før det er godkendt. Det er vigtigt, fordi:

  • Mange shell-sårbarheder (ordopdeling, injektion og anførselstegnsløs ekspansion) er usynlige under test af den normale situation, men udløses ved input, som en angriber kontrollerer.
  • ShellCheck fanger disse fejltyper før kørsel uden ekstra omkostninger.
  • Det dokumenterer hvorfor hvert mønster er farligt, så dit team gradvist bliver mere opmærksomt.

Installér det på ethvert system:

# Debian / Ubuntu
sudo apt-get install shellcheck

# macOS (Homebrew)
brew install shellcheck

# From source via Cabal (any platform)
cabal update && cabal install ShellCheck

# Verify
shellcheck --version

Kørsel af ShellCheck for første gang

Det enkleste kald er shellcheck <script>. ShellCheck læser shebang-linjen for at bestemme shell-dialekten og skriver derefter resultaterne til stdout.

Hvert resultat indeholder:

  • Fil og linjenummer – præcis placering
  • Alvorlighedsgrad – error, warning, info eller style
  • SC-kode – stabil regelidentifikator, som du kan slå op eller undertrykke
  • Forklaring i almindeligt sprog – fortæller dig hvad der er galt, og ofte hvordan du løser det

Kør scriptet nedenfor, og se det output, ShellCheck ville producere:

#!/usr/bin/env bash
# demo_bad.sh — intentionally flawed for ShellCheck demonstration

FILE=$1

if [ $FILE == '' ]; then
  echo "No file given"
fi

cat $FILE | grep 'error' | wc -l

Fortolkning af ShellCheck-output og SC-koder

For scriptet fra den foregående scene ville ShellCheck skrive resultater som:

  • SC2086 (warning) – Sæt dette i dobbelte anførselstegn for at forhindre globbing og ordopdeling – på $FILE i [ $FILE == '' ] og i cat $FILE.
  • SC2039 / SC3010 (info) – == i [ ] er en Bash-specifik konstruktion; brug = til POSIX.
  • SC2002 (style) – Overflødigt cat. Overvej cmd < file i stedet for cat file | cmd.

Hver SC-kode henviser til en wikiside på https://www.shellcheck.net/wiki/SCxxxx med begrundelse og et korrigeret eksempel.

Den korrigerede version af scriptet:

#!/usr/bin/env bash
# demo_fixed.sh — ShellCheck-clean

FILE="$1"

if [ -z "$FILE" ]; then
  echo "No file given" >&2
  exit 1
fi

grep -c 'error' "$FILE"

Alvorlighedsgrader, og hvad du skal reagere på

ShellCheck klassificerer hvert resultat efter alvorlighedsgrad. I en sikkerhedskontrol bør du behandle dem sådan:

  • error – Næsten med sikkerhed en fejl eller sikkerhedsbrist. Blokér bygningen. Ret det straks. Eksempel: SC2148 manglende shebang, SC2070 anførselstegnsløs $?.
  • warning – Mønster med høj risiko, som ofte kan udnyttes. Blokér bygningen. Ret det, eller begrund udtrykkeligt, hvorfor det undertrykkes. Eksempel: SC2086 variabel uden anførselstegn.
  • info – Sandsynligvis korrekt i dag, men skrøbeligt eller ikke-portabelt. Ret det i den samme PR, medmindre det udtrykkeligt er uden for omfanget.
  • style – Kosmetisk anbefaling eller POSIX-præference. Anbefales, men er valgfrit i en ren Bash-kodebase.

Brug --severity=warning for kun at afslutte med en fejlkode ved advarsler og højere alvorlighedsgrader – den almindelige tærskel for en sikkerhedskontrol:

#!/usr/bin/env bash
# gate.sh — fail CI on errors and warnings only
shellcheck --severity=warning scripts/*.sh
echo "ShellCheck exit code: $?"

Integration af ShellCheck som sikkerhedskontrol i CI

En sikkerhedskontrol er kun nyttig, når den er obligatorisk og automatiseret. Mønsteret nedenfor indlejrer ShellCheck i et CI-trin, der:

  • Finder alle .sh-filer i lageret.
  • Kører ShellCheck med --severity=warning og maskinlæsbar JSON-output.
  • Fejler pipelinen (exit 1), hvis der findes et resultat.
  • Udskriver en opsummering, så udviklere kan reagere på resultaterne uden at forlade CI-loggen.

Læg denne fil i dit repository, og kald den fra din CI-pipeline (GitHub Actions, Jenkins, GitLab CI osv.):

#!/usr/bin/env bash
# ci/shellcheck_gate.sh
set -euo pipefail

SCRIPTS=$(find . -name '*.sh' -not -path './.git/*')
FAILED=0

for script in $SCRIPTS; do
  echo "==> Checking: $script"
  if ! shellcheck --severity=warning --format=tty "$script"; then
    FAILED=1
  fi
done

if [ "$FAILED" -eq 1 ]; then
  echo "[GATE] ShellCheck found warnings or errors. Build blocked." >&2
  exit 1
fi

echo "[GATE] All scripts passed ShellCheck."

SC2086-familien: Anførselstegnsløse variabelekspansioner

SC2086 er det mest almindelige ShellCheck-resultat og en af de mest udnyttede shell-sårbarheder: variabelekspansioner uden anførselstegn.

Når en variabel ikke står i dobbelte anførselstegn, udfører shellen ordopdeling (opdeling ved IFS) og glob-ekspansion på dens værdi. En angriber, der kontrollerer variablen, kan indsætte ekstra argumenter, udløse gennemgang af filsystemet eller få kommandoer til at modtage uventede operander.

Klassisk farligt mønster:

#!/usr/bin/env bash
# Attacker sets: FILENAME="important.txt /etc/passwd"
FILENAME="$1"

# UNSAFE — word splitting turns this into two args
rm $FILENAME

# SAFE — double quotes prevent splitting
rm "$FILENAME"

# Arrays are the right tool for lists
FILES=("$@")
rm -- "${FILES[@]}"

Registrering af risiko for kommandoinjektion med SC2046 og SC2035

To mindre kendte, men kritiske regler håndterer kommandoinjektion via output fra subshells:

  • SC2046 – Sæt dette i anførselstegn for at forhindre ordopdeling eller glob inde i $(…). Hvis outputtet fra en subshell bruges uden anførselstegn, bliver mellemrum eller glob-tegn i outputtet til et shell-token.
  • SC2035 – Brug ./*.sh i stedet for *.sh for at undgå, at filnavne, der begynder med -, fortolkes som indstillinger (en klassisk vektor for argumentinjektion).

Konkret udnyttelsesscenarie og løsning:

#!/usr/bin/env bash
# SC2046 example — output of find fed unquoted to chmod
# If a filename contains spaces, extra arguments appear

# UNSAFE
chmod 600 $(find /secrets -name '*.key')

# SAFE — use a while-read loop or xargs with -0
find /secrets -name '*.key' -print0 \
  | xargs -0 chmod 600

# SC2035 example
# UNSAFE — a file named '-rf' would be passed as an option
rm *.sh

# SAFE
rm -- ./*.sh

Brug af JSON-outputformatet til automatisering

ShellCheck understøtter flere outputformater via --format:

  • tty (standard) – terminaloutput, der kan læses af mennesker
  • json – maskinlæsbar; ideel til dashboards, brugerdefinerede blokeringer eller upload til SAST-platforme
  • gcc – kompatibelt med værktøjer, der fortolker GCC-fejlformatet (IDE'er, Vim/Emacs)
  • checkstyle – XML-format, der bruges af Jenkins Checkstyle-pluginet

JSON-formatet giver dig mulighed for at skrive automatiserede politikker, for eksempel kun at blokere ved bestemte SC-koder eller samle resultater fra en stor kodebase i en sikkerhedsrapport.

#!/usr/bin/env bash
# Emit JSON and filter for only error-severity findings using jq
shellcheck --format=json scripts/deploy.sh \
  | jq '[.[] | select(.level == "error")]'

# Count distinct SC codes across all scripts
find . -name '*.sh' -print0 \
  | xargs -0 shellcheck --format=json 2>/dev/null \
  | jq '[.[] | .code] | group_by(.) | map({code: .[0], count: length}) | sort_by(-.count)'

Korrekt undertrykkelse af falske positiver

En omfattende deaktivering af ShellCheck modarbejder formålet med værktøjet. Den korrekte tilgang er en målrettet, dokumenteret undertrykkelse, der kun påvirker den nøjagtige linje eller blok, hvor resultatet reelt ikke er relevant.

Tre mekanismer til undertrykkelse:

  • Deaktivering på linjen – # shellcheck disable=SC2086 på linjen over den problematiske kode. Påvirker kun den linje.
  • Deaktivering/aktivering af blok – omslut en sektion med # shellcheck disable=… og # shellcheck enable=….
  • Direktiv på filniveau – placér # shellcheck disable=… øverst i filen (sjældent berettiget; dokumentér hvorfor).

Enhver undertrykkelse skal indeholde en kommentar, der forklarer, hvorfor resultatet er en falsk positiv:

#!/usr/bin/env bash
# deploy.sh

# Legitimate suppression: $DEPLOY_ARGS is intentionally word-split
# because it is a pre-validated list of flags from a trusted config file.
# shellcheck disable=SC2086
exec deploy-tool $DEPLOY_ARGS

# Block suppression for a section that generates dynamic code
# shellcheck disable=SC2016
VARS='$HOME $PATH $USER'
echo "Unexpanded vars: $VARS"
# shellcheck enable=SC2016

Konfiguration af ShellCheck via .shellcheckrc

For indstillinger, der gælder for hele projektet, læser ShellCheck .shellcheckrc fra scriptets mappe og op gennem mappestrukturen til /. Det betyder, at du ikke behøver gentage indstillinger ved hvert kald, og at kontrolscripts holdes enkle.

Nyttige direktiver i .shellcheckrc:

  • shell=bash – tilsidesæt registreringen af dialekten (nyttigt for filer uden shebangs)
  • enable=all – aktivér valgfrie kontroller (f.eks. avoid-nullary-conditions, require-variable-braces)
  • disable=SC2059 – projektdækkende undertrykkelse af en begrundet undtagelse
  • external-sources=true – følg og kontrollér source- og .-direktiver
# .shellcheckrc — project root
shell=bash
enable=all
external-sources=true

# SC2312: consider invoking this command separately to avoid masking its
# return value — suppressed project-wide because we use set -e.
# Rationale: errexit already aborts on failure; masking risk is mitigated.
disable=SC2312

Hærdet script fra start til slut: før og efter

Den mest effektive måde at få ShellCheck-resultater ind under huden på er at omstrukturere et realistisk script fra en tilstand med fejl til et rent og hærdet script. Scriptet nedenfor sikkerhedskopierer en mappe og blev skrevet uden sikkerhed for øje. Det fejler i ShellCheck på mindst fem forskellige regler.

Studér begge versioner. Versionen efter består shellcheck --severity=warning uden direktiver til undertrykkelse og er betydeligt sikrere ved input, som en angriber kontrollerer:

#!/usr/bin/env bash
# BEFORE — multiple ShellCheck violations
DEST=$1
SRC=$2
DATE=`date +%Y%m%d`

if [ ! -d $DEST ]; then
  mkdir $DEST
fi

cp -r $SRC $DEST/$DATE
echo Done


#!/usr/bin/env bash
# AFTER — ShellCheck-clean and hardened
set -euo pipefail

DEST="${1:?Usage: backup.sh <dest> <src>}"
SRC="${2:?Usage: backup.sh <dest> <src>}"
DATE=$(date +%Y%m%d)

if [ ! -d "$DEST" ]; then
  mkdir -p -- "$DEST"
fi

cp -r -- "$SRC" "$DEST/$DATE"
echo 'Done' >&2

Videnstjek: ShellCheck som sikkerhedskontrol

Test din forståelse af ShellChecks rolle som sikkerhedskontrol.

Opsummering: Statisk analyse som sikkerhedskontrol

I denne lektion har du lært at gøre ShellCheck til en obligatorisk sikkerhedskontrol i din Bash-arbejdsgang:

  • ShellCheck udfører statisk analyse uden at køre dine scripts og fanger citeringsfejl, injektionsrisici og usikre mønstre før kørsel.
  • Hvert resultat har en SC-kode (f.eks. SC2086), der linker til detaljeret dokumentation og vejledning i, hvordan problemet løses.
  • Alvorlighedstrinnene – error, warning, info, style – giver dig mulighed for at tilpasse kontrollen: --severity=warning er den anbefalede sikkerhedstærskel.
  • Brug maskinlæsbar output (--format=json) til at automatisere rapportering, følge udviklingen og integrere SAST.
  • Undertryk sparsomt: målret altid en enkelt linje, dokumentér altid hvorfor i en kommentar, og undertryk aldrig globalt, medmindre det er begrundet i .shellcheckrc.
  • Kombinér ShellCheck med set -euo pipefail, eksplicitte anførselstegn, -- argument-afslutninger og inputvalidering for et forsvar i dybden.

Et script, der består ShellCheck, er ikke automatisk sikkert – men et script, der fejler i ShellCheck, bør aldrig nå produktionen.

Gratis at komme i gang

Lær Bash med en AI-underviser — gratis

Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.

Kurser
22
Lektioner
88

Ofte stillede spørgsmål

Er lektionen “Statisk analyse og audit med ShellCheck” gratis?

Ja — hele teksten til “Statisk analyse og audit med ShellCheck” kan læses gratis her på nettet. Hvis du vil øve dig interaktivt med en indbygget kodeeditor og en AI-vejleder døgnet rundt og få adgang til resten af Linux-kommandolinjen og Bash-scripting på ekspertniveau-kurset, skal du opgradere til CoddyKit PRO. Linux-kommandolinjen og Bash-scripting på ekspertniveau-kurset indeholder 4 lektioner i alt.

Hvad lærer jeg i “Statisk analyse og audit med ShellCheck”?

Integrér ShellCheck i en sikkerhedsgate, og fortolk resultaterne for at sikre hvert script bedre. Du øver dig i Linux-kommandolinjen og Bash-scripting på ekspertniveau med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.

Skal jeg have erfaring for at begynde på Linux-kommandolinjen og Bash-scripting på ekspertniveau?

Der kræves ingen tidligere erfaring. Linux-kommandolinjen og Bash-scripting på ekspertniveau på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 4 af 4.

Hvor lang tid tager lektionen “Statisk analyse og audit med ShellCheck”?

De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.

Kan jeg skrive og køre kode i denne Linux-kommandolinjen og Bash-scripting på ekspertniveau-lektion?

Ja. Alle Linux-kommandolinjen og Bash-scripting på ekspertniveau-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.

Alle lektioner i dette kursus

  1. Forebyggelse af kommando- og argumentinjektion
  2. Sikker håndtering af hemmeligheder og rent miljø
  3. Kørsel med færrest mulige rettigheder og disciplineret brug af sudo
  4. Statisk analyse og audit med ShellCheck
← Tilbage til Linux-kommandolinjen og Bash-scripting på ekspertniveau