Komento- ja argumentti-injektioiden estäminen
Lainaa, validoi ja välitä epäluotettava syöte taulukkoina, jotta estät sanajaon ja eval-pohjaiset injektiot.
Komento- ja argumentti-injektioiden estäminen on ilmainen DevOps-bootcamp-oppitunti CoddyKitissä. Tämä on oppitunti 1/4. Voit lukea tästä oppimispolusta kokonaan mitkä tahansa 3 oppituntia ilmaiseksi — sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä käytännön harjoittelun sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. Oppitunti kuuluu DevOps-bootcamp-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. DevOps-bootcamp-kurssilla on yhteensä 4 oppituntia.
Miksi injektiohyökkäyksiä tapahtuu Bashissa
Bash on tehokas liimakieli — se välittää tekstiä suoraan ytimelle, muille ohjelmille ja alikuorille. Tämä teho muuttuu riskiksi heti, kun epäluotettu syöte päätyy komennolle ilman tarkistusta tai lainausta.
Lähes kaikkien Bash-injektioiden taustalla on kaksi perussyytä:
- Sanojen pilkkominen: Lainaamattomat muuttujat pilkotaan tyhjemerkkien (
IFS) kohdalta, jolloin yksi looginen arvo muuttuu useiksi komentotulkin tunnuksiksi. - Jokerimerkkien laajennus: Merkit kuten
*,?ja[laajennetaan komentotulkissa ennen komennon suorittamista.
Hyökkääjä, joka hallitsee tiedostonimeä, käyttäjänimeä, URL-parametria tai ympäristömuuttujaa, voi hyödyntää kumpaakin suorittaakseen mielivaltaisia komentoja, lukeakseen tiedostoja tai korottaakseen käyttöoikeuksia.
Tässä oppitunnissa näytetään tarkasti, miten nämä haavoittuvuudet syntyvät ja — mikä tärkeintä — miten ne poistetaan oikealla lainauksella, syötteen tarkistuksella ja taulukoihin perustuvalla argumenttien välityksellä.
Sanojen pilkkominen: huomaamaton uhka
Kun Bash kohtaa lainaamattoman muuttujan, se pilkkoo sen arvon kaikkien $IFS-muuttujassa lueteltujen merkkien kohdalta (oletuksena välilyönti, sarkain ja rivinvaihto). Yhdeltä argumentilta näyttävästä arvosta tulee useita argumentteja.
Suorittakaa alla oleva skripti ja tarkkailkaa, kuinka välilyönnin sisältävä tiedostonimi muuttuu kahdeksi erilliseksi rm-komennon argumentiksi.
#!/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):"
lsLainatkaa aina: puolustavan Bash-ohjelmoinnin ensimmäinen sääntö
Yksinkertaisin ja tehokkain suoja sanojen pilkkomista vastaan on lainata muuttujalaajennukset aina kaksinkertaisilla lainausmerkeillä.
"$var"— laajennetaan täsmälleen yhdeksi tunnukseksi, jolloin välilyönnit, sarkaimet ja rivinvaihdot säilyvät.'literal'— yksinkertaiset lainausmerkit: mitään laajennuksia ei tehdä; sopii kiinteille merkkijonoille.- Älkää käyttäkö muuttujaa
$varlainaamattomana, paitsi jos tarvitsette nimenomaisesti sanojen pilkkomista ja jokerimerkkien laajennusta.
Alla oleva skripti näyttää edellisen esimerkin turvallisen version.
#!/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):'
lsJokerimerkkien injektio: kun * muuttuu aseeksi
Lainaamattomat muuttujat ovat alttiita myös polkulaajennukselle (jokerimerkkien käsittelylle). Jos käyttäjän hallitsema syöte sisältää merkin * tai ?, Bash laajentaa sen tiedostojärjestelmän perusteella ennen komennon suorittamista.
Perinteinen hyökkäysvektori on verkkolomake, joka asettaa arvon PATTERN=*, minkä jälkeen skripti suorittaa komennon cp $PATTERN /tmp/leak/ — tällöin kaikki nykyisen hakemiston tiedostot kopioidaan.
Korjaus on sama: lainatkaa muuttuja kaksinkertaisilla lainausmerkeillä. Lainattu "$PATTERN" välitetään sellaisenaan, eikä komentotulkki suorita sille jokerimerkkien laajennusta.
#!/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_dstArgumentti-injektio lainaamattomien paikkaparametrien kautta
Kutsujalta argumentteja vastaanottavat skriptit ovat ensisijaisia injektiokohteita. Jokainen paikkaparametri ($1, $2, ...) on lainattava kaikkialla, missä sitä käytetään.
Erityisen vaarallista on välittää $@ tai $* lainaamattomana toiselle komennolle:
"$@"— laajentaa jokaisen paikkaparametrin erilliseksi, yksitellen lainatuksi sanaksi. Käyttäkää aina tätä muotoa.$@tai$*lainaamattomana — altistuu sanojen pilkkomiselle ja jokerimerkkien laajennukselle."$*"— yhdistää kaikki parametrit yhdeksi sanaksi, mikä on harvoin haluttu lopputulos.
#!/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"Komento-injektio eval-komennon ja tarkistamattoman syötteen kautta
eval tulkitsee argumenttinsa uudelleen komentotulkin koodina. Kaikki eval-komennolle päätyvä epäluotettu data voi suorittaa mielivaltaisia komentoja.
Yleisiä vaarallisia malleja:
eval "$user_input"eval echo \$$var(epäsuora muuttujahaku)- Käyttäjädatan välittäminen komennolla
bash -c "$input"
Sääntö: älkää koskaan välittäkö epäluotettua syötettä komennolle eval tai bash -c. Käyttäkää turvallisia Bash-vaihtoehtoja:
- Epäsuora laajennus:
${!varname}komennoneval echo \$$varnamesijaan - Assosiatiiviset taulukot dynaamiseen avain–arvo-hakuun
- Funktiot muodostettujen komentomerkkijonojen sijaan
#!/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
fiSyötteen tarkistus: sallitut listat kiellettyjen listojen sijaan
Tunnetusti haitallisten merkkien hylkääminen (kielletty lista) on hauraata — hyökkääjät löytävät koodauksia tai merkkejä, jotka olette unohtaneet. Määrittäkää sen sijaan sallittu lista: hyväksykää vain merkit, joiden tiedätte olevan turvallisia.
Sallittujen listojen strategioita Bashissa:
- Säännöllisen lausekkeen vertailu:
[[ "$input" =~ ^[A-Za-z0-9_-]+$ ]] - Kuvion vertailu:
case "$input" in [A-Za-z0-9]*) ... ;; esac - Enumeraation tarkistus: verratkaa arvoa kiinteään joukkoon kelvollisia arvoja
Tarkistakaa syöte rajapinnalla — heti, kun se tulee skriptiin — ennen kuin se päätyy millekään komennolle.
#!/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' # REJECTEDArgumenttien turvallinen välittäminen taulukoiden avulla
Kun komento on muodostettava dynaamisesti — esimerkiksi lippoja ehdollisesti lisäämällä tai syötteitä läpikäymällä — käyttäkää Bash-taulukkoa merkkijonojen yhdistämisen sijaan.
Merkkijonojen yhdistäminen hävittää rakenteen; Bash-taulukko säilyttää jokaisen argumentin erillisenä alkiona ilman komentotulkin uutta tulkintaa.
- Määrittely:
args=() - Lisääminen:
args+=(--flag "$value") - Suorittaminen:
command "${args[@]}"
"${args[@]}" laajentaa jokaisen alkion erilliseksi, yksitellen lainatuksi sanaksi — aivan kuten "$@".
#!/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[@]}"---erotin: suojaus lippuinjektiolta
Oikein lainattu argumenttikin voidaan tulkita valitsimeksi, jos se alkaa merkillä -. Tarkastelkaa komentoa rm "$file", kun file='-rf .': lainaus suojaa sanojen pilkkomiselta, mutta rm tulkitsee -rf-osan silti lipuiksi.
POSIX-käytäntö -- ilmaisee useimmille GNU/BSD-apuohjelmille valitsinten lopun. Kaikki ---erottimen jälkeinen käsitellään paikkaperustaisena argumenttina, ei koskaan lippuna.
#!/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_targetSyötteen puhdistaminen SQL:ää ja ulkoisia työkaluja varten
Kun Bash-skriptit kutsuvat tietokantojen komentorivityökaluja (psql, mysql), käyttäjän antamia URL-osoitteita käsittelevää curl-komentoa tai vastaavia työkaluja, sovelletaan kahta lisäkerrosta:
- Parametrisoidut kyselyt: Älkää koskaan upottako käyttäjän dataa SQL-merkkijonoihin. Välittäkää arvot
psql-komennolle valitsimella-vtaicurl-komennolle valitsimella--data-urlencode. - Erotelkaa data ja koodi: Käyttäkää
printf-komentoa kiinteän muotoilumerkkijonon kanssa; älkää koskaan antako käyttäjän syötteen toimia muotoilumerkkijonona.
Alla oleva esimerkki kysyy PostgreSQL:stä turvallisesti ja pitää käyttäjän antaman arvon kokonaan SQL-tekstin ulkopuolella.
#!/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"Tietoturvan vahvistamisen tarkistuslista: kaikki tekniikat yhdessä
Tuotantokelpoinen turvallinen Bash-skripti yhdistää kaikki tämän oppitunnin tekniikat johdonmukaiseksi, kerroksittaiseksi suojaukseksi. Tässä on minimaalinen mutta täydellinen vahvistettu mallipohja:
set -euo pipefail— lopettaa virheessä, käsittelee määrittelemättömät muuttujat virheinä ja välittää putken virheet eteenpäin.- Tarkistakaa syöte heti alussa — määrittäkää jokaiselle ulkoiselle syötteelle sallittu lista ennen kuin se päätyy millekään komennolle.
- Lainatkaa kaikki —
"$var","$@","${array[@]}"— ei poikkeuksia, paitsi jos tarvitsette pilkkomista. - Käyttäkää taulukoita dynaamisten komentojen muodostamiseen.
- Lisätkää argumenttien eteen
--, kun välitätte käyttäjän antamia tiedostonimiä tai merkkijonoja. - Älkää koskaan käyttäkö komentoa
evalepäluotetun datan kanssa; suosikaa epäsuoraan hakuun laajennusta${!var}. - Rajoittakaa käyttöoikeudet — suorittakaa skriptit vähimmillä tarvittavilla käyttöoikeuksilla ja välttäkää
sudo-komentoa käyttäjän syötettä vastaanottavissa skripteissä.
#!/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[@]}"Tietotesti: lainaus ja injektioiden estäminen
Testatkaa ymmärryksenne tämän oppitunnin keskeisistä käsitteistä.
Oppitunnin kertaus: komento- ja argumentti-injektioiden estäminen
Olette käyneet läpi Bashin turvallisen syötteenkäsittelyn kattavan puolustuskeinovalikoiman:
- Sanojen pilkkominen ja jokerimerkkien laajennus ovat perusmekanismeja, jotka muuttavat vaaralliset muuttujat injektiovektoreiksi.
- Lainatkaa jokainen muuttuja kaksinkertaisilla lainausmerkeillä (
"$var","$@","${arr[@]}") kummankin uhan torjumiseksi. - Käyttäkää argumenttien välittämiseen
"$@"-muotoa — älkää koskaan käyttäkö lainaamattomia muotoja$@tai$*. - Lisätkää käyttäjän antamien tiedostonimien eteen
--lippuinjektion estämiseksi. - Määrittäkää kaikelle ulkoiselle syötteelle sallittu lista säännöllisen lausekkeen tarkistuksella (
[[ $v =~ ^pattern$ ]]) ennen kuin syöte päätyy millekään komennolle. - Muodostakaa dynaamiset komennot taulukoilla (
cmd+=()→"${cmd[@]}"), älkää koskaan merkkijonoja yhdistämällä. - Poistakaa käytöstä
evaljabash -c "$input"; käyttäkää${!varname}-laajennusta turvalliseen epäsuoraan hakuun. - Aloittakaa skriptit aina komennoilla
set -euo pipefailjaIFS=$'\n\t'turvallisen perustason saavuttamiseksi.
Kun näitä käytäntöjä sovelletaan johdonmukaisesti jokaisen skriptin ensimmäisestä rivistä alkaen, Bashin injektioluokan haavoittuvuuksien hyökkäyspinta pienenee lähes olemattomaksi.
Opi DevOps-bootcamp tekoälytuutorin avulla — ilmaiseksi
Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.
- Kurssit
- 142
- Oppitunnit
- 568
Usein kysytyt kysymykset
Onko oppitunti ”Komento- ja argumentti-injektioiden estäminen” ilmainen?
Kyllä — voit lukea täällä verkossa kokonaan ilmaiseksi mitkä tahansa DevOps-bootcamp-oppimispolun 3 oppituntia, myös oppitunnin “Komento- ja argumentti-injektioiden estäminen”. Sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä interaktiiviset harjoitukset sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. DevOps-bootcamp-kurssilla on yhteensä 4 oppituntia.
Mitä opin oppitunnilla ”Komento- ja argumentti-injektioiden estäminen”?
Lainaa, validoi ja välitä epäluotettava syöte taulukkoina, jotta estät sanajaon ja eval-pohjaiset injektiot. Harjoittelet DevOps-bootcamp-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.
Tarvitsenko kokemusta aloittaakseni DevOps-bootcamp-opiskelun?
Aiempi kokemus ei ole tarpeen. CoddyKitin DevOps-bootcamp-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 1/4.
Kuinka kauan ”Komento- ja argumentti-injektioiden estäminen”-oppitunnin suorittaminen kestää?
Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.
Voinko kirjoittaa ja suorittaa koodia tällä DevOps-bootcamp-oppitunnilla?
Kyllä. Jokainen DevOps-bootcamp-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.
Kaikki tämän kurssin oppitunnit
- Komento- ja argumentti-injektioiden estäminen
- Salaisten tietojen turvallinen käsittely ja ympäristön siisteys
- Vähimpien oikeuksien suoritus ja sudo-kuri
- Staattinen analyysi ja tarkastus ShellCheckilla