File .env — 6 Kesalahan yang Menyebabkan Kunci Anda Tersimpan di GitHub
Kebanyakan kebocoran file .env bukan karena para hacker — melainkan karena para pengembang yang mengunggah file sebelum aturan .gitignore diatur, mengirimkan file .env.example dengan nilai aktual, atau membiarkan kerangka kerja secara diam-diam mengintegrasikan rahasia server ke dalam JavaScript klien. Berikut ini adalah 6 kesalahan yang sebenarnya terjadi.
Laporan tentang Penyebaran Rahasia GitGuardian tahun 2023 menemukan lebih dari 12 juta rahasia yang diserahkan ke repositori GitHub publik. Sebagian besar tidak dicuri — mereka diunggah oleh pengembang yang benar-benar berpikir mereka telah menangani hal tersebut. Ini adalah pola yang bertanggung jawab.
1. Menambahkan .gitignore setelah komit pertama
.gitignore dipindahkan. Jika file sudah ada di sejarah Git, menambahkannya ke tidak berpengaruh. Git tetap mengendalikannya dan akan tetap mengonfirmasi perubahan terhadap file tersebut. file dari proses penyimpanan. Sekali suatu file diikuti — bahkan secara singkat — maka ia masuk ke sejarah git. Jika Anda membuat .env, menjalankan git add . && git commit, lalu menambahkan .env ke .gitignore setelahnya, file tersebut tetap ada di setiap komit sebelum perubahan tersebut.
Periksa apakah sudah ada di sejarah:
git log --all -- .env
Jika hasilnya adalah komit, maka rahasia tersebut ada di sejarah. Rotasi kredensial terlebih dahulu. Lalu hapus file tersebut dari sejarah menggunakan git-filter-repo (pengganti yang direkomendasikan untuk git filter-branch):
pip install git-filter-repo
git filter-repo --path .env --invert-paths
Lakukan force-push ke semua remote dan beri tahu rekan kerja untuk mengklon ulang. Komit-komit tersebut tetap ada di setiap klon yang dibuat sebelum penghapusan — termasuk sistem CI otomatis yang melakukan pengekstensi repositori tersebut.
2. Menyalin .env ke .env.example tanpa menghapus nilai-nilai
Alur standar: buat .env dengan nilai nyata, lalu salin ke .env.example untuk menunjukkan rekan kerja apa saja kunci yang dibutuhkan proyek tersebut. Salinan inilah yang menjadi masalahnya.
cp .env .env.example menggandakan semua — kunci dan nilai. Dan .env.example seharusnya disimpan. Itulah tujuan utamanya. Nilai nyata di .env.example dimasukkan secara sengaja ke dalam repositori.
❌ Apa yang akhirnya masuk ke git:
DATABASE_URL=postgres://admin:supersecretpassword@prod-db.example.com/appdb
STRIPE_SECRET_KEY=sk_live_51AbcDefGhiJklMnopQrstUvwx...
JWT_SECRET=my-actual-production-jwt-secret
✅ Apa yang .env.example seharusnya terlihat:
DATABASE_URL=postgres://user:password@localhost:5432/appdb
STRIPE_SECRET_KEY=sk_live_YOUR_KEY_HERE
JWT_SECRET=generate-a-random-secret-min-32-chars
Membuat .env.example dengan nilai placeholder terlebih dahulu, komitkan, lalu salin ke .env dan isi nilai nyata — bukan sebaliknya.
3. Mencatat process.env dalam penangulang kesalahan
Yang satu ini dimulai sebagai 'debug cepat' saat insiden terjadi dan tidak pernah dihapus. Atau ia berada di middleware kesalahan umum yang tampaknya tidak berbahaya.
// Classic debug line that makes it to production
console.log('Starting with config:', process.env);
// Generic error handler that dumps everything
app.use((err, req, res, next) => {
logger.error({ config: process.env, error: err.message });
res.status(500).json({ error: 'Internal server error' });
});
process.env di runtime mencakup setiap variabel yang dimuat oleh dotenv, ditambah variabel sistem. Menyampaikan objek lengkap ke logger berarti data tersebut masuk ke aggregator log Anda, layanan pelacakan kesalahan (Sentry, Datadog, Rollbar), dan mungkin ke email atau webhook pemberitahuan kesalahan. Banyak layanan ini mengalir ke penyimpanan pihak ketiga dengan kontrol akses mereka sendiri.
Catat hanya nilai-nilai yang diperlukan untuk diagnosis:
logger.error({
nodeEnv: process.env.NODE_ENV,
appVersion: process.env.APP_VERSION,
error: err.message,
stack: err.stack
});
4. Menyisipkan rahasia ke lapisan gambar Docker
Dua pola yang secara permanen menyisipkan rahasia ke sejarah gambar Docker:
# Pattern 1: COPY bakes the entire .env into a layer
COPY .env .
# Pattern 2: ARG/ENV burns values into build metadata
ARG DATABASE_URL
ENV DATABASE_URL=$DATABASE_URL
Meskipun Anda menghapus file di lapisan berikutnya (RUN rm .env), nilai tersebut tetap dapat dibaca dalam sejarah gambar. Siapa pun yang memiliki akses pull ke gambar dapat menjalankan:
docker history --no-trunc your-image:tag
dan memulihkan nilai ARG yang digunakan saat pembangunan. Docker BuildKit rahasia adalah alat yang tepat — ia menempatkan rahasia selama pembangunan tanpa menulisnya ke lapisan apa pun:
# syntax=docker/dockerfile:1
RUN --mount=type=secret,id=db_url DATABASE_URL=$(cat /run/secrets/db_url) ./setup.sh
Untuk konfigurasi saat berjalan, injeksi variabel lingkungan saat memulai kontainer melalui docker run -e atau environment: dalam Docker Compose yang merujuk ke variabel lingkungan host — tidak pernah nilai yang dihardcode, tidak pernah COPY‘dari file rahasia.
5. Menggunakan placeholder rahasia lemah yang dikirim ke produksi
JWT_SECRET=secret, SESSION_SECRET=keyboard cat, APP_KEY=changeme, ENCRYPTION_KEY=1234567890abcdef. Ini dimulai sebagai placeholder pengembangan dan kadang-kadang tidak pernah diganti. Penyerang yang melakukan brute-force pada tanda tangan JWT secara aktif mencoba string ini — mereka ada dalam daftar kata karena muncul di pencarian GitHub.
Sebuah JWT yang ditandatangani dengan HS256 dan rahasia lemah dapat ditebak secara offline dengan alat seperti c-jwt-cracker. Satu token yang berhasil ditangkap cukup untuk melakukan brute-force pada rahasia dan membuat token sembarang.
Rahasia yang benar harus acak secara kriptografi, minimal 32 byte. Buatlah mereka sebelum Anda membutuhkannya — Generator Rahasia Lingkungan di IO Tools akan menghasilkan nilai yang acak secara tepat untuk rahasia umum .env (kunci JWT, rahasia sesi, kunci API) tanpa memerlukan pengaturan apa pun. Tetapkan sejak awal; jangan gunakan placeholder dan rencanakan untuk 'memperbaikinya sebelum produksi.'
6. Konvensi variabel lingkungan framework yang mengungkapkan rahasia ke klien
Beberapa framework populer menggunakan prefiks nama variabel untuk menentukan visibilitas antara klien dan server. Salahnya dalam hal ini menyebabkan rahasia masuk ke bundle JavaScript ke setiap browser yang memuat aplikasi Anda — dalam bentuk teks murni.
- Next.js: Setiap direktori bernama
NEXT_PUBLIC_-prefiks variabel diikat ke sisi klien. Namun rahasia server bocor saat dilewatkan melaluigetServerSidePropsprops — setiap nilai yang dikembalikan dalampropsdikonversi ke HTML halaman dan dapat dibaca dari sumber. - Vite: Variabel yang prefiks
VITE_dikompilasi ke dalam JavaScript klien. MenggunakanVITE_DATABASE_URL“untuk kenyamanan” adalah kesalahan yang sebenarnya dilakukan oleh pengembang. - Create React App: Semua
REACT_APP_variabel akhirnya masuk ke bundle klien, tanpa pengecualian. Tidak ada runtime CRA di sisi server — semua yang memuat akan masuk ke browser.
Verifikasi setelah pembangunan dengan mencari nilai rahasia yang dikenal di direktori output:
grep -r "sk_live_" ./dist
grep -r "sk_live_" ./.next/static
Jika ada nilai yang cocok, maka rahasia tersebut ada di setiap tab browser. Rotasi segera dan audit apa saja yang dibundel.
Satu kebiasaan yang perlu dibangun sejak awal
Sebelum membuat file apa pun yang akan menyimpan rahasia, atur .gitignore terlebih dahulu — bukan sebagai hal yang terlambat. Komit pertama di repositori baru harus .gitignore dan .env.example dengan nilai placeholder. Akan menghasilkan file ignore lengkap, sesuai dengan framework, dalam waktu kurang dari satu menit. .gitignore Generator Keenam kesalahan di atas semua dapat dicegah sebelum kode ditulis. Rotasi adalah satu-satunya solusi setelah rahasia terbuka — dan itu berarti rotasi di mana-mana: penyedia layanan, setiap lingkungan yang memiliki salinan, dan setiap sistem yang mungkin menyimpan nilai tersebut di log.
.env Files — 6 Kesalahan yang Menyebabkan Rahasia Anda Masuk ke GitHub 2
Instal Ekstensi Kami
Tambahkan alat IO ke browser favorit Anda untuk akses instan dan pencarian lebih cepat
恵 Papan Skor Telah Tiba!
Papan Skor adalah cara yang menyenangkan untuk melacak permainan Anda, semua data disimpan di browser Anda. Lebih banyak fitur akan segera hadir!
Alat Wajib Coba
Lihat semua Pendatang baru
Lihat semuaMemperbarui: Kita alat terbaru ditambahkan pada 17 Juni 2026
