[英]Why and how to put secrets in environment variables in Node.js?
我對 Node.js 和 Express 還比較陌生,我正在遵循使用 JWT 將身份驗證添加到我的網站的指南: Medium 。 我對本指南的一點感到困惑,關於使用秘密,它說:
JWT 庫將在創建和驗證令牌時讀取此密鑰。 在生產中,我們需要將這個秘密存儲在環境變量而不是文件中。
在指南中,他們將秘密放在配置文件中。 我希望指南描述了為什么 JWT 密碼應該是環境變量而不是配置文件,但它非常模糊。 那么為什么秘密應該是環境變量,以及使用秘密的其他最佳實踐是什么? 我決定使用 Passport & Express Sessions 進行身份驗證,而不是 JWT,但我認為它仍然適用於 session 機密。
我的下一個問題是如何在環境變量中准確設置秘密? 我不再使用該指南,但是使用它的人如何將該配置文件轉換為環境變量? 最后,您通常在典型的 Node.js 應用程序中使用環境變量做什么?
為什么秘密應該是環境變量,而不是存儲在配置文件中?
在處理項目時,您最終會將代碼上傳到 github 上,每個人都可以訪問。 如果您將機密存儲在配置文件中,任何擁有 github 帳戶的人都可以讀取它,因此存在安全風險。 將秘密存儲為環境變量可確保它們的安全。 您的配置文件應該從process.env
object 中讀取這些值。 像這樣的東西:
const jwtSecretKey = process.env.JWT_SECRET_KEY;
const googleApiKey = process.env.GOOGLE_API_KEY;
const serverPort = process.env.PORT || 8000; // 8000 is the default value in case if the env variable has not been set
module.exports = {
jwtSecretKey: jwtSectetKey,
googleApiKey: googleApiKey,
serverPort: serverPort
}
使用這些秘密的任何其他代碼都應該需要配置文件。
const config = require('./config');
...
jwt.verify(token, config.jwtSecretKey);
除了將機密存儲為環境變量之外,您還應該將任何特定於環境的值存儲為環境變量。 例如,假設您的 NodeJS 服務器(即連接到托管數據庫)在三個環境中運行 - 開發、QA 和 PROD。 這些環境中的每一個都將具有有關環境應連接到的 DB HOST 和 PORT 的不同信息。 環境變量是在每個單獨的環境中存儲數據庫主機和端口的好方法,並且可以在所有環境中使用相同的代碼通過讀取環境變量來連接到不同的數據庫。
如何將值存儲為環境變量 - 一種方法是手動,但我不推薦它。 一種方法是使用 shell 腳本。 這實際上取決於您的基礎架構。
也許最初的問題更多是關於為什么你不應該將秘密硬編碼到你的代碼庫中? 希望這對大多數人來說是相當明顯的。 因此,理想情況下,您的秘密和非秘密“應用程序配置”應該與您的代碼庫分開,使您的應用程序“可配置”。 執行此操作的標准方法:
.gitignore
的開發配置文件(例如config.js
或.env
),因此它永遠不會被簽入。config.sample.js
或sample.env
)供新開發人員用作他們自己的開發配置的模板(已簽入)。(是的,我知道這對某些人來說是一個有爭議的話題。對不起。)
您無法真正阻止非特權用戶訪問 ENV 信息。
如果您正在配置生產服務器,您可以使用熟悉的環境變量格式輕松地將您的秘密放入.env
文件中,就像 systemd EnvironmentFile
一樣。
然而,訣竅是您希望將此視為秘密配置,而不是將其加載到進程環境中(通過 systemd、bash、npm 腳本等)或應用程序中的process.env
。
dotenv
默認情況下(當您調用.config()
時)填充process.env
。 因此,如果您想安全地使用dotenv
,可以使用dotenv.parse
解析.env
配置,這樣它就不會將.env
中的秘密放入process.env
。
這將允許您提供帶有生產機密的.env
文件,並使用您添加到.gitignore
的開發.env
文件,這樣您就不會提交您的開發文件。 但是,應用程序開發人員需要記住使用.parse
而不是.config
,否則會帶來安全風險。
或者,如果您不想使用dotenv
,因為它的主要設計專注於加載 ENV……只需使用 json 或 js 配置文件,該文件導出配置 object (例如config.js
)。 與.env
相同,您可以擁有一個未提交的開發版本和一個自動配置的生產版本。 這可以在需要的應用程序中進行,並避免意外將機密填充到環境中的風險(您使用 dotenv)。
所有這一切的缺點是 ENV 為我們提供了一種非常標准的方式來將配置傳遞給生產環境中的任何類型的應用程序/進程/腳本(即不僅僅是 nodejs)。 ENV 不安全意味着我們必須提出一種(理想情況下是標准的)機制來將安全配置傳遞給生產中的各種應用程序和腳本。
在 bash (例如)中,您可以.env
文件,只要這些變量沒有export
ed,它們只是當前 bash 進程的“本地”變量(即不被子進程繼承)。 不使用export
類似於不填充process.env
。 在簡單的 bash 腳本中解析 json 配置......沒有幫助應用程序就不那么有趣了。
您希望應用程序開發人員不必考慮生產機密/配置或安全性,並為他們提供適用於本地開發、測試和生產的標准配置檢索機制。 您希望這種標准機制是直截了當的,並且它們無意中在應用程序端打開安全問題的風險相對較低(將生產機密暴露給子流程)。 當然,沒有什么可以 100% 保護您,就好像應用程序可以訪問秘密一樣,有很多方法可能會泄漏它(寫入文件,進行 http 調用等)......但至少它不會是由於配置加載/傳遞機制。
我們目前正在為生產中的各種應用程序尋找解決此問題的選項......如果有人有深思熟慮的建議或以干凈、通用的方式解決此問題的經驗,我們將非常高興。 我傾向於堅持使用.env
,因為我們已經支持 EnvironmentFile 配置,並且每個應用程序都可以處理它……問題是如何讓應用程序將其加載為配置而不是全面處理環境。
正如我所說,這是為關心安全的人准備的。 許多博客/指南/教程在線展示了通過 ENV 傳遞的秘密。 將秘密加載到進程環境中的dotenv
的流行也可能使您相信這是正確的方法。 安全性始終是風險、努力/成本和不便之間的權衡。 就我個人而言,我認為如果您自動配置生產,那么解決這個問題並不是什么大問題......問題更多的是提出一種可以跨各種應用程序/代碼語言工作的半標准機制。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.