連線幾乎就要完成。代理已經備好組態,也指明了服務,卻停在一個欄位上:API 金鑰。服務提供了一個很長的字串,但光看這個字串本身,根本無法看出該往哪裡放。是放在聊天裡?在程式碼旁邊的檔案?還是直接放在組態裡,確保它可以運作?
讓我們用一個模型來分析這個問題。我們會看到值是在哪裡設定的、哪個程序會收到它,以及如何確認一切都設定好,而不需要洩露機密本身。無論是本機執行、MCP 連線還是已發佈的應用程式,模型都是一樣的,變的只是我們要設定誰的環境。
API 金鑰的作用
金鑰把請求和某個帳戶或專案,以及授予您的權限連在一起。服務靠金鑰知道是誰發出請求、對方可以做什麼,以及已經用了多少額度。金鑰的確切含義由具體的服務定義。有時候是對整個帳戶的存取權,有時候只是對某個專案的唯讀存取。

在說明文件裡,"金鑰"旁邊常會出現權杖這個詞。日常文章常把兩者當成同一件事,但機制細節並不相同,差別在於取得方式、有效期限和權限範圍。最好不要把它們看成完全的同義詞,服務到底發的是什麼,要看它的文件。
為什麼服務需要區分使用者呢?看一個日常例子就清楚了。您建立了帳戶,選擇了月度請求配額的方案,並獲得了一個金鑰。然後服務會透過這個金鑰計算您的請求次數,將其與配額進行比較,如果是付費方案的話,還會開立帳單。金鑰洩露給陌生人,就意味著配額和帳單會轉到別人頭上。
金鑰本身不做決定。它只是提供給服務一個指向擁有者設定的連結,然後由服務決定是否允許特定的請求,以及是否需要從配額中扣除。
也有一些值是服務特別標明為公開的,它們本來就該放在頁面程式碼裡。不過,光看變數名稱分不出公開值和機密值。用途寫在文件裡,要去那裡查。下面的範例中到處都是明顯的佔位符,比如 fc-EXAMPLE-0000000000,真實的金鑰不會是這樣的。
應用程式在哪裡存放機密
想像這樣的情況。您直接將金鑰加入網頁程式碼中,執行專案並從 API 取得回應。一切正常。發佈之後,應用程式也能開啟,請求也能通過,看起來任務已經完成。
但每位訪客的瀏覽器在收到程式碼的同時,也收到了金鑰。只要打開開發者工具,在 JavaScript 或請求裡找到金鑰並複製下來就行。之後對方就能以您的名義發送自己的請求。這些請求會消耗您的配額,直到服務開始拒絕您自己的請求。
問題不在哪一種組建工具。頁面交給瀏覽器的一切,瀏覽器的使用者都拿得到:HTML、樣式表、JavaScript、請求的位址和標頭。即使組建時金鑰是從本機的 .env 取得的,一旦代入 JavaScript,它就會和其他程式碼一起送到訪客手上。
後端是在伺服器上執行的程式碼。訪客只會收到它的回應,看不到原始程式碼,也看不到伺服器程序的環境變數。因此,後端可以將金鑰存放在自己那裡,並代表應用程式存取外部服務。
請求的流程也跟著改變。瀏覽器向您的後端發送一般請求,不帶機密金鑰。後端從自己的環境讀取金鑰,把它放進另一個發往 API 的請求,最後只把結果傳回瀏覽器。
現在訪客看得到後端位址和回應資料,但看不到外部服務的金鑰。機密只掌握在使用它的程序手中。
機密可以有兩個可能的擁有者:
- 本機程序 - 已連接整合的 Claude Code、指令稿或開發伺服器。它在您的電腦上執行,也在那裡取得金鑰;
- 已發佈應用程式的後端 - 伺服器上自行呼叫外部 API 的程式碼。它的環境在託管服務的控制台中設定。
這是兩份各自獨立的設定。您電腦環境裡的金鑰不會自己出現在託管環境中,即使服務和變數名稱都一樣。
把金鑰移到後端,瀏覽器就看不到它了,但公開的後端本身仍然需要防範他人的請求。
在 Claude Code 要求您設定值之前,請它說出兩件事:哪個程序會使用金鑰,以及該值如何傳遞給該程序。如果答不出來,現在還沒有東西可以設定。
環境變數如何運作
環境變數是程式啟動時收到的一個具名的值。它有名稱,例如 FIRECRAWL_API_KEY,也有值,就是那串很長的字串。組態和程式碼裡寫的是名稱;值另外存放,不放在程式碼旁邊。
程式從哪裡拿到它?從終端機啟動的程式,會繼承這個終端機的環境。在某個視窗設定變數,再從這個視窗啟動 Claude Code,Claude Code 就看得到它。打開第二個視窗在那裡設定變數,對已經在執行的程序沒有影響,它的環境在啟動時就定下來了。
"金鑰明明設定了,卻不能用"這種抱怨,最常見的原因就在這裡:值設定在別的視窗,或是在啟動之後才設定。解決方法是從有這個變數的終端機重新啟動程序。
教學用的寫法,值顯然是假的:
# bash:為目前終端機設定變數
export FIRECRAWL_API_KEY=fc-EXAMPLE-0000000000# PowerShell:做同樣的事
$env:FIRECRAWL_API_KEY = "fc-EXAMPLE-0000000000"教學範例裡用佔位符這樣寫沒有問題。真正的金鑰就不該用這種方式輸入了:整行會進入命令歷史,關掉終端機後還留在那裡。真正的值要用不回顯的輸入方式:您貼上字串,螢幕上什麼也不顯示,歷史裡只留下命令本身:
# bash:隱蔽輸入值
read -s -r FIRECRAWL_API_KEY
export FIRECRAWL_API_KEY# PowerShell:隱蔽輸入,並把值還原成明文放進環境變數
$secure = Read-Host "FIRECRAWL_API_KEY" -AsSecureString
$env:FIRECRAWL_API_KEY = [System.Net.NetworkCredential]::new('', $secure).Password檢查設定時,要確保值不會出現在螢幕上、日誌裡或螢幕截圖中。要回答"設定了沒有",兩行就夠了:
# bash
[ -n "$FIRECRAWL_API_KEY" ] && echo "已設定" || echo "未設定"# PowerShell
if ($env:FIRECRAWL_API_KEY) { "已設定" } else { "未設定" }不需要列印長度或前幾個字元。這對驗證沒有幫助,而金鑰的片段已經是機密的一部分。
永久設定變數的方法很多,每個系統各有各的做法。現在不需要去研究:在本機工作時,終端機就夠了,而在託管環境中,變數是在託管服務的控制台中設定的。
環境變數是讓機密不必寫進程式碼的方法,而不是保護機制。值不會加密,在同一個環境中執行的程式都能直接讀到它。所以,您設定的是誰的程序,這件事才那麼重要。
為什麼需要 .env 和 .env.example
每開一個新終端機就手動設定一次變數,很快就會膩,所以大家會把值存進文字檔 .env。檔案裡一行存放一組名稱和值。
最常被忽略的是一個重要細節:檔案本身什麼也不會設定。必須有某個東西讀取它,再把值放進程序的環境:應用程式、程式庫,或是啟動您程式的啟動器。不能建立了 .env,就認為任何程式都會自動讀取它。在您的情況下到底是誰載入這個檔案,應該直接弄清楚,而不是用猜的。
它旁邊通常還有兩個檔案:
# .env - 只保留在您的機器上
FIRECRAWL_API_KEY=fc-EXAMPLE-0000000000# .env.example - 給開啟專案的人的範本
# 值是空的,這裡只有名稱
FIRECRAWL_API_KEY=# .gitignore
.env| 檔案 | 用途 | 內容 |
|---|---|---|
.env | 執行時使用的本機值 | 實際的名稱和值,只在您的電腦上 |
.env.example | 給開啟專案的人的提示 | 相同的名稱,但值為空,有時帶有簡短備註 |
.gitignore | 防止本機檔案進入儲存庫的規則 | 含有檔案名稱的行 |
這樣分開的道理很簡單。.env.example 回答的是"這個專案需要哪些變數",它可以放心留在儲存庫裡,因為裡面沒有值。真正的金鑰不會搬進這個檔案,暫時也不行。
如果您還不熟悉 Git,只需記住 .gitignore 的角色。它列出不應該加入儲存庫的檔案。Git 和 .gitignore 的用法,我們會在第 13 級詳細說明。
接下來是 .gitignore 一個大家經常踩到的陷阱。這條規則只對 Git 還沒追蹤的檔案有效。如果 .env 曾經被提交過,之後在 .gitignore 加上這一行,也不會讓它脫離追蹤。檔案仍然在版本控制之下,它的變更會繼續進入提交。Git 文件把這點寫得很清楚:已經被 Git 追蹤的檔案,不受忽略規則影響。gitignore 文件。
圖中的關鍵條件在中間。.gitignore 中相同的一行只在 .env 未被追蹤時有效。對於已經被追蹤的檔案,需要單獨的步驟。
所以,把真正的機密寫進檔案之前,先確認 Git 還不知道這個檔案。git status 會顯示它是否出現在變更中。如果檔案已經被追蹤,就用 git rm --cached .env 取消追蹤,再提交這個變更:檔案會留在磁碟上,但不再受版本控制。
只是要注意,這只影響之後的提交。已經進入歷史記錄的值會一直留在那裡,得用別的方法處理,下文會談到。
如何將金鑰傳遞給 MCP 連線
MCP 是把外部工具連接到 Claude Code 的一種方式。連線寫在 .mcp.json 檔案裡,這個檔案通常和專案一起放在儲存庫中,也就是整個團隊都看得到。所以裡面不能有機密。
透過 HTTP 連接 Firecrawl 服務,最精簡的設定長這樣:
{
"mcpServers": {
"firecrawl": {
"type": "http",
"url": "https://mcp.firecrawl.dev/v2/mcp",
"headers": {
"Authorization": "Bearer ${FIRECRAWL_API_KEY}"
}
}
}
}檔案裡沒有金鑰。標頭中寫的是 ${FIRECRAWL_API_KEY},也就是依名稱參照一個環境變數。Claude Code 會在這裡代入它所在程序環境中的值。進入儲存庫的只有名稱,值則是每個人各有一份。Claude Code 能在 url、headers、env、command 和 args 欄位中做這種代入。Claude Code 的 MCP 文件。
圖中可以看到,請求標頭匯集了來自兩個地方的東西。標頭範本來自共用組態,值則從程序環境代入。沒有任何一步會把金鑰寫進會送進儲存庫的檔案。
位址和傳遞金鑰的方式,要看服務本身的文件。Firecrawl 用的是 Authorization 標頭,文件還特別提醒不要把金鑰放進 MCP 位址。原因很簡單:位址是一般文字,會進入組態、日誌和命令歷史,金鑰也會跟著進去。
有些服務支援透過瀏覽器登入。用戶端會自己開啟登入頁面,根本不必手動傳遞 API 金鑰。Firecrawl 為此另外提供了一個位址。Firecrawl 關於 MCP 的文件。
如果工具沒有反應,請依序檢查:
- 組態裡的變數名稱和您設定的名稱一字不差;
- 值設定在啟動 Claude Code 的那個程序裡;
- 設定變數之後,程序已經重新啟動。
變數不存在時,Claude Code 不會默默出錯。它照樣載入組態,讓 ${FIRECRAWL_API_KEY} 這段文字保持原樣不代入,並顯示一則警告,指出缺少的變數名稱。值本身不會在任何地方印出來,所以這樣診斷是安全的。為了找問題而把整個環境印出來,則完全沒有必要。
這個範例是為了看懂一個已經做好的連線。如何挑選、新增伺服器,以及它會拿到哪些權限,是另一個主題;這裡只關心在這套設定裡,機密放在哪裡。
如果金鑰已經外洩
這種事很常見。金鑰出現在訊息、提交或螢幕截圖裡。不必驚慌,但也別拖。處理順序如下:
- 在服務的帳戶後台撤銷或更換金鑰。只有這一步能讓舊字串再也打不開任何東西;
- 在需要的地方設定新值:本機、託管環境、連線設定;
- 處理外洩的地方:刪除訊息、修正檔案、關閉存取權限;
- 在帳戶後台查看金鑰被怎麼使用過,以及服務顯示的費用。
順序就是這樣,第一步不能往後挪。刪掉訊息,或在舊提交上面加一個新提交,都不會讓原本的機密變得安全。訊息可能被讀過,儲存庫可能被複製,歷史可能被保存。只要金鑰有效,就對擁有它的所有人有效。
關於儲存庫的單獨說明。如果機密進入了提交,GitHub 有刪除此類資料的指南。從儲存庫移除敏感資料。但要注意,完整的歷史清理會重寫現有提交,因此會影響使用該儲存庫的每個人。這類操作應該與擁有者協調,而不是自己憑教學文章來執行。金鑰更換應該立即進行,無需徵求任何人的同意。
可以委託 Claude Code 做什麼
本文的機制,代理幾乎都能包辦,只有一件事例外:機密由您自己輸入。可以放心交給它的是:
- 準備組態,裡面寫變數名稱,而不是值;
- 說明具體是什麼把變數載入程序,以及變數應該出現在哪個程序裡;
- 檢查機密不在用戶端組建和 Git 追蹤的檔案中;
- 執行存取檢查並回報結果,過程中不輸出值。
您要負責的是,透過專門的機制輸入真正的金鑰:終端機裡的隱蔽輸入、本機檔案、託管服務的控制台。機密永遠不進聊天、螢幕截圖或代理的報告,就算"只是一下下,檢查用"也不行。
交代的內容大致可以這樣寫:
透過 API 連接服務。金鑰由我設定。
從文件中查出位址、方法和傳遞金鑰的方式。
在組態中使用環境變數的名稱,不要用值。
說明哪個程序應該拿到變數,以及是什麼載入它的。
確認用戶端組建和 Git 追蹤的檔案中沒有金鑰。
在不輸出任何值或其片段的情況下執行存取驗證。
報告結果:已設定、未設定或存取被拒。最後談談怎麼讀報告。"變數已設定"和"存取可用"是兩個不同的說法,不要拿其中一個代替另一個。值不存在,也和服務拒絕不一樣:前者是請求沒有東西可以用來簽署,後者是服務有回應,但沒有給存取權。如果代理只說"完成了",請追問它具體檢查了什麼。
機密不傳到聊天裡,不出現在螢幕截圖上,也不放進會送進儲存庫的檔案。本文其餘的內容,都是在遵守這條規則的同時不耽誤工作的方法。
GO TO FULL VERSION