0Pricing
Linux Command Line & Bash Scripting Mastery · Pelajaran

Mencegah Injeksi Perintah dan Argumen

Gunakan tanda kutip, validasi, dan teruskan input tak tepercaya sebagai array untuk menghilangkan pemisahan kata serta injeksi berbasis eval.

Mencegah Injeksi Perintah dan Argumen adalah pelajaran Linux Command Line & Bash Scripting Mastery gratis di CoddyKit. Ini adalah pelajaran 1 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar Linux Command Line & Bash Scripting Mastery, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus Linux Command Line & Bash Scripting Mastery mencakup 4 pelajaran total.

Mengapa Serangan Injeksi Terjadi di Bash

Bash adalah bahasa perekat yang kuat — Bash meneruskan teks secara langsung ke kernel, program lain, dan sub-shell. Kekuatan itu menjadi kelemahan begitu input yang tidak tepercaya mencapai suatu perintah tanpa validasi atau pengutipan.

Dua penyebab utama memicu hampir semua injeksi Bash:

  • Pemisahan kata: Variabel yang tidak diberi tanda kutip dipisahkan berdasarkan spasi kosong (IFS), sehingga satu nilai logis berubah menjadi banyak token shell.
  • Ekspansi glob: Karakter seperti *, ?, dan [ diperluas oleh shell sebelum perintah benar-benar dijalankan.

Penyerang yang mengendalikan nama file, nama pengguna, parameter URL, atau variabel lingkungan dapat mengeksploitasi keduanya untuk menjalankan perintah arbitrer, membaca file, atau meningkatkan hak istimewa.

Pelajaran ini menunjukkan dengan tepat bagaimana kerentanan tersebut muncul dan — yang lebih penting — cara menghilangkannya dengan pengutipan yang benar, validasi input, dan penerusan argumen berbasis array.

Pemisahan Kata: Ancaman yang Tak Terlihat

Ketika Bash melihat variabel yang tidak diberi tanda kutip, Bash memisahkan nilainya berdasarkan karakter apa pun yang tercantum dalam $IFS (bawaan: spasi, tab, baris baru). Sesuatu yang tampak seperti satu argumen berubah menjadi banyak argumen.

Jalankan skrip di bawah dan amati bagaimana nama file yang mengandung spasi berubah menjadi dua argumen terpisah untuk 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

Selalu Beri Tanda Kutip: Aturan Pertama Bash Defensif

Pertahanan paling sederhana dan efektif terhadap pemisahan kata adalah selalu memberi tanda kutip ganda pada ekspansi variabel.

  • "$var" — diperluas menjadi tepat satu token, dengan mempertahankan spasi, tab, dan baris baru.
  • 'literal' — tanda kutip tunggal: tidak ada ekspansi sama sekali, berguna untuk string tetap.
  • Jangan pernah menggunakan $var tanpa tanda kutip, kecuali Anda memang memerlukan pemisahan kata dan ekspansi glob.

Skrip di bawah menunjukkan versi aman dari 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

Injeksi Glob: Saat * Menjadi Senjata

Variabel yang tidak diberi tanda kutip juga terkena ekspansi nama jalur (globbing). Jika input yang dikendalikan pengguna berisi * atau ?, Bash memperluasnya berdasarkan sistem berkas sebelum perintah dijalankan.

Vektor serangan klasik: formulir web yang menetapkan PATTERN=*, lalu skrip menjalankan cp $PATTERN /tmp/leak/ — menyalin setiap file di direktori saat ini.

Perbaikannya sama: beri tanda kutip ganda pada variabel. "$PATTERN" yang diberi tanda kutip diteruskan secara harfiah; shell tidak pernah melakukan ekspansi 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

Injeksi Argumen melalui Parameter Posisi Tanpa Tanda Kutip

Skrip yang menerima argumen dari pemanggil merupakan sasaran utama injeksi. Setiap parameter posisi ($1, $2, ...) harus diberi tanda kutip di mana pun digunakan.

Pola yang sangat berbahaya adalah meneruskan $@ atau $* tanpa tanda kutip ke perintah lain:

  • "$@" — memperluas setiap parameter posisi sebagai kata yang terpisah dan diberi tanda kutip secara individual. Selalu gunakan bentuk ini.
  • $@ atau $* tanpa tanda kutip — terkena pemisahan kata dan globbing.
  • "$*" — menggabungkan semua parameter menjadi satu kata (jarang merupakan yang Anda inginkan).
#!/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"

Injeksi Perintah melalui eval dan Input yang Tidak Divalidasi

eval mengurai ulang argumennya sebagai kode shell. Data yang tidak tepercaya dan mencapai eval dapat menjalankan perintah arbitrer.

Pola berbahaya yang umum:

  • eval "$user_input"
  • eval echo \$$var (pencarian variabel tidak langsung)
  • Meneruskan data pengguna melalui bash -c "$input"

Aturan: jangan pernah meneruskan input yang tidak tepercaya ke eval atau bash -c. Gunakan alternatif Bash yang aman:

  • Ekspansi tidak langsung: ${!varname}, bukan eval echo \$$varname
  • Array asosiatif untuk pencarian kunci-nilai dinamis
  • Fungsi, bukan string perintah yang dibuat secara dinamis
#!/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

Validasi Input: Daftar yang Diizinkan Lebih Baik daripada Daftar yang Ditolak

Menolak karakter yang diketahui buruk ( daftar yang ditolak ) rapuh — penyerang dapat menemukan pengodean atau karakter yang Anda lupakan. Sebagai gantinya, gunakan daftar yang diizinkan: terima hanya karakter yang Anda ketahui aman.

Strategi daftar yang diizinkan di Bash:

  • Pencocokan regex: [[ "$input" =~ ^[A-Za-z0-9_-]+$ ]]
  • Pencocokan pola: case "$input" in [A-Za-z0-9]*) ... ;; esac
  • Pemeriksaan enum: bandingkan dengan himpunan tetap nilai yang valid

Validasi pada batas masuk — segera setelah input memasuki skrip — sebelum input menyentuh perintah apa pun.

#!/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 Array untuk Meneruskan Argumen dengan Aman

Ketika Anda perlu membangun perintah secara dinamis — menambahkan bendera secara kondisional atau melakukan perulangan pada input — gunakan array Bash, bukan menggabungkan string.

Penggabungan string meruntuhkan seluruh struktur; array Bash mempertahankan setiap argumen sebagai elemen terpisah tanpa penguraian ulang oleh shell.

  • Deklarasikan: args=()
  • Tambahkan: args+=(--flag "$value")
  • Jalankan: command "${args[@]}"

"${args[@]}" memperluas setiap elemen sebagai kata terpisah yang masing-masing diberi tanda kutip — persis 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 dari Injeksi Bendera

Bahkan argumen yang diberi tanda kutip dengan benar dapat disalahartikan sebagai bendera opsi jika diawali dengan -. Pertimbangkan rm "$file" ketika file='-rf .': pengutipan melindungi dari pemisahan kata, tetapi rm tetap menafsirkan -rf sebagai bendera.

Konvensi POSIX -- memberi sinyal akhir opsi kepada sebagian besar utilitas GNU/BSD. Semua yang berada setelah -- diperlakukan sebagai argumen posisi, bukan sebagai 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

Membersihkan Input untuk SQL dan Perkakas Eksternal

Ketika skrip Bash memanggil CLI basis data (psql, mysql), curl dengan URL yang diberikan pengguna, atau perkakas serupa, berlaku dua lapisan tambahan:

  • Kueri berparameter: Jangan pernah menyisipkan data pengguna ke dalam string SQL. Teruskan nilai melalui -v di psql atau --data-urlencode di curl.
  • Pisahkan data dari kode: Gunakan printf dengan string format harfiah; jangan pernah menjadikan input pengguna sebagai string format.

Contoh di bawah mengueri PostgreSQL dengan aman, dengan menjaga nilai yang diberikan pengguna sepenuhnya di luar 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"

Daftar Periksa Penguatan: Menerapkan Semuanya

Skrip Bash aman berstandar produksi menggabungkan setiap teknik dari pelajaran ini menjadi pertahanan berlapis yang konsisten. Berikut templat penguatan yang minimal tetapi lengkap:

  • set -euo pipefail — keluar saat terjadi kesalahan, perlakukan variabel yang tidak ditetapkan sebagai kesalahan, dan teruskan kegagalan pipe.
  • Validasi saat masuk — gunakan daftar yang diizinkan untuk setiap input eksternal sebelum input menyentuh perintah apa pun.
  • Beri tanda kutip pada semuanya — "$var", "$@", "${array[@]}" — tanpa pengecualian, kecuali Anda memerlukan pemisahan.
  • Gunakan array untuk membangun perintah dinamis.
  • Awali argumen dengan -- saat meneruskan nama file atau string yang diberikan pengguna.
  • Jangan pernah menggunakan eval dengan data yang tidak tepercaya; pilih ${!var} untuk pencarian tidak langsung.
  • Batasi izin — jalankan skrip dengan hak istimewa minimum yang diperlukan; hindari sudo di dalam skrip yang menerima input 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[@]}"

Pemeriksaan Pengetahuan: Pengutipan dan Pencegahan Injeksi

Uji pemahaman Anda tentang konsep-konsep utama dalam pelajaran ini.

Ringkasan Pelajaran: Mencegah Injeksi Perintah dan Argumen

Anda telah mempelajari perangkat lengkap untuk menangani input Bash dengan aman secara defensif:

  • Pemisahan kata dan ekspansi glob adalah mekanisme utama yang mengubah variabel tidak aman menjadi vektor injeksi.
  • Beri tanda kutip ganda pada setiap variabel ("$var", "$@", "${arr[@]}") untuk menekan kedua ancaman tersebut.
  • Gunakan "$@" — jangan pernah gunakan $@ atau $* tanpa tanda kutip — saat meneruskan argumen.
  • Awali nama file yang diberikan pengguna dengan -- untuk mencegah injeksi bendera.
  • Gunakan daftar yang diizinkan untuk semua input eksternal dengan penjaga regex ([[ $v =~ ^pattern$ ]]) sebelum input mencapai perintah apa pun.
  • Bangun perintah dinamis dengan array (cmd+=() → "${cmd[@]}"), bukan dengan penggabungan string.
  • Hilangkan eval dan bash -c "$input"; gunakan ${!varname} untuk ekspansi tidak langsung yang aman.
  • Selalu awali skrip dengan set -euo pipefail dan IFS=$'\n\t' sebagai dasar yang diperkuat.

Jika diterapkan secara konsisten sejak baris pertama setiap skrip, praktik-praktik ini mengurangi permukaan serangan Bash hingga hampir nol untuk kerentanan kelas injeksi.

Pertanyaan yang Sering Diajukan

Apakah pelajaran “Mencegah Injeksi Perintah dan Argumen” gratis?

Ya — teks lengkap “Mencegah Injeksi Perintah dan Argumen” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus Linux Command Line & Bash Scripting Mastery, upgrade ke CoddyKit PRO. Kursus Linux Command Line & Bash Scripting Mastery mencakup 4 pelajaran total.

Apa yang akan aku pelajari di “Mencegah Injeksi Perintah dan Argumen”?

Gunakan tanda kutip, validasi, dan teruskan input tak tepercaya sebagai array untuk menghilangkan pemisahan kata serta injeksi berbasis eval. Kamu berlatih Linux Command Line & Bash Scripting Mastery dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.

Apakah aku perlu pengalaman untuk memulai Linux Command Line & Bash Scripting Mastery?

Tidak diperlukan pengalaman sebelumnya. Linux Command Line & Bash Scripting Mastery di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 1 dari 4.

Berapa lama pelajaran “Mencegah Injeksi Perintah dan Argumen” memakan waktu?

Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.

Bisakah aku menulis dan menjalankan kode dalam pelajaran Linux Command Line & Bash Scripting Mastery ini?

Ya. Setiap pelajaran Linux Command Line & Bash Scripting Mastery menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.

Semua pelajaran dalam kursus ini

  1. Mencegah Injeksi Perintah dan Argumen
  2. Penanganan Rahasia yang Aman dan Kebersihan Environment
  3. Eksekusi dengan Hak Minimum dan Disiplin sudo
  4. Analisis Statis dan Audit dengan ShellCheck
← Kembali ke Linux Command Line & Bash Scripting Mastery