移動認證
by Kathy Dinh
凱西·丁(Kathy Dinh)
如何在移動設備上實施安全的生物特征認證 (How to implement secure Biometric Authentication on mobile devices)
A quick search for React Native biometric authentication would give you several tutorials. That was the first thing I did when there was a need for such a feature in one of my projects. Depending on the level of risk acceptable for your app, one of those solutions might be suitable. For a high risk app like ours, it would not pass security testing.
快速搜索React Native生物特征認證將為您提供一些教程。 當我的一個項目中需要這種功能時,這是我要做的第一件事。 根據您的應用程序可接受的風險級別,這些解決方案之一可能是合適的。 對于像我們這樣的高風險應用程序,它不會通過安全測試。
If you want to add a secure biometric authentication to aa React Native iOS app, you are in the right place.
如果您想向React Native iOS應用添加安全的生物特征認證,那么您來對地方了。
react-native-touchid有什么問題? (What is wrong with react-native-touchid?)
Most implementations use the react-native-touchid package. At line 65 in the TouchID.m file, the authenticate method calls the following LAContext method when attempting TouchID/FaceID authentication:
大多數實現使用react-native-touchid包。 在TouchID.m文件的第65行 ,嘗試進行TouchID / FaceID身份驗證時, authenticate方法將調用以下LAContext方法:
evaluatePolicy:localizedReason:reply:^(BOOL success, NSError *error)
The method relies on a Local Authentication check if the provided fingerprint matches the one enrolled on the device. When the check passes, a success boolean is returned and the user has authenticated successfully with TouchID/FaceID.
如果提供的指紋與設備上注冊的指紋匹配,則該方法依賴于本地身份驗證檢查。 通過檢查后,將返回成功布爾值,并且用戶已使用TouchID / FaceID成功認證。
There have been reports of the possibility to bypass Local Authentication by sending a success signal to Apple’s APIs on jailbroken or non-jailbroken iOS devices. Thus, biometric authentication via Local Authentication is vulnerable to spoofing by an attacker who could interfere with the check at runtime.
有報道稱,有可能通過在越獄或未越獄的iOS設備上向Apple的API發送成功信號來繞過本地身份驗證 。 因此,通過本地身份驗證進行的生物特征身份驗證很容易受到攻擊者的欺騙,攻擊者可能會在運行時干擾檢查。
實施生物特征認證的安全方法是什么? (What is the secure way to implement biometric authentication?)
To implement biometric authentication in an iOS app, there are two ways — either through Apple’s Local Authentication APIs or through access control of Keychain Services natively provided by the underlying system.
要在iOS應用中實現生物特征認證,有兩種方法-通過Apple的本地認證API或通過底層系統本地提供的鑰匙串服務的訪問控制 。
Authenticating with Local Authentication is simpler but generally not recommended for critical applications. As described in the previous section, Local Authentication is a high level API whose behaviour can be overridden, i.e. an attacker could fake a successful authentication by changing the API’s response.
使用本地身份驗證進行身份驗證更簡單,但通常不建議用于關鍵應用程序。 如上一節所述,本地身份驗證是一種高級API,其行為可以被覆蓋,即攻擊者可以通過更改API的響應來偽造成功的身份驗證。
It is acknowledgedly best practice to use Keychain Services for implementing biometric authentication in high risk apps. Keychain Services enforces access control on its stored content using functionality provided by iOS and Secure Enclave. The process executes at the hardware and operating system layer and thus minimises exposure to the less trustworthy application layer. Security risks do exist when user is on a jailbroken or malware-infected device, but these threats can be mitigated by mobile device management (MDM) technology.
公認的最佳實踐是使用鑰匙串服務在高風險應用程序中實施生物識別。 鑰匙串服務使用iOS和Secure Enclave提供的功能對存儲的內容實施訪問控制。 該過程在硬件和操作系統層執行,因此將對可信度較低的應用程序層的影響降至最低。 當用戶處于越獄或感染了惡意軟件的設備上時,確實存在安全風險,但是可以通過移動設備管理(MDM)技術減輕這些威脅。
我們如何通過鑰匙串服務實施生物特征認證? (How do we implement biometric authentication with Keychain Services?)
In order to access Keychain Services in our React Native app, we are going to use the package react-native-keychain. The example code is in TypeScript, which should easily be converted to JavaScript.
為了在React Native應用程序中訪問Keychain Services,我們將使用package react-native-keychain 。 示例代碼在TypeScript中,應該可以輕松轉換為JavaScript。
First, install react-native-keychain and its type declaration as your project dependency:
首先, 安裝 react-native-keychain及其類型聲明作為您的項目依賴項:
npm i -S react-native-keychain
npm i -S @types/react-native-keychain
Next, we have to link the library as it depends on the native component. There are two ways of linking libraries in a React Native app: automatic linking and manual linking. I encountered many errors with CocoaPods while performing automatic linking. Manual linking works but involves many steps.
接下來,我們必須鏈接庫,因為它依賴于本機組件。 在React Native應用程序中有兩種鏈接庫的方式:自動鏈接和手動鏈接。 在執行自動鏈接時,CocoaPods遇到許多錯誤。 手動鏈接有效,但涉及許多步驟。
I discovered that the library is linked properly without errors if you run react-native link after temporarily removing Podfile under the iOS folder. To save you the hassle, let’s follow such a hybrid approach. Assuming your code is under version control so that it is possible to safely revert any changes, delete your Podfile, then run the linking command:
我發現如果臨時刪除iOS文件夾下的Podfile后運行react-native鏈接 ,則該庫已正確鏈接,沒有錯誤。 為了節省您的麻煩,讓我們遵循這種混合方法。 假設您的代碼受版本控制 ,因此可以安全地還原所有更改,刪除Podfile, 然后運行鏈接命令:
react-native link react-native-keychain
Now, undo your Podfile deletion. For iOS 10 you’ll need to enable the Keychain Sharing
entitlement in the Capabilities
section of your build target.
現在,撤消您的Podfile刪除。 對于iOS 10,您需要在構建目標的“ Capabilities
部分中啟用“ Keychain Sharing
權利。
Add the following key value pair to Info.plist:
將以下鍵值對添加到Info.plist :
<key>NSFaceIDUsageDescription</key><string>Enabling Face ID allows you quick and secure access to your account.</string>
Then rebuild your project with:
然后使用以下命令重建項目:
react-native run-ios
In case you encounter difficulty in installing react-native-keychain, refer to this GitHub README.
如果您在安裝react-native-keychain時遇到困難,請參閱此GitHub README 。
Before asking the user to authenticate with TouchID/FaceID, it is wise to check if the user’s iOS device supports such capability by calling getSupportedBiometryType
:
在要求用戶使用TouchID / FaceID進行身份驗證之前,明智的做法是通過調用getSupportedBiometryType
來檢查用戶的iOS設備是否支持這種功能:
After confirming that biometric authentication is supported, you need to save some content in the keychain and set access control flags. The content could be user credentials or some access token. Keychain entry is encrypted and stored in secure storage. To store a value in the keychain, call setGenericPassword
:
確認支持生物特征認證后,您需要在鑰匙串中保存一些內容并設置訪問控制標志。 內容可以是用戶憑據或某些訪問令牌。 鑰匙串條目已加密并存儲在安全存儲中。 要將值存儲在鑰匙串中,請調用setGenericPassword
:
A few points to note here:
這里要注意幾點:
Setting accessControl to any of these
Keychain.ACCESS_CONTROL
enum valuesBIOMETRY_ANY
,BIOMETRY_CURRENT_SET
,BIOMETRY_ANY_OR_DEVICE_PASSCODE
,BIOMETRY_CURRENT_SET_OR_DEVICE_PASSCODE
mandates that the user authenticate with TouchID/FaceID whenever we attempt to retrieve the keychain item.將accessControl設置為這些
Keychain.ACCESS_CONTROL
枚舉值BIOMETRY_ANY
,BIOMETRY_CURRENT_SET
,BIOMETRY_ANY_OR_DEVICE_PASSCODE
,BIOMETRY_CURRENT_SET_OR_DEVICE_PASSCODE
強制要求用戶在每次嘗試檢索鑰匙串項目時使用TouchID / FaceID進行身份驗證。We also set accessible to
Keychain.ACCESSIBLE
enum valueWHEN_PASSCODE_SET_THIS_DEVICE_ONLY
. This is the strictest accessible constraint, which enforces:我們還將
Keychain.ACCESSIBLE
枚舉值WHEN_PASSCODE_SET_THIS_DEVICE_ONLY
設置為可訪問 。 這是最嚴格的可訪問約束,它強制執行:
Your device must be unlocked for the secret to be accessible.
Your device must have a device passcode set.
If you turn off your device passcode, the secret is deleted.
The secret cannot be restored to a different device.
The secret is not included in iCloud backups.
Finally, we trigger the TouchID/FaceID authentication prompt by attempting to access the previously stored keychain value with getGenericPassword
:
最后,我們嘗試通過使用getGenericPassword
訪問先前存儲的鑰匙串值來觸發TouchID / FaceID身份驗證提示:
Since we saved our secret with access control previously, accessing the item requires user to pass biometric authentication. When authentication is successful, the result returns an object, whose username is ‘your-secret-name’, password is ‘your-secret-value’, and service is ‘your-service-name’.
由于我們之前通過訪問控制保存了我們的秘密,因此訪問該項需要用戶通過生物特征認證。 身份驗證成功后,結果將返回一個對象,其用戶名為“您的秘密名稱”, 密碼為“您的秘密值”, 服務為“您的服務名稱”。
After 5 failed attempts of TouchID/FaceID authentication system-wide, biometric authentication is turned off everywhere on the device. The user must lock and unlock the device with a passcode to re-enable TouchID/FaceID. That’s why at line 14 we have to check for supported biometry type and handle the case appropriately, e.g. asking the user to login with their username/password.
在系統范圍內進行5次TouchID / FaceID身份驗證失敗后,生物識別身份驗證在設備上的所有位置均被關閉。 用戶必須使用密碼鎖定和解鎖設備才能重新啟用TouchID / FaceID。 這就是為什么在第14行,我們必須檢查受支持的生物特征類型并適當地處理這種情況,例如,要求用戶使用其用戶名/密碼登錄。
注意事項 (Caveats)
Though biometric authentication with react-native-keychain is suitable for critical applications, there are a few caveats I would like to bring to your attention:
盡管使用react-native-keychain進行生物特征認證適用于關鍵應用,但我還是要提醒您一些注意事項:
There is no passcode fallback. You may receive a requirement to allow the user to authenticate with their device passcode. Looking at the package’s README, you should find Keychain.ACCESS_CONTROL
enum keys DEVICE_PASSCODE
, BIOMETRY_ANY_OR_DEVICE_PASSCODE
, BIOMETRY_CURRENT_SET_OR_DEVICE_PASSCODE
.
沒有密碼回退 。 您可能會收到允許用戶使用其設備密碼進行身份驗證的要求。 查看軟件包的自述文件,您應該找到Keychain.ACCESS_CONTROL
枚舉鍵DEVICE_PASSCODE
, BIOMETRY_ANY_OR_DEVICE_PASSCODE
, BIOMETRY_CURRENT_SET_OR_DEVICE_PASSCODE
。
Unfortunately, setting an access control value when calling setGenericPassword
to any of those three enum keys do not enable an “Enter Password” fallback. The issue has been reported on GitHub, but there has been no response at the time of publishing this article.
不幸的是,在調用setGenericPassword
到這三個枚舉鍵中的任何一個時設置訪問控制值不會啟用“ Enter Password”回退。 該問題已在GitHub上進行了報道 ,但在發布本文時尚未得到任何回應。
You may think of implementing passcode fallback with a different library. Be aware that your system is only as secure as your weakest link. If your passcode fallback implementation executes at the application layer, it is a potential target for a security attack and defeats the purpose of relying on Keychain Services for biometric authentication.
您可能會想到使用其他庫來實現密碼回退。 請注意,您的系統僅與最弱的鏈接一樣安全 。 如果您的密碼后備實現在應用程序層執行,則它可能成為安全攻擊的目標,并且無法實現依靠鑰匙串服務進行生物識別的目的。
Also, authenticating with react-native-keychain on Android devices may not be considered secure as there is no equivalence of Keychain Services in Android.
此外,由于Android中沒有等效的鑰匙串服務,因此在Android設備上使用react-native-keychain進行身份驗證可能并不安全 。
結語 (Wrapping up)
Thank you for reading this far. I hope you’ve found the tutorial useful. One improvement you may want to make is asking the user whether they would like to opt-in for biometric authentication before enabling it in your app. Also, you may add a setting to let the user turn on or off TouchID/FaceID authentication in your app settings page.
感謝您閱讀本文。 我希望您發現本教程對您有所幫助。 您可能要做的一項改進是詢問用戶在應用程序中啟用生物識別身份驗證之前,是否愿意加入。 另外,您可以在應用程序設置頁面中添加一個設置,以允許用戶打開或關閉TouchID / FaceID身份驗證。
參考文獻 (References)
Why local authentication is not secure
為什么本地身份驗證不安全
How Keychain Authentication with Touch ID Works
帶有Touch ID的鑰匙串身份驗證如何工作
翻譯自: https://www.freecodecamp.org/news/how-to-implement-secure-biometric-authentication-on-mobile-devices-4dc518558c5c/
移動認證