Statische analyse en auditing met ShellCheck
Integreer ShellCheck in een security gate en interpreteer de bevindingen om elk script te beveiligen.
Statische analyse en auditing met ShellCheck is een gratis De Linux-opdrachtregel en Bash-scripting beheersen-les op CoddyKit. Dit is les 4 van 4. Je kunt de volledige les hieronder gratis lezen en daarna in de browser praktisch oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is. Deze les maakt deel uit van het leertraject De Linux-opdrachtregel en Bash-scripting beheersen. Je voortgang wordt gesynchroniseerd op het web en in de CoddyKit-app. De cursus De Linux-opdrachtregel en Bash-scripting beheersen bevat in totaal 4 lessen.
Wat is ShellCheck en waarom is het belangrijk
ShellCheck is een opensourceprogramma voor statische analyse van shellscripts. Het parseert je broncode voor Bash (en POSIX sh, dash en ksh) zonder die uit te voeren en meldt fouten, onveilige constructies, problemen met overdraagbaarheid en stijlproblemen — elk voorzien van een unieke regelcode zoals SC2086.
In een beveiligde pijplijn fungeert ShellCheck als een verplichte controlepoort: er wordt geen script geleverd voordat het is goedgekeurd. Dit is belangrijk omdat:
- Veel kwetsbaarheden in shells (splitsen van woorden, injectie en uitbreidingen zonder aanhalingstekens) tijdens tests van het normale pad onzichtbaar zijn, maar worden geactiveerd door invoer die door een aanvaller wordt beheerst.
- ShellCheck deze soorten fouten vóór runtime, zonder extra kosten, onderschept.
- Het documenteert waarom elk patroon gevaarlijk is, waardoor je team na verloop van tijd alerter wordt.
Installeer het op elk systeem:
# 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 --versionShellCheck voor het eerst uitvoeren
De eenvoudigste aanroep is shellcheck <script>. ShellCheck leest de shebang-regel om het shelldialect te bepalen en schrijft daarna bevindingen naar stdout.
Elke bevinding bevat:
- Bestand en regelnummer — de exacte locatie
- Ernst —
error,warning,infoofstyle - SC-code — stabiele regelidentificatie die je kunt opzoeken of onderdrukken
- Uitleg in gewone taal — vertelt je wat er fout is en vaak ook hoe je dit kunt oplossen
Voer het onderstaande script uit en bekijk de uitvoer die ShellCheck zou produceren:
#!/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 -lShellCheck-uitvoer en SC-codes interpreteren
Voor het script uit de vorige scène zou ShellCheck bevindingen zoals deze melden:
SC2086(waarschuwing) — Gebruik dubbele aanhalingstekens om globbing en het splitsen van woorden te voorkomen — bij$FILEin[ $FILE == '' ]en incat $FILE.SC2039/SC3010(informatie) — == in [ ] is een bashism; gebruik = voor POSIX.SC2002(stijl) — Overbodige cat. Overweeg cmd < file in plaats van cat file | cmd.
Elke SC-code verwijst naar een wikipagina op https://www.shellcheck.net/wiki/SCxxxx met uitleg en een gecorrigeerd voorbeeld.
De gecorrigeerde versie van dat script:
#!/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"Ernstniveaus en wat je moet aanpakken
ShellCheck classificeert elke bevinding op ernst. In een beveiligingscontrolepoort behandel je ze als volgt:
- fout — Bijna zeker een bug of beveiligingslek. Blokkeer de build. Los het onmiddellijk op. Voorbeeld:
SC2148, ontbrekende shebang, enSC2070,$?zonder aanhalingstekens. - waarschuwing — Patroon met een hoog risico dat vaak kan worden misbruikt. Blokkeer de build. Los het op of motiveer expliciet waarom je de melding onderdrukt. Voorbeeld:
SC2086, variabele zonder aanhalingstekens. - informatie — Waarschijnlijk nu correct, maar kwetsbaar of niet overdraagbaar. Los het op in dezelfde PR, tenzij het expliciet buiten de reikwijdte valt.
- stijl — Cosmetische voorkeur of POSIX-voorkeur. Aanbevolen, maar optioneel in een codebasis die uitsluitend Bash gebruikt.
Gebruik --severity=warning om alleen bij waarschuwingen en ernstigere bevindingen met een waarde ongelijk aan nul af te sluiten — de standaarddrempel voor een beveiligingscontrolepoort:
#!/usr/bin/env bash
# gate.sh — fail CI on errors and warnings only
shellcheck --severity=warning scripts/*.sh
echo "ShellCheck exit code: $?"ShellCheck integreren als beveiligingscontrolepoort in CI
Een beveiligingscontrolepoort is alleen nuttig als die verplicht en geautomatiseerd is. Het onderstaande patroon verpakt ShellCheck in een CI-stap die:
- Elk
.sh-bestand in de repository vindt. - ShellCheck uitvoert met
--severity=warningen JSON-uitvoer die door machines kan worden gelezen. - De pijplijn laat mislukken (
exit 1) als er een bevinding bestaat. - Een samenvatting afdrukt, zodat ontwikkelaars bevindingen kunnen aanpakken zonder het CI-logboek te verlaten.
Plaats dit bestand in je repository en roep het aan vanuit je CI-pijplijn (GitHub Actions, Jenkins, GitLab CI enzovoort):
#!/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."De SC2086-familie: uitbreidingen van variabelen zonder aanhalingstekens
SC2086 is de meest voorkomende ShellCheck-bevinding en een van de meest misbruikte kwetsbaarheden in shells: uitbreidingen van variabelen zonder aanhalingstekens.
Wanneer een variabele niet tussen dubbele aanhalingstekens staat, voert de shell splitsen van woorden (op IFS) en glob-uitbreiding uit op de waarde ervan. Een aanvaller die de variabele beheerst, kan extra argumenten injecteren, doorkruisen van het bestandssysteem veroorzaken of ervoor zorgen dat opdrachten onverwachte operanden ontvangen.
Klassiek gevaarlijk patroon:
#!/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[@]}"Risico op opdrachtinjectie detecteren met SC2046 en SC2035
Twee minder bekende maar kritieke regels gaan over opdrachtinjectie via uitvoer van subshells:
SC2046— Gebruik aanhalingstekens om het splitsen van woorden en globbing te voorkomen binnen$(…). Als de uitvoer van een subshell zonder aanhalingstekens wordt gebruikt, wordt elke spatie of elk globteken in de uitvoer een shelltoken.SC2035— Gebruik./*.shin plaats van*.shom te voorkomen dat bestandsnamen die met-beginnen als opties worden geïnterpreteerd (een klassieke vector voor injectie van argumenten).
Concreet scenario met misbruik en oplossing:
#!/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 -- ./*.shHet JSON-uitvoerformaat gebruiken voor automatisering
ShellCheck ondersteunt meerdere uitvoerformaten via --format:
tty(standaard) — terminaluitvoer die voor mensen leesbaar isjson— leesbaar voor machines; ideaal voor dashboards, aangepaste blokkeerregels of uploaden naar SAST-platformsgcc— compatibel met hulpmiddelen die de GCC-foutindeling parseren (IDE's, Vim/Emacs)checkstyle— XML-indeling die wordt verwerkt door de Jenkins Checkstyle-plug-in
Met de JSON-indeling kun je geautomatiseerd beleid schrijven, bijvoorbeeld alleen specifieke SC-codes blokkeren of bevindingen uit een grote codebasis samenvoegen in een beveiligingsrapport.
#!/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)'Onjuiste positieven correct onderdrukken
ShellCheck overal uitschakelen ondermijnt het doel ervan. De juiste aanpak is gerichte, gedocumenteerde onderdrukking die alleen de exacte regel of het blok beïnvloedt waar de bevinding echt niet van toepassing is.
Drie mechanismen voor onderdrukking:
- Inline uitschakelen —
# shellcheck disable=SC2086op de regel boven de code die de bevinding veroorzaakt. Heeft alleen effect op die regel. - Blok uitschakelen/inschakelen — omsluit een gedeelte met
# shellcheck disable=…en# shellcheck enable=…. - Richtlijn op bestandsniveau — plaats
# shellcheck disable=…bovenaan het bestand (zelden gerechtvaardigd; documenteer waarom).
Elke onderdrukking moet een opmerking bevatten waarin wordt uitgelegd waarom de bevinding een onjuiste positieve is:
#!/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=SC2016ShellCheck configureren via .shellcheckrc
Voor projectbrede instellingen leest ShellCheck .shellcheckrc vanaf de map van het script omhoog tot /. Zo hoef je niet bij elke aanroep opnieuw opties op te geven en blijven scripts voor controlepoorten eenvoudig.
Nuttige richtlijnen in .shellcheckrc:
shell=bash— overschrijft de detectie van het dialect (handig voor bestanden zonder shebang)enable=all— activeert optionele controles (bijvoorbeeldavoid-nullary-conditionsenrequire-variable-braces)disable=SC2059— projectbrede onderdrukking voor een gerechtvaardigde uitzonderingexternal-sources=true— volgt en controleertsource- en.-richtlijnen
# .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=SC2312Van begin tot eind gehard script: voor en na
De effectiefste manier om bevindingen van ShellCheck eigen te maken, is een realistisch script om te bouwen van een toestand waarin het faalt naar een schone, geharde versie. Het onderstaande script maakt een reservekopie van een map en is geschreven zonder rekening te houden met beveiliging. Het faalt voor minstens vijf verschillende regels van ShellCheck.
Bestudeer beide versies. De na-versie slaagt voor shellcheck --severity=warning zonder richtlijnen voor onderdrukking en is aanzienlijk veiliger bij invoer die door een aanvaller wordt beheerst:
#!/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' >&2Kennistoets: ShellCheck als beveiligingscontrolepoort
Test je begrip van de rol van ShellCheck als beveiligingscontrolepoort.
Samenvatting: statische analyse als beveiligingscontrolepoort
In deze les heb je geleerd hoe je ShellCheck tot een verplichte beveiligingscontrolepoort in je Bash-werkstroom maakt:
- ShellCheck voert statische analyse uit zonder je scripts uit te voeren en onderschept fouten met aanhalingstekens, injectierisico's en onveilige patronen vóór runtime.
- Elke bevinding bevat een SC-code (bijvoorbeeld
SC2086) die verwijst naar gedetailleerde documentatie en aanwijzingen voor de oplossing. - Met de ernstniveaus —
error,warning,info,style— kun je de controlepoort afstemmen:--severity=warningis de aanbevolen beveiligingsdrempel. - Gebruik uitvoer die door machines kan worden gelezen (
--format=json) om rapportage, trendbewaking en SAST-integratie te automatiseren. - Onderdruk spaarzaam: richt je altijd op één regel, documenteer altijd in een opmerking waarom en onderdruk nooit globaal tenzij dit via
.shellcheckrcgerechtvaardigd is. - Combineer ShellCheck met
set -euo pipefail, expliciete aanhalingstekens, afsluiters van het type-- argumenten invoervalidatie voor gelaagde beveiliging.
Een script dat ShellCheck doorstaat, is niet automatisch veilig — maar een script dat ShellCheck niet doorstaat, mag nooit productie bereiken.
Leer Bash met een AI-tutor — gratis
Schrijf echte code en voer die uit in je browser, krijg direct hulp van een AI-tutor die 24/7 beschikbaar is en ga verder waar je gebleven bent op het web of in de app.
- Cursussen
- 22
- Lessen
- 88
Veelgestelde vragen
Is de les “Statische analyse en auditing met ShellCheck” gratis?
Ja — de volledige tekst van “Statische analyse en auditing met ShellCheck” kun je hier gratis op het web lezen. Als je interactief wilt oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is, en de rest van de cursus De Linux-opdrachtregel en Bash-scripting beheersen wilt ontgrendelen, kun je upgraden naar CoddyKit PRO. De cursus De Linux-opdrachtregel en Bash-scripting beheersen bevat in totaal 4 lessen.
Wat leer ik in “Statische analyse en auditing met ShellCheck”?
Integreer ShellCheck in een security gate en interpreteer de bevindingen om elk script te beveiligen. Je oefent met De Linux-opdrachtregel en Bash-scripting beheersen door code rechtstreeks in de browser uit te voeren. Een AI-begeleider die 24/7 beschikbaar is beantwoordt je vragen terwijl je de les doorwerkt.
Heb ik ervaring nodig om met De Linux-opdrachtregel en Bash-scripting beheersen te beginnen?
Ervaring vooraf is niet nodig. De Linux-opdrachtregel en Bash-scripting beheersen op CoddyKit is opgebouwd voor beginners tot gevorderden, zodat je hier of bij het begin kunt starten en in je eigen tempo kunt leren. Dit is les 4 van 4.
Hoe lang duurt de les “Statische analyse en auditing met ShellCheck”?
De meeste lessen van CoddyKit duren ongeveer 5–10 minuten. Elke les is kort en interactief, zodat je gestaag vooruitgaat en op het web en in de app precies verdergaat waar je was gebleven.
Kan ik code schrijven en uitvoeren in deze les over De Linux-opdrachtregel en Bash-scripting beheersen?
Ja. Elke les over De Linux-opdrachtregel en Bash-scripting beheersen bevat een ingebouwde code-editor, zodat je rechtstreeks in je browser echte code kunt schrijven en uitvoeren en direct feedback van AI krijgt — lokale installatie is niet nodig.
Alle lessen in deze cursus
- Command- en argumentinjectie voorkomen
- Veilige omgang met geheimen en een schoon omgevingsbeheer
- Uitvoering met minimale rechten en gedisciplineerd sudo-gebruik
- Statische analyse en auditing met ShellCheck