Aplikasi Python modern berdiri di atas puluhan package: framework web, driver database, SDK pembayaran. Setiap package yang kita pasang adalah kode orang lain yang berjalan dengan hak akses penuh milik aplikasi kita — membaca environment variables, membuka koneksi jaringan, dan menyentuh file. Serangan pada rantai pasok (supply chain) menargetkan tepat titik itu: bukan kode kita yang dibobol, melainkan dependensinya. Chapter ini membahas kebiasaan yang menutup celah tersebut.

Rantai Pasok yang Menyeret Kita #

Dua pola serangan paling umum. Pertama, typosquatting: penyerang mempublikasikan package bernama mirip package populer — reqeusts alih-alih requests — dan menunggu satu salah ketik di terminal atau di requirements.txt. Kedua, package takeover: package sah yang pengelolanya tidak lagi aktif diambil alih, lalu versi barunya disusupi kode pencuri data. Karena pip install mengeksekusi kode setup, penyerapan data bisa terjadi bahkan sebelum aplikasi dijalankan.

Cara kerjanya sederhana namun fatal: kode dependensi berjalan di dalam proses aplikasi kita. Environment variable berisi secrets — topik Chapter Mengelola Secrets — bisa dibaca, dikirim ke server penyerang, dan dikembalikan seolah tidak terjadi apa-apa.

Memindai dengan pip-audit #

Tool resmi dari PyPA bernama pip-audit memeriksa seluruh package terpasang terhadap basis data kerentanan publik:

bash
pip-audit

Output yang Dihasilkan (ilustratif, isi bergantung pada versi dan kerentanan yang diketahui):

text
No known vulnerabilities found

Pemindaian rutin lebih berguna daripada pemindaian sekali: kerentanan baru ditemukan di package lama setiap hari, sehingga kode yang tidak berubah pun bisa jadi tidak aman lagi.

Pin Versi dan Lockfile #

Langkah pertahanan pertama adalah tahu persis apa yang berjalan di produksi. Module importlib.metadata dari standard library melaporkan versi package yang benar-benar terpasang:

python
from importlib.metadata import version

for paket in ["requests", "flask", "pydantic"]:
    print(f"{paket:10} -> {version(paket)}")

Output yang Dihasilkan:

text
requests   -> 2.32.5
flask      -> 3.1.3
pydantic   -> 2.12.5

Angka versi semacam ini harus sama di laptop, server staging, dan produksi. Caranya adalah pin versi di requirements.txt — dibahas tuntas pada Chapter Dependency Pinning:

text
requests==2.32.5
flask==3.1.3
pydantic==2.12.5

Lockfile melangkah lebih jauh dengan mengunci seluruh pohon dependensi: uv.lock dari uv dan poetry.lock dari Poetry merekam versi setiap package transitive beserta hash-nya, sehingga build ulang menghasilkan environment yang identik bit per bit. Hash yang tercatat membuat penyerang tidak bisa menyelipkan file berbeda di mirror tanpa terdeteksi.

Kebiasaan Minimal dan Terukur #

Empat kebiasaan menutup rantai ini:

  • Tinjau sebelum memasang — baca repository, jumlah pengguna, dan riwayat rilis; package kecil tanpa riwayat yang menawarkan fungsi sepele patut dicurigai.
  • Minimal dependensi — setiap package adalah permukaan serangan baru; kode 20 baris yang bisa kita tulis sendiri sering lebih murah daripada satu dependensi tambahan.
  • Private index — tim besar mengarahkan seluruh pip install ke mirror internal (misalnya devpi atau AWS CodeArtifact) berisi package yang sudah disaring, sehingga typosquatting tidak pernah sampai ke mesin pengembang.
  • SBOM — Software Bill of Materials, daftar seluruh komponen beserta versinya; format standar seperti SPDX menjadikan “apa saja yang berjalan di aplikasi kita” sebuah dokumen yang bisa diaudit, bukan tebakan.

Materi pada Chapter Continuous Integration menunjukkan tempat pemindaian ini berjalan otomatis: setiap commit memicu pip-audit sehingga kerentanan baru terdeteksi sebelum mencapai produksi.