[譯]在 Git 中保護 iOS 專案的敏感資訊

YinTokey發表於2018-02-07

原文連結 (自備梯子)

一些可以保護API key等資訊的簡單方法

幾乎所有 iOS 應用都需要使用一些私有值,比如 API key,HMAC secrets 或密碼。有一個簡單的途徑可以把這些私有值包含到你的 app 中,那就是把它們寫在程式碼裡或者寫在 Info.plist 檔案裡。但是這麼做會產生一個問題,就是這些檔案會被包含到 Git 倉庫裡,任何人都可以看到並獲取到原始碼,自然也就可以獲取到這些敏感資訊。

保護原始碼

針對上面提及的問題,首先想到的解決方式可能很簡單,就是直接保護原始碼,這樣其他人就沒法獲取到原始碼,也就沒辦法獲取到這些敏感資訊了。然而不幸的是很多應用是開源的,每個人都需要去獲取其原始碼,所以這種解決方式並不總是奏效的。對於一些頂級的 iOS app,人們還可以去反編譯它或者分析應用包的 Contents 來尋找這些敏感資訊。

讓檔案不包含到 Git 倉庫中

在允許保持程式碼開源的前提下,你可以簡單地讓包含敏感資訊的檔案被 Git 忽略。任何人需要在專案中使用這些敏感資訊,可以簡單地建立相關檔案。對於一個開源專案來說,這些相關細節,可以在 README 或者 wiki 頁面裡註明。

如果按照上面所說,那麼一個 iOS 應用,每一個開發者都需要建立一個原始碼檔案或者一個 plist 檔案,然後新增到專案中。這樣你不得不很小心地在專案設定裡去確保相關檔案的引用情況,即使當這些相關檔案不包含在 Git 中。

xcconfig

我更傾向於把敏感資訊儲存在 xcconfig 檔案中,每一個編譯環境( Debug 或 Release )對應一個檔案。這些檔案可以讓你在不同環境使用不同的配置,為開發者簡化配置,而且讓敏感資訊不包含在 Git 倉庫裡。

1. 建立一些樣例檔案在專案裡

我更喜歡把它們放在 BuildConfig 資料夾裡,讓它們與專案裡的其他檔案分離開。開發者只需要簡單地複製它們,給它們重新命名,然後把一些敏感資訊寫到裡面。這些樣例檔案可以指定 key 的列表,但是不把值包含進去。每一個編譯版本的配置,比如 Debug 和 Release,都需要這麼一個檔案。

debug.example.xcconfig
API_CLIENT_ID = API_CLIENT_ID_FOR_TEST
API_CLIENT_SECRET = API_CLIENT_SECRET_FOR_TEST
複製程式碼
release.example.xcconfig
API_CLIENT_ID = API_CLIENT_ID_FOR_PRODUCTION
API_CLIENT_SECRET = API_CLIENT_SECRET_FOR_PRODUCTION
複製程式碼

你將需要把這些檔案新增到 Xcode 專案中。但是你要確定把他們從 Xcode 的檔案檢查器的 Target Membership 區域中移除。

2. 為每一個編譯版本建立真實檔案

在這裡面把例子的值替換成專案裡真實的值

debug.xcconfig
API_CLIENT_ID = 123456789
API_CLIENT_SECRET = abcdefgh
複製程式碼
release.xcconfig
API_CLIENT_ID = 987654321
API_CLIENT_SECRET = hgfedcba
複製程式碼

你將要把這些檔案新增到專案中,但是它們不需要依附到任何 target。

3. 把這些配置檔案新增到 .gitignore 檔案中。

4. 在專案設定裡選中這些檔案。

你需要在 Info->Configurations 中選中這些檔案,在 Debug 和 Release 中都去設定它們。

[譯]在 Git 中保護 iOS 專案的敏感資訊

值的使用

任何包含在 xcconfig 檔案的值都可以作為專案檔案的環境變數來使用,比如 Info.plist,如果需要再程式碼裡使用這些值,你需要在 Info.plist 建立一個屬性連結到環境變數,使用這種格式 $(API_CONFIG_KEY)

2018-02-01 更新

把敏感資訊儲存在Info.plist 不是最安全的方式。如果你的應該比較注重安全性,那麼你可能需要把這些敏感資訊放在其他地方。本篇文章的側重點事把它們排除在 Git 倉庫之外。後面我會再更新說明如何在程式碼中使用這些環境變數,來作為 Info.plist 的代替方案。

2018-02-03 更新

使用 Sourcery,可以生成一個 Swift 結構體,該結構體包含了在 xcconfig 檔案裡的特定敏感資訊。

  1. Sourcery 新增到專案中。

  2. 建立一個 stencil 檔案,例如 AppSecrets.stencil,把專案程式碼裡需要訪問到的敏感資訊都寫在這裡,作為Swift常量。

struct AppSecrets {
    static let secretKey="{{ argument.secretKey }}"
}
複製程式碼
  1. 新增 build phase 來生成 AppSecrets.swift。
Tools/Sourcery/bin/sourcery --sources Sources --templates Templates/AppSecrets.stencil --output Generated --args secretKey=\"$SECRET_KEY\"
複製程式碼
  • Sourcery 的路徑取決於是怎麼安裝它的,我這例子裡是作為一個獨立版本工具,將它包含在專案中。
  • 上面那個 sources 引數是必須的,雖然在這種情況下並沒有用到,只是在後面輸入了一個在專案裡的有效路徑。
  • 上面 templates 引數是 AppSecrets.stencil 相對於 root 的路徑。
  • output 資料夾是 AppSecrets.swift 寫入的地方,這個資料夾必須有。你可以在 build phase 新增 mkdir -p Generated 來確保這個資料夾存在。
  • 寫這些引數的時候,他們分開的格式應該是這樣:arg1=one,arg2=two 。我避免在 SECRET_KEY 內容裡新增任何特殊字元。
  1. 把 AppSecrets.swift 加入到 .gitignore 檔案中,讓它不被新增到 Git 倉庫中。
  2. 編譯專案,然後把 AppSecrets.swift 加到專案中,這樣 AppSecrets.swift 會被編譯和連結到專案的 target 中。

注意:如果你的 App key 之類的敏感資訊沒有要求在不同的編譯條件下( debug 和 release) 具有不同的值,你可以跳過 xcconfig 部分。你可以使用另一個方案,那就是把敏感資訊寫成一個可執行的 shell 指令碼,新增到 build phase 中。

總結一下,通過以上這些方法,你可以讓你專案中的敏感資訊不被加入到 Git 倉庫裡,與此同時,對於這個專案新的開發者們來說,也比較易於理解上手。

相關文章