.env 非常方便,幾乎所有現代框架都會用它。但只要存放位置弄錯一處,裡面所有的祕密就可能被任何人讀取。本文從零開始講解它的含義和防護方法。
再講細一點
應用程式裡有「隨環境而變的值」和「不想給人看到的值」。比如資料庫密碼、外部服務的 API key、用來加密工作階段的金鑰等。如果把這些直接寫死在原始碼裡,一旦共享程式碼,祕密也會跟著一起外洩。
於是,把這些集中到 .env 這一個檔案裡,程式碼則以「環境變數」的形式讀取它們。Next.js、Laravel、Rails 等許多框架都採用這種方式。
內容是純文字,一行一個「名稱=值」(以下的值是佔位用的範例)。
APP_ENV=production
DB_HOST=127.0.0.1
DB_PASSWORD=your-db-password-here
PAYMENT_API_KEY=your-payment-api-key-here把設定放在程式碼之外的做法,因 Web 應用設計指南《The Twelve-Factor App》而普及。它判斷設定是否確實分離的標準是:程式碼能否隨時作為開源公開,而不洩漏任何認證資訊。.env 是在開發中實踐這個想法的方便容器。
與相似事物的區別
以下是最常與 .env 混淆的東西。其中只有一部分是存放祕密的安全位置。
| 名稱 | 是什麼 | 可以放祕密嗎? |
|---|---|---|
| 環境變數 | 作業系統或容器傳給執行中程序的值 | 可以(正式環境的標準做法) |
.env | 把環境變數匯集成一個檔案 | 可以,但絕不能放在公開目錄或 Git |
.env.example | 列出名稱、值留空的範本 | 不可以(本來就是要提交的) |
NEXT_PUBLIC_* / VITE_* | 被嵌入瀏覽器 JavaScript 的變數 | 不可以(任何人都能讀) |
| 機密管理服務 | 用來保管機密值的雲端服務 | 可以;以權限與稽核紀錄管理 |
第四列是最容易被忽略的。Next.js 會把以 NEXT_PUBLIC_ 開頭、Vite 會把以 VITE_ 開頭的變數值,在建置時嵌入送到瀏覽器的 JavaScript。即使它放在 .env 裡,帶有這些前綴的變數就會變成公開的。
為什麼是「最危險的檔案」
.env 在一個檔案裡匯集了多把鑰匙,所以這裡一旦外洩,損害就會一下子擴散開來。把每把鑰匙「外洩後會發生什麼」並列出來,就能看出有多嚴重。
| 外洩的值 | 會發生什麼 |
|---|---|
| 資料庫認證資訊 | 資料被讀取、竄改、全部刪除 |
| 外部 API key | 被冒名使用、違規扣費 |
加密金鑰(如 Laravel APP_KEY、簽章金鑰) | 工作階段偽造、冒名登入 |
| OAuth 機密 | 關聯應用程式被接管 |
事實上,.env 被公開是很典型的事故模式。→ .env 曾向全世界公開的故事
實際案例:被公開的 .env 成為目標
- 大規模勒索行動(2024 年):某資安公司的研究團隊報告了一起活動:以 11 萬個網域為目標,蒐集 Web 伺服器上公開的
.env檔案,利用其中的雲端認證資訊竊取資料並索要贖金。被蒐集的變數超過 9 萬個,其中約 7,000 個是雲端服務的、約 1,500 個是社群媒體帳號的。原因並非雲端業者的漏洞,而是公開了.env的組織自身的設定錯誤 - Vercel(2026 年 4 月):內部系統遭未經授權存取,導致部分客戶的環境變數被讀取——是存放在「值可以再次顯示」那一類別中的變數 → 詳細解說(英文)
- 公開版本庫(2026 年的研究):在 GitHub 上公開的 54 萬多筆認證資訊,在研究當時仍然有效。認證資訊沒有撤銷的話,刪除檔案或歷史都沒有用 → 詳細解說(英文)
第一個案例顯示,公開的 .env 不是被人逛到才發現的,而是被自動、大規模地蒐集。不要以為小網站就不會被找到。
外洩的典型模式=存放位置的失誤
最大的原因是「把應用程式本體整個放進公開目錄(docroot)」。本該只暴露 public/,結果卻公開了它的上層目錄,連 .env 都能被取到。
✗ 危險(本體直接放在公開根目錄下)
public_html/ ├─ .env ← 能被讀到! ├─ app/ └─ public/
✓ 安全(本體在外,只公開 public)
app-root/ ├─ .env ← 無法到達 ├─ app/ └─ public_html/ → public/
除了存放位置,它也會經由這些途徑外洩:
- 提交到 Git(公開版本庫會立即公開;私人版本庫則所有有權限的人都看得到)
- 把
.env.bak、.env.old等備份留在公開目錄 - 發布的容器映像或發行用 zip 中仍含有
.env - 如上所述,把祕密放進
NEXT_PUBLIC_/VITE_變數
防護方法
不要放進公開目錄
應用程式本體放在 docroot 之外,公開的只有 public/ 等。在虛擬主機上的具體步驟見 這篇文章。
不要提交到 git
在 .gitignore 裡加入 .env*,只共享把值留空的 .env.example。
外洩後全部輪替
不只是能確認到的那一個,而要把 .env 裡的鑰匙全部更換。按照已被看到的前提來行動。
定期自查
養成確認自己網站上 /.env 是否能被打開的習慣。
如何檢查網站與版本庫
自查(僅限你自己擁有的網域)
# 回傳 200 且有正文就說明已公開。403/404 則暫時沒問題
curl -sI https://你的網域/.env | head -1
curl -sI https://你的網域/.git/config | head -1養成每次發布都做一次這項確認的習慣,就能及早發現存放位置的失誤。
網站的外側與版本庫的內側都要檢查。
- 對已確認所有權的網站,網站安全健檢會一次檢查
/.env、/.env.local、/.env.bak等路徑 - 在版本庫中執行
git log --all --oneline -- .env,看它是否曾被提交。若有任何結果,就撤銷其中的鑰匙 - 把設定或程式碼貼到機密外洩掃描器,找出寫死的 API key 或私鑰(在瀏覽器中執行)
- 檢查
NEXT_PUBLIC_/VITE_變數的清單,確認沒有祕密會進到建置後的 JavaScript
本站觀點:.env 的存放位置與鑰匙的撤銷方式,要一起決定
多數 .env 事故都始於一個放錯位置的檔案。讓損害之後擴大的,是沒有事先定好更換鑰匙的程序。本站建議:若使用 .env,不只要把它放在公開目錄之外、不進 Git,還要事先寫下其中每把鑰匙的撤銷與重新簽發方式。在正式環境中,改用雲端的機密管理服務,或改用值無法再次顯示的環境變數,能進一步減少外洩途徑。
出處(一手資料)
- The Twelve-Factor App, "III. Config" — 12factor.net(把設定存在環境變數;開源化的判斷標準)
- Next.js 文件 "Environment Variables" — nextjs.org(
NEXT_PUBLIC_在建置時被嵌入 JavaScript;不要提交 .env 檔案) - Vite 文件 "Env Variables and Modes" — vite.dev(
VITE_變數會暴露給用戶端程式碼) - Unit 42(Palo Alto Networks), "Leaked Environment Variables Allow Large-Scale Extortion Operation in Cloud Environments"(2024 年 8 月 15 日)— unit42.paloaltonetworks.com