Kem Intensif DevOps · Pelajaran

Mencegah Suntikan Perintah dan Argumen

Petik, sahkan dan hantar input tidak dipercayai melalui tatasusunan untuk menghapuskan pemisahan perkataan dan suntikan berasaskan eval

Pelajaran 1 daripada 413 langkah

Mencegah Suntikan Perintah dan Argumen ialah pelajaran Kem Intensif DevOps percuma di CoddyKit. Ini ialah pelajaran 1 daripada 4. Sebanyak 3 pelajaran dalam laluan pembelajaran ini boleh dibaca sepenuhnya secara percuma — selepas itu, CoddyKit PRO membuka akses kepada semua pelajaran, serta latihan praktikal dengan penyunting kod terbina dalam dan tutor kecerdasan buatan yang tersedia 24/7. Pelajaran ini merupakan sebahagian daripada laluan pembelajaran Kem Intensif DevOps, dan kemajuan anda disegerakkan merentas web serta aplikasi CoddyKit. Kursus Kem Intensif DevOps merangkumi sejumlah 4 pelajaran.

Mengapa Serangan Suntikan Berlaku dalam Bash

Bash ialah bahasa penghubung yang berkuasa — ia menghantar teks terus kepada kernel, program lain dan subcangkerang. Kuasa ini menjadi liabiliti sebaik sahaja masukan tidak dipercayai sampai kepada perintah tanpa pengesahan atau pemetikkan.

Dua punca utama mendorong hampir semua suntikan Bash:

  • Pemisahan perkataan: Pemboleh ubah yang tidak dipetik dipisahkan pada ruang kosong (IFS), lalu menukar satu nilai logik menjadi banyak token cangkerang.
  • Pengembangan glob: Aksara seperti *, ? dan [ dikembangkan oleh cangkerang sebelum perintah dijalankan.

Penyerang yang mengawal nama fail, nama pengguna, parameter URL atau pemboleh ubah persekitaran boleh mengeksploitasi kedua-duanya untuk menjalankan perintah sewenang-wenangnya, membaca fail atau meningkatkan keistimewaan.

Pelajaran ini menunjukkan dengan tepat bagaimana kerentanan ini muncul dan — yang lebih penting — cara menghapuskannya dengan pemetikkan yang betul, pengesahan masukan dan penghantaran argumen berasaskan tatasusunan.

Pemisahan Perkataan: Ancaman Senyap

Apabila Bash menemui pemboleh ubah yang tidak dipetik, ia memisahkan nilainya pada mana-mana aksara yang disenaraikan dalam $IFS (lalai: ruang, tab, baris baharu). Perkara yang kelihatan seperti satu argumen menjadi banyak argumen.

Jalankan skrip di bawah dan perhatikan bagaimana nama fail yang mengandungi ruang menjadi dua argumen berasingan kepada 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

Sentiasa Gunakan Pemetikkan: Peraturan Pertama Bash Defensif

Pertahanan paling mudah dan berkesan terhadap pemisahan perkataan ialah sentiasa menggunakan tanda petik berganda pada pengembangan pemboleh ubah.

  • "$var" — dikembangkan menjadi tepat satu token, sambil mengekalkan ruang, tab dan baris baharu.
  • 'literal' — tanda petik tunggal: tiada pengembangan langsung, berguna untuk rentetan tetap.
  • Jangan gunakan $var tanpa petik melainkan anda memang memerlukan pemisahan perkataan dan pengembangan glob.

Skrip di bawah menunjukkan versi selamat bagi contoh sebelumnya.

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

Suntikan Glob: Apabila * Menjadi Senjata

Pemboleh ubah yang tidak dipetik juga tertakluk kepada pengembangan nama laluan (glob). Jika masukan yang dikawal pengguna mengandungi * atau ?, Bash mengembangkannya berdasarkan sistem fail sebelum perintah dijalankan.

Vektor serangan klasik: borang web yang menetapkan PATTERN=* dan skrip menjalankan cp $PATTERN /tmp/leak/ — menyalin setiap fail dalam direktori semasa.

Penyelesaiannya sama: gunakan tanda petik berganda pada pemboleh ubah. "$PATTERN" yang dipetik dihantar secara literal; cangkerang tidak melakukan pengembangan glob terhadapnya.

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

Suntikan Argumen melalui Parameter Kedudukan yang Tidak Dipetik

Skrip yang menerima argumen daripada pemanggil ialah sasaran utama suntikan. Setiap parameter kedudukan ($1, $2, ...) mestilah dipetik di mana-mana sahaja ia digunakan.

Pola yang amat berbahaya ialah menghantar $@ atau $* tanpa petik kepada perintah lain:

  • "$@" — mengembangkan setiap parameter kedudukan sebagai perkataan berasingan dan dipetik secara individu. Sentiasa gunakan bentuk ini.
  • $@ atau $* tanpa petik — tertakluk kepada pemisahan perkataan dan pengembangan glob.
  • "$*" — menggabungkan semua parameter menjadi satu perkataan (jarang sekali itulah yang anda mahukan).
#!/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"

Suntikan Perintah melalui eval dan Masukan yang Tidak Disahkan

eval menghuraikan semula argumennya sebagai kod cangkerang. Apa-apa data yang tidak dipercayai dan sampai kepada eval boleh menjalankan perintah sewenang-wenangnya.

Pola berbahaya yang biasa:

  • eval "$user_input"
  • eval echo \$$var (carian pemboleh ubah tidak langsung)
  • Menghantar data pengguna melalui bash -c "$input"

Peraturan: jangan sesekali menghantar masukan tidak dipercayai kepada eval atau bash -c. Gunakan alternatif Bash yang selamat:

  • Pengembangan tidak langsung: ${!varname} dan bukannya eval echo \$$varname
  • Tatasusunan bersekutu untuk carian nilai-kunci dinamik
  • Fungsi dan bukannya rentetan perintah yang dijana
#!/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

Pengesahan Masukan: Senarai Benarkan Mengatasi Senarai Tolak

Menolak aksara yang diketahui buruk (sebuah senarai tolak) adalah rapuh — penyerang boleh mencari pengekodan atau aksara yang anda terlupa. Sebaliknya, gunakan senarai benarkan: terima hanya aksara yang anda tahu selamat.

Strategi senarai benarkan dalam Bash:

  • Padanan ungkapan nalar: [[ "$input" =~ ^[A-Za-z0-9_-]+$ ]]
  • Padanan pola: case "$input" in [A-Za-z0-9]*) ... ;; esac
  • Semakan enum: bandingkan dengan set nilai sah yang tetap

Sahkan pada sempadan — sebaik sahaja masukan memasuki skrip — sebelum masukan menyentuh mana-mana perintah.

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

Menggunakan Tatasusunan untuk Menghantar Argumen dengan Selamat

Apabila anda perlu membina perintah secara dinamik — menambah bendera secara bersyarat atau menggelung melalui masukan — gunakan tatasusunan Bash dan bukannya menggabungkan rentetan.

Penggabungan rentetan meruntuhkan semua struktur; tatasusunan Bash mengekalkan setiap argumen sebagai unsur diskret tanpa penghuraian semula oleh cangkerang.

  • Isytihar: args=()
  • Tambah: args+=(--flag "$value")
  • Laksanakan: command "${args[@]}"

"${args[@]}" mengembangkan setiap unsur sebagai perkataan berasingan yang dipetik secara individu — tepat seperti "$@".

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

Pemisah --: Melindungi daripada Suntikan Bendera

Argumen yang dipetik dengan betul pun boleh disalah tafsir sebagai bendera pilihan jika bermula dengan -. Pertimbangkan rm "$file" apabila file='-rf .': pemetikkan melindungi daripada pemisahan perkataan, tetapi rm masih mentafsir -rf sebagai bendera.

Konvensyen POSIX -- menandakan akhir pilihan kepada kebanyakan utiliti GNU/BSD. Segala-galanya selepas -- dianggap sebagai argumen kedudukan, bukan bendera.

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

Menyanitasi Masukan untuk SQL dan Alat Luaran

Apabila skrip Bash memanggil CLI pangkalan data (psql, mysql), curl dengan URL yang dibekalkan pengguna atau alat yang serupa, dua lapisan tambahan terpakai:

  • Kuiri berparameter: Jangan sesekali menyisipkan data pengguna ke dalam rentetan SQL. Hantar nilai melalui -v dalam psql atau --data-urlencode dalam curl.
  • Asingkan data daripada kod: Gunakan printf dengan rentetan format literal; jangan sesekali membenarkan masukan pengguna menjadi rentetan format.

Contoh di bawah menyoal PostgreSQL dengan selamat sambil memastikan nilai yang dibekalkan pengguna tidak masuk langsung ke dalam teks SQL.

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

Senarai Semak Pengerasan: Menggabungkan Kesemuanya

Skrip Bash selamat bertaraf produksi menggabungkan setiap teknik daripada pelajaran ini menjadi pertahanan berlapis yang konsisten. Berikut ialah templat yang diperkukuh, minimum tetapi lengkap:

  • set -euo pipefail — keluar apabila berlaku ralat, anggap pemboleh ubah yang tidak ditetapkan sebagai ralat, dan sebarkan kegagalan paip.
  • Sahkan semasa masuk — gunakan senarai benarkan untuk setiap masukan luaran sebelum masukan menyentuh mana-mana perintah.
  • Petik semuanya — "$var", "$@", "${array[@]}" — tiada pengecualian kecuali anda memerlukan pemisahan.
  • Gunakan tatasusunan untuk pembinaan perintah dinamik.
  • Awali argumen dengan -- apabila menghantar nama fail atau rentetan yang dibekalkan pengguna.
  • Jangan sesekali gunakan eval dengan data yang tidak dipercayai; utamakan ${!var} untuk carian tidak langsung.
  • Hadkan keizinan — jalankan skrip dengan keistimewaan minimum yang diperlukan; elakkan sudo dalam skrip yang menerima masukan pengguna.
#!/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[@]}"

Semakan Pengetahuan: Pemetikkan dan Pencegahan Suntikan

Uji pemahaman anda tentang konsep utama dalam pelajaran ini.

Ringkasan Pelajaran: Mencegah Suntikan Perintah dan Argumen

Anda telah mempelajari set alat pertahanan lengkap untuk mengendalikan masukan Bash dengan selamat:

  • Pemisahan perkataan dan pengembangan glob ialah mekanisme asas yang menukar pemboleh ubah tidak selamat menjadi vektor suntikan.
  • Gunakan tanda petik berganda pada setiap pemboleh ubah ("$var", "$@", "${arr[@]}") untuk menyekat kedua-dua ancaman.
  • Gunakan "$@" — jangan sesekali gunakan $@ atau $* tanpa petik — apabila meneruskan argumen.
  • Awali nama fail yang dibekalkan pengguna dengan -- untuk mencegah suntikan bendera.
  • Gunakan senarai benarkan untuk semua masukan luaran dengan pengawal ungkapan nalar ([[ $v =~ ^pattern$ ]]) sebelum masukan sampai kepada mana-mana perintah.
  • Bina perintah dinamik dengan tatasusunan (cmd+=() → "${cmd[@]}"), bukan dengan penggabungan rentetan.
  • Hapuskan eval dan bash -c "$input"; gunakan ${!varname} untuk pengembangan tidak langsung yang selamat.
  • Sentiasa mulakan skrip dengan set -euo pipefail dan IFS=$'\n\t' sebagai garis dasar yang diperkukuh.

Amalan ini, jika diterapkan secara konsisten dari baris pertama setiap skrip, mengurangkan permukaan serangan Bash kepada hampir sifar bagi kerentanan kelas suntikan.

Percuma untuk bermula

Pelajari Kem Intensif DevOps dengan tutor kecerdasan buatan — percuma

Tulis dan jalankan kod sebenar dalam pelayar anda, dapatkan bantuan segera daripada tutor kecerdasan buatan yang tersedia 24/7, dan sambung semula dari tempat anda berhenti di web atau dalam aplikasi.

Kursus
142
Pelajaran
568

Soalan Lazim

Adakah pelajaran “Mencegah Suntikan Perintah dan Argumen” percuma?

Ya — sebanyak 3 pelajaran dalam laluan pembelajaran Kem Intensif DevOps, termasuk “Mencegah Suntikan Perintah dan Argumen”, boleh dibaca sepenuhnya secara percuma di web ini. Selepas itu, CoddyKit PRO membuka akses kepada semua pelajaran, serta latihan interaktif dengan penyunting kod terbina dalam dan tutor kecerdasan buatan yang tersedia 24/7. Kursus Kem Intensif DevOps merangkumi sejumlah 4 pelajaran.

Apakah yang akan saya pelajari dalam “Mencegah Suntikan Perintah dan Argumen”?

Petik, sahkan dan hantar input tidak dipercayai melalui tatasusunan untuk menghapuskan pemisahan perkataan dan suntikan berasaskan eval Anda berlatih Kem Intensif DevOps menggunakan kod praktikal yang dijalankan terus dalam pelayar, manakala tutor kecerdasan buatan 24/7 menjawab soalan anda semasa anda mengikuti pelajaran.

Adakah saya memerlukan pengalaman untuk memulakan Kem Intensif DevOps?

Tiada pengalaman terdahulu diperlukan. Pembelajaran Kem Intensif DevOps di CoddyKit disusun untuk pelajar daripada peringkat pemula hingga lanjutan, jadi anda boleh bermula di sini atau dari awal dan belajar mengikut kadar anda sendiri. Ini ialah pelajaran 1 daripada 4.

Berapa lamakah pelajaran “Mencegah Suntikan Perintah dan Argumen” diambil?

Kebanyakan pelajaran CoddyKit mengambil masa kira-kira 5–10 minit. Setiap pelajaran ringkas dan interaktif, jadi anda boleh membuat kemajuan secara berterusan dan menyambung tepat dari tempat anda berhenti di web atau aplikasi.

Bolehkah saya menulis dan menjalankan kod dalam pelajaran Kem Intensif DevOps ini?

Ya. Setiap pelajaran Kem Intensif DevOps menyertakan penyunting kod terbina dalam, jadi anda boleh menulis dan menjalankan kod sebenar terus dalam pelayar serta menerima maklum balas kecerdasan buatan serta-merta — tanpa memerlukan persediaan setempat.

Semua pelajaran dalam kursus ini

  1. Mencegah Suntikan Perintah dan Argumen
  2. Pengendalian Rahsia yang Selamat dan Kebersihan Persekitaran
  3. Pelaksanaan dengan Keistimewaan Minimum dan Disiplin sudo
  4. Analisis Statik dan Pengauditan dengan ShellCheck
← Kembali ke Kem Intensif DevOps