1. 程式人生 > 程式設計 >試試 python-dotenv,避免敏感資訊被硬編碼到程式碼中

試試 python-dotenv,避免敏感資訊被硬編碼到程式碼中

我們開發的每個系統都離不開配置資訊,例如資料庫密碼、Redis密碼、郵件配置、各種第三方配置資訊,這些資訊都非常敏感,一旦洩露出去後果非常嚴重,被洩露的原因一般是程式設計師將配置資訊和程式碼混在一起導致的。

判斷一個系統是否正確地將配置排除在程式碼之外,一個簡單的方法是看該系統的程式碼是否可以立刻開源,而不用擔心會暴露任何敏感資訊。

所以我們做的第一件事情就是將配置資訊與程式碼解耦,根據不同的部署環境(開發環境、測試環境、預釋出、生產環境)各使用一套配置檔案,然後將配置資訊集中到配置檔案中。

例如在 django 最佳實踐裡面,就有這種做法,每個部署環境都有一個獨立的配置檔案,因為每個部署環境所需要的配置各不相同。

├── settings
│   ├── __init__.py
│   ├── base.py
│   ├── local.py
│   ├── production.py
│   └── test.py
複製程式碼

系統啟動的時候,根據指定的環境變數決定載入哪個配置檔案。

if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE","settings.local")複製程式碼

這樣就完了嗎?

不,因為配置資訊還是和專案程式碼捆綁在一起,如果配置檔案與程式碼同步到版本控制系統又擔心敏感資訊洩露。

前面只是將配置與程式碼解耦,但是程式碼與敏感配置資訊並沒有完全隔離。

一個更好的辦法就是將配置儲存於環境變數中,環境變數可以非常方便地在不同的部署間做修改,卻不動一行程式碼,而這些資訊同步到程式碼庫的概率微乎其微。

在程式碼中我們通過讀取環境變數中的配置資訊來獲取該值。

settings.py
MAIL_SERVER = os.getenv('MAIL_SERVER')
MAIL_USERNAME = os.getenv('MAIL_USERNAME')
MAIL_PASSWORD = os.getenv('MAIL_PASSWORD')複製程式碼

現在哪怕程式碼開源出去,也沒人知道密碼是什麼。

將配置資訊儲存在變數環境中,有好幾種方式,一種就是手動在命令列挨個設定到環境變數中,類似於:

EXPORT SECRET_KEY=xxxxx
EXPORT SQLALCHEMY_DATABASE_URI=XXXX
EXPORT ACCESSKEYID=XXXXX複製程式碼

這種方式很麻煩,每次啟動都需要設,雖然你也可以寫到類似 .bashrc 這樣的檔案中。

第二種方式是把配置資訊寫在supervisor中,如果你的系統是用supervisor來管理程式的話,supervisor 中可以設定環境變數,如:

[program:xxxx]
environment=
        KEY=value,Key2=value2,key3="val.&"複製程式碼

但是這種方式與 supervisor 的本身配置耦合在一起,用起來比較混亂。

而今天推薦的這個工具 python-dotenv 就可以完全獨立於其它配置,只針對應用本身使用的配置資訊,你只需要把配置資訊全部寫入到專案根目錄的 .env 檔案中

例如這樣:

REDIS_ADDRESS=localhost:6379
MEANING_OF_LIFE=42
MULTILINE_VAR="hello\nworld"複製程式碼

這個檔案我們不放在git版本控制系統中。然後用一行程式碼來載入配置資訊到環境變數中

# settings.py
from dotenv import load_dotenv
load_dotenv()複製程式碼

載入完成後就可以通過 os.getenv 方法去獲取所有的配置資訊。

# settings.py
import os
SECRET_KEY = os.getenv("EMAIL")
DATABASE_PASSWORD = os.getenv("DATABASE_PASSWORD")複製程式碼

這樣就完全將敏感資訊脫離於程式碼,同時程式碼與配置也進行了解耦。 python-dov 的安裝用普通的pip安裝即可

pip install -U python-dotenv複製程式碼

這種使用方式在 django、flask 應用開發中很常見,而且他們基於此庫也做了自己的擴充套件,例如 flask 中可以用 .flaskenv 來代替 .env 檔案。