0Pricing
DevOps Bootcamp · Pelajaran

Analisis Statis dan Audit dengan ShellCheck

Integrasikan ShellCheck ke dalam gerbang keamanan dan tafsirkan temuannya untuk memperkuat setiap skrip.

Analisis Statis dan Audit dengan ShellCheck adalah pelajaran DevOps Bootcamp gratis di CoddyKit. Ini adalah pelajaran 4 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 DevOps Bootcamp, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus DevOps Bootcamp mencakup 4 pelajaran total.

Apa Itu ShellCheck dan Mengapa Penting

ShellCheck adalah alat analisis statis sumber terbuka untuk skrip shell. Alat ini mengurai sumber Bash (serta POSIX sh, dash, dan ksh) tanpa menjalankannya, lalu melaporkan bug, konstruksi yang tidak aman, masalah portabilitas, dan masalah gaya—masing-masing diberi kode aturan unik seperti SC2086.

Dalam alur yang diperkuat keamanannya, ShellCheck bertindak sebagai gerbang wajib: tidak ada skrip yang dikirim sebelum lolos pemeriksaan. Hal ini penting karena:

  • Banyak kerentanan shell (pemisahan kata, injeksi, perluasan tanpa tanda kutip) tidak terlihat saat pengujian jalur normal, tetapi muncul saat menerima input yang dikendalikan penyerang.
  • ShellCheck menangkap kelas bug ini sebelum waktu eksekusi, tanpa biaya.
  • ShellCheck mendokumentasikan mengapa setiap pola berbahaya, sehingga kesadaran tim Anda meningkat seiring waktu.

Pasang alat ini di sistem apa pun:

# 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

Menjalankan ShellCheck untuk Pertama Kalinya

Pemanggilan paling sederhana adalah shellcheck <script>. ShellCheck membaca baris shebang untuk menentukan dialek shell, lalu mengeluarkan temuan ke stdout.

Setiap temuan mencakup:

  • Nomor berkas dan baris—lokasi yang tepat
  • Tingkat keparahan—error, warning, info, atau style
  • Kode SC—pengenal aturan yang stabil dan dapat Anda cari atau nonaktifkan
  • Penjelasan untuk manusia—memberi tahu Anda apa yang salah dan sering kali cara memperbaikinya

Jalankan skrip di bawah ini dan amati keluaran yang akan dihasilkan ShellCheck:

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

Menafsirkan Keluaran ShellCheck dan Kode SC

Untuk skrip pada adegan sebelumnya, ShellCheck akan mengeluarkan temuan seperti berikut:

  • SC2086 (warning)—Gunakan tanda kutip ganda untuk mencegah globbing dan pemisahan kata—pada $FILE di [ $FILE == '' ] dan di cat $FILE.
  • SC2039 / SC3010 (info)—== di [ ] adalah bashisme; gunakan = untuk POSIX.
  • SC2002 (style)—Cat tidak berguna. Pertimbangkan cmd < file sebagai pengganti cat file | cmd.

Setiap kode SC dipetakan ke halaman wiki di https://www.shellcheck.net/wiki/SCxxxx yang berisi alasan dan contoh yang telah diperbaiki.

Versi skrip yang telah diperbaiki:

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

Tingkat Keparahan dan Tindakan yang Harus Dilakukan

ShellCheck mengklasifikasikan setiap temuan berdasarkan tingkat keparahan. Dalam gerbang keamanan, tangani temuan tersebut sebagai berikut:

  • error—Hampir pasti merupakan bug atau celah keamanan. Hentikan pembuatan. Perbaiki segera. Contoh: SC2148 tanpa shebang, SC2070 $? tanpa tanda kutip.
  • warning—Pola berisiko tinggi yang sering dapat dieksploitasi. Hentikan pembuatan. Perbaiki atau berikan alasan penonaktifan secara eksplisit. Contoh: SC2086 variabel tanpa tanda kutip.
  • info—Kemungkinan benar saat ini, tetapi rapuh atau tidak portabel. Perbaiki dalam PR yang sama kecuali dinyatakan di luar cakupan.
  • style—Preferensi kosmetik / POSIX. Disarankan, tetapi opsional dalam basis kode Bash murni.

Gunakan --severity=warning agar keluar dengan status bukan nol hanya untuk warning dan tingkat di atasnya—ambang gerbang keamanan standar:

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

Mengintegrasikan ShellCheck sebagai Gerbang Keamanan CI

Gerbang keamanan hanya berguna jika bersifat wajib dan otomatis. Pola di bawah ini membungkus ShellCheck dalam langkah CI yang:

  • Menemukan setiap berkas .sh di repositori.
  • Menjalankan ShellCheck dengan --severity=warning dan keluaran JSON yang dapat dibaca mesin.
  • Menggagalkan alur (exit 1) jika ada temuan.
  • Mencetak ringkasan agar teknisi dapat menindaklanjuti temuan tanpa meninggalkan log CI.

Letakkan berkas ini di repositori Anda dan panggil dari alur CI Anda (GitHub Actions, Jenkins, GitLab CI, dan sebagainya):

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

Keluarga SC2086: Perluasan Variabel Tanpa Tanda Kutip

SC2086 adalah temuan ShellCheck yang paling umum dan salah satu kerentanan shell yang paling sering dieksploitasi: perluasan variabel tanpa tanda kutip.

Jika variabel tidak diberi tanda kutip ganda, shell melakukan pemisahan kata (memisahkan berdasarkan IFS) dan perluasan glob pada nilainya. Penyerang yang mengendalikan variabel tersebut dapat menyisipkan argumen tambahan, memicu penelusuran lintas sistem berkas, atau menyebabkan perintah menerima operan yang tidak terduga.

Pola berbahaya yang klasik:

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

Mendeteksi Risiko Injeksi Perintah dengan SC2046 dan SC2035

Dua aturan yang kurang dikenal tetapi penting menangani injeksi perintah melalui keluaran subshell:

  • SC2046—Berikan tanda kutip pada ini untuk mencegah pemisahan kata / glob di dalam $(…). Jika keluaran subshell digunakan tanpa tanda kutip, spasi atau karakter glob apa pun dalam keluaran tersebut menjadi token shell.
  • SC2035—Gunakan ./*.sh sebagai pengganti *.sh untuk mencegah nama berkas yang diawali - ditafsirkan sebagai opsi (vektor injeksi argumen klasik).

Skenario eksploitasi dan perbaikan konkret:

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

Menggunakan Format Keluaran JSON untuk Otomatisasi

ShellCheck mendukung beberapa format keluaran melalui --format:

  • tty (bawaan)—keluaran terminal yang mudah dibaca manusia
  • json—dapat dibaca mesin; ideal untuk dasbor, pemblokir khusus, atau pengunggahan ke platform SAST
  • gcc—kompatibel dengan alat yang mengurai format kesalahan GCC (IDE, Vim/Emacs)
  • checkstyle—format XML yang digunakan oleh plugin Checkstyle Jenkins

Format JSON memungkinkan Anda menulis kebijakan otomatis, misalnya memblokir hanya kode SC tertentu atau menggabungkan temuan dari basis kode besar menjadi laporan keamanan.

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

Menonaktifkan Positif Palsu dengan Benar

Menonaktifkan ShellCheck secara menyeluruh menggagalkan tujuannya. Pendekatan yang benar adalah penonaktifan terarah dan terdokumentasi yang hanya memengaruhi baris atau blok tepat tempat temuan tersebut memang tidak berlaku.

Tiga mekanisme penonaktifan:

  • Penonaktifan sebaris—# shellcheck disable=SC2086 pada baris di atas kode yang bermasalah. Hanya memengaruhi baris tersebut.
  • Penonaktifan/pengaktifan blok—bungkus suatu bagian dengan # shellcheck disable=… dan # shellcheck enable=….
  • Direktif tingkat berkas—letakkan # shellcheck disable=… di bagian atas berkas (jarang dapat dibenarkan; dokumentasikan alasannya).

Setiap penonaktifan harus menyertakan komentar yang menjelaskan mengapa temuan tersebut merupakan positif palsu:

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

Mengonfigurasi ShellCheck melalui .shellcheckrc

Untuk pengaturan seluruh proyek, ShellCheck membaca .shellcheckrc dari direktori skrip ke atas hingga /. Dengan demikian, Anda tidak perlu mengulangi bendera pada setiap pemanggilan dan skrip gerbang tetap sederhana.

Direktif yang berguna dalam .shellcheckrc:

  • shell=bash—menimpa deteksi dialek (berguna untuk berkas tanpa shebang)
  • enable=all—mengaktifkan pemeriksaan opsional (misalnya, avoid-nullary-conditions, require-variable-braces)
  • disable=SC2059—penonaktifan seluruh proyek untuk pengecualian yang memiliki alasan
  • external-sources=true—mengikuti dan memeriksa direktif source / .
# .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

Skrip Diperkuat Menyeluruh: Sebelum dan Sesudah

Cara paling efektif untuk memahami temuan ShellCheck adalah memfaktorkan ulang skrip realistis dari kondisi gagal menjadi skrip yang bersih dan diperkuat. Skrip di bawah ini mencadangkan sebuah direktori dan ditulis tanpa mempertimbangkan keamanan. Skrip tersebut gagal dalam setidaknya lima aturan berbeda di ShellCheck.

Pelajari kedua versinya. Versi sesudah lolos dari shellcheck --severity=warning tanpa direktif penonaktifan dan jauh lebih aman saat menerima input yang dikendalikan penyerang:

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

Uji Pengetahuan: ShellCheck dalam Gerbang Keamanan

Uji pemahaman Anda tentang peran ShellCheck sebagai gerbang keamanan.

Rangkuman: Analisis Statis sebagai Gerbang Keamanan

Dalam pelajaran ini, Anda mempelajari cara menjadikan ShellCheck sebagai gerbang keamanan wajib dalam alur kerja Bash Anda:

  • ShellCheck melakukan analisis statis tanpa menjalankan skrip Anda, sehingga dapat menangkap kesalahan penggunaan tanda kutip, risiko injeksi, dan pola tidak aman sebelum waktu eksekusi.
  • Setiap temuan memiliki kode SC (misalnya, SC2086) yang terhubung ke dokumentasi terperinci dan panduan perbaikan.
  • Jenjang tingkat keparahan—error, warning, info, style—memungkinkan Anda menyesuaikan gerbang: --severity=warning adalah ambang keamanan yang disarankan.
  • Gunakan keluaran yang dapat dibaca mesin (--format=json) untuk mengotomatisasi pelaporan, pelacakan tren, dan integrasi SAST.
  • Lakukan penonaktifan seperlunya: selalu targetkan satu baris, selalu dokumentasikan alasannya dalam komentar, dan jangan pernah menonaktifkan secara global kecuali dibenarkan oleh .shellcheckrc.
  • Padukan ShellCheck dengan set -euo pipefail, penggunaan tanda kutip secara eksplisit, terminator -- argument, dan validasi input sebagai pertahanan berlapis.

Skrip yang lolos ShellCheck tidak otomatis aman—tetapi skrip yang gagal dalam ShellCheck tidak boleh mencapai produksi.

Pertanyaan yang Sering Diajukan

Apakah pelajaran “Analisis Statis dan Audit dengan ShellCheck” gratis?

Ya — teks lengkap “Analisis Statis dan Audit dengan ShellCheck” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus DevOps Bootcamp, upgrade ke CoddyKit PRO. Kursus DevOps Bootcamp mencakup 4 pelajaran total.

Apa yang akan aku pelajari di “Analisis Statis dan Audit dengan ShellCheck”?

Integrasikan ShellCheck ke dalam gerbang keamanan dan tafsirkan temuannya untuk memperkuat setiap skrip. Kamu berlatih DevOps Bootcamp 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 DevOps Bootcamp?

Tidak diperlukan pengalaman sebelumnya. DevOps Bootcamp 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 4 dari 4.

Berapa lama pelajaran “Analisis Statis dan Audit dengan ShellCheck” 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 DevOps Bootcamp ini?

Ya. Setiap pelajaran DevOps Bootcamp 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 DevOps Bootcamp