開發人員關係工程師
隨著業界逐漸淘汰密碼和實體錢包,若要提供現代化的使用者歷程,就必須兼顧流暢的驗證流程和可靠的身分驗證機制。雖然密碼金鑰可讓使用者輕觸一下就安全登入,但更換裝置仍是使用者參與度大幅下降的主因之一。瞭解如何使用 Restore Credentials API 減少遷移阻礙,符合 Google Play 免輕觸登入新標準。
本課程將探討如何透過 Android Credential Manager 的單一整合,整合密碼金鑰、無聲裝置還原和數位憑證,讓您直接從裝置驗證身分屬性,並建立輕鬆、安全的註冊流程。
轉錄稿
大家好。
感謝各位撥冗參加,
今天,我們很高興能與大家分享驗證和數位身分的未來發展。
我是 Tom Colvin。
我是 Apptaura 的技術長,也是 Android 的 Google 開發人員專家。今天與我一起主持的是 Chiping Yeh,他是 Google 的資深 Android 開發人員關係工程師。
傳統密碼已過時。
至少應該是這樣。
今天我要介紹無密碼的世界。
密碼是安全基礎架構中眾所周知的漏洞。
即使安全地儲存,仍可能受到網路釣魚、伺服器入侵和憑證填充等自動化攻擊。
業界曾試圖透過強制提高複雜度來解決這個問題,例如要求使用特殊字元、數字和強制輪替。
證據顯示,這種做法並未奏效,部分原因在於,密碼越難記,反而越容易促使使用者採取不安全的行為。
因為如果密碼複雜又經常變更,使用者很可能會寫在便利貼上。
即使是簡訊雙重驗證,也容易遭到攔截,例如 SIM 卡盜換。
不過,這個問題現在已大致解決。
密碼金鑰是以 FIDO 標準為基礎,並採用公開/私密金鑰密碼編譯技術。
密碼金鑰具有高度抗網路釣魚能力,不會在伺服器遭到入侵時外洩,而且會透過螢幕鎖定直接與使用者的手機安全性連結,在大多數情況下,螢幕鎖定會以生物辨識、指紋等為基礎。此外,密碼金鑰還能提供跨平台統一體驗,使用者也不必記住複雜的密碼,因此能有效提升使用者體驗。
我們今天的宣言很簡單。
現在就邁向無密碼時代。
而我們已經擁有實現這個目標的工具。
Jetpack Credential Manager 是 Android 實現這項躍進的核心。
這項功能支援 Android 4.4 以上版本,密碼金鑰則支援 Android 9 以上版本。Credential Manager 提供單一整合式 API,可支援密碼金鑰和傳統驗證方式,例如聯合登入 (像是使用 Google 帳戶登入),並在必要時提供流暢的密碼備用機制。
您呼叫 Credential Manager API,該 API 會處理 UI,選取使用者想看到的驗證方式。
接著,系統會執行繁重的工作,安全地取得並傳回正確的憑證。
支援登入、註冊和備份憑證。
您也可以使用這個 API 更新及刪除憑證。
此外,使用者只要點按幾下,就能在憑證提供者之間轉移密碼和密碼金鑰,不必下載檔案。
這項服務旨在讓使用者完全掌控自己的資料,並能隨時自由切換供應商。
Credential Manager 支援多種板型規格,包括手錶、電視、XR、汽車、手機、摺疊式裝置、平板電腦。
最重要的是,它有專屬的密碼金鑰流程。
以下是使用者在註冊時看到的畫面。
我的應用程式會告知 Credential Manager 可使用密碼金鑰驗證,並提供從後端收集的詳細資料。
輕觸「註冊」後,Credential Manager 會顯示底部功能表,並提示您設定螢幕鎖定。
通常是透過指紋或臉孔掃描等生物辨識技術解鎖。
Credential Manager 則會處理複雜的密碼編譯工作,例如實際建立密碼金鑰。
並將密碼金鑰儲存到我的 Credential Manager,在本例中是 Google 密碼管理工具,但也可以是其他工具。
程式碼如下所示。
val createPublicKeyCredentialRequest = CreatePublicKeyCredentialRequest(
requestJson = registerRequestJson
)
val createCredentialResponse = credentialManager.createCredential (
context = localActivity,
request = createPublicKeyCredentialRequest
)首先,我們使用後端提供的詳細資料 (即 registerRequestJson) 建立這個 createPublicKeyCredentialRequest 物件。
接著,我們呼叫魔術方法 credentialManager.createCredential。
我們傳入該要求和當地特色,以便顯示 UI。
順帶一提,我完全不需要在這裡編寫任何 UI 程式碼。
Credential Manager 會完全代為處理。
現在,這是登入程序。
對使用者來說,這與註冊程序非常相似。
只要解鎖一次,就能完成付款。
對開發人員來說,兩者只有些微差異。
val getPublicKeyCredentialOption = GetPublicKeyCredentialOption(
requestJson = authenticationRequestJson
)
val signInRequest =
GetCredentialRequest(listOf(getPublicKeyCredentialOption))
val result = credentialManager.getCredential (
context = localActivity,
request = signInRequest
)首先,我們會從後端取得登入詳細資料,建構 GetPublicKeyCredential 執行個體。
我們會告知 Credential Manager 支援的憑證類型。
這裡只有密碼金鑰。
但我們也可以視需要新增其他類型的憑證。
接著,我們呼叫 credentialManager.getCredential,傳入剛才要求的憑證清單。
同樣地,不含 UI 程式碼。
完全不必編寫任何 UI 程式碼。
Credential Manager 會為我們處理這項作業。
這項功能會引導使用者選擇最常用的選項,同時保留其他選項做為備用。
這能自動解決現今最惱人的驗證問題之一。
您有注意到嗎?
也就是記住我上次登入時使用的方法。
看,答案就整齊地呈現在底部功能表中。
順帶一提,這不只是讓使用者感到困擾。
這確實是個阻礙。
這會導致不必要的帳戶救援,並造成商業影響,例如購物車遭棄置。
以下是我的示範應用程式程式碼,您可以使用它來親自試用 Credential Manager。
您可以在自己的裝置上查看這些流程。
左側是官方的 Google 程式碼範例。
用於處理密碼金鑰建立作業。
如何將現有密碼使用者升級為密碼金鑰?
這時,條件式建立功能就能派上用場。
如果使用者剛使用密碼登入,且密碼是由支援的憑證提供者自動填入,我們就知道他們正在積極參與,且我們已重新驗證他們的身分。
在這種情況下,條件式建立功能可讓我們在背景自動要求建立密碼金鑰。
不會中斷使用者的工作流程。
密碼金鑰會自動產生並儲存。
Google 密碼管理工具會顯示通知,確認密碼金鑰已建立完成。
其他密碼管理工具可能會有不同做法。
條件式建立的程式碼與註冊的程式碼非常相似。
val createPublicKeyCredentialRequest = CreatePublicKeyCredentialRequest(
requestJson = registerRequestJson,
preferImmediatelyAvailableCredentials = false,
isConditional = true
)
val createCredentialResponse = credentialManager.createCredential (
context = localActivity,
request = createPublicKeyCredentialRequest
)神奇的旗標是 isConditional true,可確保使用者不會看到該 UI。
由於這項功能會視情況運作,因此我們會將其放入 try-catch。
我們會默默處理任何錯誤,因此如果程序失敗,我們不會打擾使用者。
接著,密碼金鑰會儲存到使用者的 Credential Manager,下次就能使用。
Credential Manager 也允許憑證提供者安全地匯入及匯出憑證。
只要按幾下滑鼠即可完成。
無須下載任何內容。
這讓您能更靈活地建立資料架構,同時確保資訊安全。
流程如下所示。
使用者在新的憑證提供者中,要求匯入憑證。
接著,Credential Manager 會處理匯入 UI,讓使用者選取憑證資料來源。
匯出憑證提供者可以提供自己的 UI,讓使用者瞭解相關資訊並提供相關警告。
最後,使用者的全新憑證提供者會透過安全管道取得資料。
因此,不需使用者互動即可匯入。
不過,如果使用者從應用程式或網站撤銷密碼金鑰,會發生什麼情況?
憑證提供者不一定會知道這項操作。
下次嘗試登入時,Credential Manager 會提供該無效密碼金鑰,導致登入失敗。
同樣地,當使用者更新使用者名稱或顯示名稱時,也需要進行同步處理。
現在,應用程式可以透過 Signal API,向憑證提供者標記這些特定狀態。
以使用已撤銷的密碼登入為例。
應用程式可以擷取該特定錯誤狀態,並用來通知使用者的憑證提供者。
憑證提供者可以自行更新,不再提供該密碼金鑰。
以上是 Credential Manager 的部分功能,這項工具非常實用,可引導使用者透過密碼金鑰註冊,並在登入時優先使用密碼金鑰。
但請記住,我們的最終目標是完全不使用密碼。
Credential Manager 如何協助達成這個目標?
以下是我們建議的五個步驟。
在前兩個步驟中,您將引導密碼使用者改用密碼金鑰。
首先,我們會使用條件式建立功能,嘗試伺機建立。
如果沒有這類機會,我們最終需要使用者介入,因此會在應用程式內邀請使用者設定密碼金鑰。
我們就能逐漸提高這些內容的曝光度。
畢竟從使用者的角度來看,他們通常只需要提供螢幕鎖定,例如生物辨識。
如果數據分析顯示絕大多數使用者都使用密碼金鑰,則可強制所有新使用者使用密碼金鑰。
但那些舊使用者,這就是我們在最後三個步驟中處理的對象。
建議密碼金鑰使用者移除密碼。
因此在步驟 3 中,我們允許使用者手動刪除密碼,並在帳戶設定中提供非常明確的「刪除密碼」選項。
在步驟 4 中,我們開始推動密碼刪除,例如使用應用程式內通知,並搭配教育文案。
最後,您將密碼刪除功能從選擇加入改為選擇不採用。
最後,連這項選擇不採用的功能也可能消失。
分析結果將讓我們有信心從應用程式中完全移除密碼流程。
因此,邁向無密碼世界不再是未來某個時間點的理論性安全概念。
這項功能獲得高度支援。
API 功能強大,使用者體驗極佳。
建議您立即開始使用 Credential Manager 整合密碼金鑰流程。
開始為使用者升級,徹底告別密碼。
感謝您!
接下來,我將交棒給 Chiping,由他介紹裝置遷移和身分識別的最新發展。
酷!
好的,謝謝你,Tom。
正如 Tom 所說,在使用者裝置上順暢驗證身分至關重要。
不過,如果使用者換新手機,會發生什麼事?
目前,使用者歷程中最大的流失點通常發生在切換裝置時。
今天,我想先談談我們如何解決這個問題,並快速介紹 Play 商店即將推出的憑證還原規定。
自 2027 年 4 月起,Google Play 將要求應用程式符合免輕觸登入規定,才能保有完整發布權限,並在 Play 商店中獲得最佳曝光度。
什麼是免輕觸登入?
也就是說,使用者改用新裝置時,不必在應用程式中手動重新驗證。
如何實作?
建議您透過 Credential Manager 使用 Android 的 Restore Credentials API。
這個 API 可產生還原金鑰,並根據使用者的備份設定,將金鑰儲存在使用者裝置或雲端。
建議您在使用者登入後,於背景產生這組金鑰。
這張圖表說明使用者登入應用程式的流程。
接著,系統會在使用者使用應用程式時建立還原金鑰。
接著,這組金鑰會儲存在本機,或儲存在雲端 (如已啟用)。
使用者設定新裝置時,還原憑證會在裝置設定過程中,於背景自動轉移。
使用者可以選擇從雲端還原資料,或透過裝置對裝置傳輸功能轉移資料。
接著,當應用程式開啟時,您可以呼叫 Credential Manager API,使用這個還原金鑰在新裝置上首次啟動時登入使用者。
這樣一來,使用者就能快速安全地登入應用程式。
如果想在設定完成後立即還原應用程式,而不開啟應用程式,可以實作自訂備份代理程式。
這樣一來,使用者不必手動開啟應用程式,就能登入。
部分合作夥伴已在應用程式中導入這項功能。
Uber 是全球最大的多元計程車公司,為數百萬人提供交通服務,同時也支援餐點外送、醫療運輸和貨運物流。
存取簡便性至關重要。
使用者改用新裝置時,希望轉移過程順暢,不必每次都重新登入 Uber 應用程式,或透過簡訊進行一次性驗證。
這種頻繁更換裝置的現象,對使用者留存率造成挑戰。
在評估使用者需求和程式碼原型設計後,Uber 在 Uber Rider 應用程式中導入 Restore Credentials 支援,並取得非常正面的成果。
他們預估,這項功能每天可省下 400 萬次平均每日登入次數,且隨著採用率提高,這個數字還會增加。
請掃描 QR code 或點選連結,進一步瞭解這項即將實施的政策,以及如何讓應用程式符合免輕觸還原規定。
這項異動將於 2027 年 4 月生效,請務必在日曆上標註日期。
如果想搶先在應用程式中導入 Restore Credentials,請掃描這個 QR code 或點選連結,瞭解 Restore Credentials 技能。
這項技能可協助您快速開發或測試所選代理的功能。
接著,我們來看看數位身分驗證的下一個里程碑:透過 Credential Manager 使用 Digital Credentials API。
接下來,我們將介紹數位憑證及其運作方式。
數位憑證是可透過加密編譯驗證的數位文件,使用者可用來提供個人資訊。
這些文件會儲存在使用者裝置的數位儲存空間中,裝置上的其他應用程式可以要求存取,也可以透過混合方式 (例如 QR code) 向外界出示。
用途廣泛,從驗證身分、存取服務到線上購物,不一而足。
數位憑證提供安全便利的方式,讓您不必使用實體卡片,就能分享資訊。
數位憑證涉及三方:核發者、持有者和驗證者。
數位憑證的生命週期通常由左至右。
接著來逐一介紹這些實體和其作用。
首先是核發者,顧名思義,就是核發憑證的一方,就像政府核發護照一樣。
不過,在數位世界中,為了防止假冒,這些憑證也會由核發者使用其數位憑證進行簽署,因此任何收到憑證的人都能確切知道憑證的來源。
事實上,任何人都可以是發卡機構,無論是健身房、飯店,甚至是您自己。
只要建立憑證並簽署即可。
好,發行者建立並核發憑證後,需要儲存在某個地方,就像您需要將政府核發的身分證件存放在自己的錢包中一樣。
這是下一個參與方,稱為持有者,通常也稱為數位錢包。
顧名思義,持有者主要持有核發者核發的憑證。
這些憑證會以應用程式的形式儲存在裝置上,並可向要求方出示。
與發行者類似,任何人都可以是持有者。
事實上,發卡機構和持卡人由同一實體管理的情況並不少見。
舉例來說,健身房可能想建立自己的數位會員憑證,並透過自家應用程式管理。
這會同時是發卡機構和持卡人。
第三個角色是驗證者,也就是要求提供數位憑證的一方。
驗證者通常會提出憑證要求,檢查使用者的屬性,例如年齡規定或姓氏等。
這些商家或應用程式需要額外的使用者資料才能提供服務,例如購買酒精飲料或驗證最低年齡。
在 Android 上,這三方與使用者之間的互動,是透過 Credential Manager 搭配 Digital Credentials API 協調。
核發者可以呼叫 API,向持有者核發憑證,但如果兩者是同一個實體,則不需要這麼做。
憑證核發後,驗證者可以呼叫 API 要求憑證。
Credential Manager 會比對要求與所有可用的持有者,並向使用者顯示,以便選取憑證並提供同意聲明。
選取持有者後,系統會叫用該持有者,並在最終與驗證者共用憑證前,視需要執行額外檢查。
驗證者收到憑證後,也可以對憑證的合法性執行各種檢查,包括檢查原始核發者。
您可能會想知道,數位憑證究竟如何確保安全?
其實,這個程序的每個步驟都內建安全性機制,我們現在就來介紹其中幾項。
因此,在核發者端,當核發者想與持有者分享憑證時,必須驗證持有者無法遭到竄改或複製,基本上就是可以信任。
該如何驗證?
核發者在核發憑證前,必須先要求持有者證明自己的身分,以及所用裝置的安全性。
持有者會傳送錢包認證,通常是可驗證的憑證鏈。
持有者也會產生與硬體繫結的金鑰組。
它會將這個金鑰組的公開金鑰傳送給發卡機構,並附上 Android 金鑰認證,讓發卡機構驗證硬體合法性。
核發機構會將這個公開金鑰簽署到核發的憑證中,因此憑證會正式繫結至單一裝置。
在持有者端,持有者取得新憑證後,只會向 Credential Manager 註冊憑證中繼資料。
Credential Manager 會使用這項中繼資料,判斷驗證者提出憑證要求時,要顯示哪些持有者。
Credential Manager 不會註冊任何真實使用者資料,也不會向 Google 揭露這類資料。
即使 Credential Manager 正在選取要向使用者顯示的錢包,也不會在此時顯示各錢包的內容。
現在,當系統提出憑證要求,且使用者同意分享憑證時,系統會叫用所選持有者,並將工作流程控制權交給持有者。
您可能還記得,持有者只是一個應用程式,因此系統會叫用該應用程式。
此時,持有者可以查看要求驗證者和要求的憑證等資訊,並決定是否要與該驗證者共用該憑證,即使使用者已授予權限也一樣。
Google 無法存取憑證資料本身。
系統只會註冊轉送中繼資料,酬載則會在持有者和驗證者之間進行端對端加密。
因此,持有者可以控管要與哪些對象分享憑證。
最後,在驗證者端,要求憑證且持有者分享憑證後,驗證者會收到持有者提供的憑證。
現在,驗證者可以檢查回應是否由原始憑證持有者針對要求新生成。
確認憑證回應是以持有者的裝置繫結金鑰簽署,包括要求一次性權杖,以及呼叫持有者觀察到的來源。
驗證者也可以驗證核發者憑證,確認憑證來自可信任的來源,藉此檢查憑證核發者的真實性。
簡而言之,發卡機構可獲得硬體保證,持卡人可控管要分享的憑證,驗證者可取得發卡機構和持卡人的密碼編譯證明,使用者則可完全同意要分享的資料。
瞭解數位憑證的安全機制後,接著來看看目前在 Android 上,可透過 Digital Credentials API 實現的數位憑證用途。
首先要介紹的是電子郵件驗證。
這個 API 會直接從使用者的裝置擷取登入的 Gmail 帳戶,並以 Google 驗證的數位憑證形式提供給應用程式,因此不必傳送動態密碼或魔術連結。
也就是說,使用者不必離開應用程式,只要輕觸熟悉的 Credential Manager 底部功能表,即可提供同意聲明。
以下是 API 實際運作的示範錄影。
這個範例應用程式透過 Digital Credentials API 實作電子郵件驗證。
輕觸「要求提供已驗證的電子郵件」後,Credential Manager 會向裝置上持有這類憑證的使用者,要求提供已驗證的電子郵件數位憑證。
在這種情況下,只有 Google 持有這項已驗證的電子郵件憑證,如底部功能表所示。
這是使用者在裝置上登入的其中一個電子郵件地址。
事實上,Google 在這個案例中同時是數位憑證的核發者和持有者。
選取要分享的憑證後,系統會將憑證傳回應用程式,目前只會顯示憑證中的欄位,也就是已驗證的電子郵件。
在應用程式中,您可以使用這項資訊前往下一個應用程式畫面,例如建立密碼金鑰或其他帳戶建立步驟。
對使用者來說,只要提供同意聲明,然後前往下一個畫面,就是這麼簡單。
如要試用,請前往 GitHub 範例,並在自己的裝置上安裝。
請嘗試在實體裝置上使用,並注意您必須在裝置上登入至少一個 Gmail 帳戶。
如果大家有興趣,我會多留一點時間。
現在我們來做個小測驗
聽起來很棒,對吧?
除了電子郵件驗證,您還會想到哪種使用者驗證方式?
沒錯,就是電話號碼驗證。
Digital Credentials API 也原生支援電話號碼驗證,可消除簡訊動態密碼的阻礙和安全漏洞。
電話號碼驗證作業也是透過 Digital Credentials API 運作,在這種情況下,系統會要求提供裝置上的電話號碼,並以數位憑證的形式呈現。
使用者只會看到熟悉的 Credential Manager 底部功能表,用於分享或驗證電話號碼,全程不需離開應用程式,只要輕觸幾下即可完成驗證。
以下範例應用程式中,顧客只要輕觸一下,就能分享電話號碼,完全不必離開應用程式。
那麼,這項設定如何運作?
如果將這個概念對應到數位憑證參與方,核發方就是裝置 SIM 卡上電話號碼的電信業者,持有方則是 Android Telephony。
當驗證者 (例如您的應用程式) 要求使用者的電話號碼時,系統會透過 Digital Credentials API 呼叫,從 Google Telephony 擷取該號碼。
您可能想知道計費方式。
這個流程有一個獨特的額外步驟,就是將憑證傳送給電信業者或匯總工具,以便進行帳單結算。
系統會從 Google Telephony 擷取電話號碼,然後執行這項作業。電話號碼在 Google Telephony 中是以加密狀態儲存。
接著,這項資訊會傳遞給電信業者,由電信業者解密並直接將電話號碼傳回應用程式後端,並向您收取費用。
這種做法的好處是,電信業者只會針對成功的驗證收費,而且驗證是透過行動數據或 Wi-Fi 傳輸,比簡訊更可靠。
以下示範如何使用 Firebase 做為電信業者匯總工具,驗證電話號碼。
應用程式在登入程序中要求使用者提供電話號碼。
這位使用者有多張 SIM 卡,並選擇其中一張與應用程式共用。
使用者確認選擇後,系統就會在背景完成交換。
接著,您只會看到下一個畫面,其中填入了擷取的電話號碼。
使用者不必離開應用程式,只要選取並確認要分享的電話號碼,就能順利完成流程,全程只需輕觸幾下。
請等待作業完成,以便再次查看完成狀態。
因此,您會在最後一個畫面上看到電話號碼。
就是這麼簡單
我們今天探討了許多內容。
我們首先探討如何使用 Credential Manager 改善密碼金鑰實作,並邁向無密碼世界。
請參閱 Credential Manager 和密碼金鑰的相關資源,進一步瞭解並取得範例應用程式。
接著,我們介紹了即將推出的免輕觸登入規定,讓使用者在設定新裝置時,能順暢登入應用程式。
Play 商店將於 2027 年 4 月強制實施這項規定,請務必留意。
最後,我們介紹了數位憑證的運作方式,以及 Android 上一些最實用的功能。
如要深入瞭解數位憑證,並取得範例,請參閱此處的資源。
今天分享的所有內容都已上線,歡迎立即使用。
Android 上的身分驗證技術未來可期,而且比以往更令人期待。
感謝各位撥冗參加,現在是午餐時間,請享用外面的餐點。
如果對密碼金鑰或數位憑證有任何疑問,歡迎隨時向我和 Tom 提問。
祝一切順心!
val createPublicKeyCredentialRequest = CreatePublicKeyCredentialRequest(
requestJson = registerRequestJson
)
val createCredentialResponse = credentialManager.createCredential (
context = localActivity,
request = createPublicKeyCredentialRequest
)val getPublicKeyCredentialOption = GetPublicKeyCredentialOption(
requestJson = authenticationRequestJson
)
val signInRequest =
GetCredentialRequest(listOf(getPublicKeyCredentialOption))
val result = credentialManager.getCredential (
context = localActivity,
request = signInRequest
)val createPublicKeyCredentialRequest = CreatePublicKeyCredentialRequest(
requestJson = registerRequestJson,
preferImmediatelyAvailableCredentials = false,
isConditional = true
)
val createCredentialResponse = credentialManager.createCredential (
context = localActivity,
request = createPublicKeyCredentialRequest
)