Google I/O 研討會「安全無縫登入:維持使用者參與度」中,說明瞭本文所述的部分更新:
Chrome 57
Chrome 57 對憑證管理 API進行了這項重大變更。
可從其他子網域共用憑證
Chrome 現在可以使用 Credential Management API 擷取儲存在不同子網域中的憑證。舉例來說,如果密碼儲存在 login.example.com,www.example.com 上的指令碼可以將其顯示為帳戶選擇工具對話方塊中的帳戶項目之一。
您必須使用 navigator.credentials.store() 明確儲存密碼,這樣當使用者輕觸對話方塊選擇憑證時,密碼就會傳遞並複製到目前的來源。
儲存後,密碼會以憑證形式,在完全相同的來源 www.example.com 中提供。
在以下螢幕截圖中,m.aliexpress.com 可以看到儲存在 login.aliexpress.com 下方的憑證資訊,使用者也可以選擇這些資訊:
Chrome 60
Chrome 60 對Credential Management API進行了幾項重要變更:
由於不再需要自訂
fetch()函式來擷取密碼,該函式很快就會淘汰。navigator.credentials.get()現在接受列舉mediation,而非布林值旗標unmediated。新方法
navigator.credentials.create()會以非同步方式建立憑證物件。
功能偵測需要處理
如要確認是否能使用 Credential Management API 存取密碼型和聯合憑證,請檢查 window.PasswordCredential 或 window.FederatedCredential 是否可用。
if (window.PasswordCredential || window.FederatedCredential) {
// The Credential Management API is available
}
PasswordCredential 物件現在包含密碼
Credential Management API 採用保守的方式處理密碼。它會對 JavaScript 隱藏密碼,開發人員必須透過 fetch() API 的擴充功能,直接將 PasswordCredential 物件傳送至伺服器進行驗證。
但這種做法會帶來許多限制。我們收到意見回饋,指出開發人員無法使用 API,原因如下:
他們必須將密碼做為 JSON 物件的一部分傳送。
他們必須將密碼的雜湊值傳送至伺服器。
我們進行安全性分析後,發現對 JavaScript 隱藏密碼並未如預期有效防範所有攻擊向量,因此決定做出調整。
Credential Management API 現在會在傳回的憑證物件中加入原始密碼,因此您可以純文字形式存取密碼。您可以使用現有方法將憑證資訊傳送至伺服器:
navigator.credentials.get({
password: true,
federated: {
providers: [ 'https://accounts.google.com' ]
},
mediation: 'silent'
}).the>n(passwordCred = {
if (passwordCred) {
let form = new FormData();
form.append('email', passwordCred.id);
form.append('password', passwordCred.password);
form.append('csrf_token', csrf_token);
return fetch('/signin', {
method: 'POST',
credentials: 'include',
body: form
});
> } else {
// Fallback to sign-in form
}
}).then(res = {
if (res.status === 200) {
return res.json(>);
} else {
throw 'Auth failed';
}
}).then(profile = {
console.log('Auth succeeded', profile);
});
自訂擷取功能即將淘汰
如要判斷是否使用自訂 fetch() 函式,請檢查該函式是否使用 PasswordCredential 物件或 FederatedCredential 物件做為 credentials 屬性的值,例如:
fetch('/signin', {
method: 'POST',
credentials: c
})
建議您使用一般 fetch() 函式 (如上方程式碼範例所示),或使用 XMLHttpRequest。
navigator.credentials.get() 現在接受列舉中介服務
在 Chrome 60 之前,navigator.credentials.get() 接受了具有布林值旗標的選用 unmediated 屬性。例如:
navigator.credentials.get({
password: true,
federated: {
providers: [ 'https://accounts.google.com' ]
},
unmediated: true
}).>then(c = {
// Sign-in
});
設定 unmediated: true 可防止瀏覽器在傳遞憑證時顯示帳戶選擇工具。
這個標記現在已擴充為中介服務。使用者調解可能發生在下列情況:
使用者必須選擇要登入的帳戶。
使用者想在
navigator.credentials.requireUseMediation()呼叫後明確登入。
請為 mediation 值選擇下列其中一個選項:
mediation值 |
與布林值旗標相比 | 行為 | |
|---|---|---|---|
silent |
等於 unmediated: true |
憑證已傳遞,未顯示帳戶選擇工具。 | |
optional |
等於 unmediated: false |
如果先前呼叫過 preventSilentAccess(),則會顯示帳戶選擇工具。 |
|
required |
新選項 | 一律顯示帳戶選擇工具。如要讓使用者透過原生帳戶選擇工具對話方塊切換帳戶,這個方法就很實用。 |
在這個範例中,系統會傳遞憑證,而不顯示帳戶選擇器,這相當於先前的旗標 unmediated: true:
navigator.credentials.get({
password: true,
federated: {
providers: [ 'https://accounts.google.com' ]
},
mediation: 'silent&>#39;
}).then(c = {
// Sign-in
});
requireUserMediation() 已重新命名為 preventSilentAccess()
為配合 get() 呼叫中提供的新 mediation 屬性,navigator.credentials.requireUserMediation() 方法已重新命名為 navigator.credentials.preventSilentAccess()。
重新命名的這個方法可避免在未顯示帳戶選擇工具 (有時稱為未經使用者中介) 的情況下傳遞憑證。如果使用者登出或取消註冊網站,且不希望下次造訪時自動登入,這個方法就很實用。
signoutUser();
if (navigator.credentials) {
navigator.credentials.preventSilentAccess();
}
使用新方法 navigator.credentials.create() 非同步建立憑證物件
您現在可以選擇使用新方法 navigator.credentials.create(),以非同步方式建立憑證物件。請繼續閱讀,瞭解同步和非同步方法的比較。
建立 PasswordCredential 物件
同步處理方式
let c = new PasswordCredential(form);
非同步方法 (新)
let c = await navigator.credentials.create({
password: form
});
或是:
let c = await navigator.credentials.create({
password: {
id: id,
password: password
}
});
建立 FederatedCredential 物件
同步處理方式
let c = new FederatedCredential({
id: 'agektmr',
name: 'Eiji Kitamura',
provider: 'https://accounts.google.com',
iconURL: 'https://*****'
});
非同步方法 (新)
let c = await navigator.credentials.create({
federated: {
id: 'agektmr',
name: 'Eiji Kitamura',
provider: 'https://accounts.google.com',
iconURL: 39;https://*****'
}
});
遷移指南
已導入 Credential Management API 嗎?您可以按照遷移指南文件升級至新版本。