ここで説明する更新の一部は、Google I/O セッション「安全でシームレスなログイン: ユーザーのエンゲージメントを維持する」で説明されています。
Chrome 57
Chrome 57 では、認証情報管理 API にこの重要な変更が導入されました。
認証情報を別のサブドメインから共有できる
Chrome は、Credential Management API を使用して、別のサブドメインに保存されている認証情報を取得できるようになりました。たとえば、パスワードが login.example.com
に保存されている場合、www.example.com
のスクリプトによって、アカウント選択ツールのダイアログでアカウント アイテムの 1 つとして表示できます。
ユーザーがダイアログをタップして認証情報を選択すると、パスワードが渡され、現在のオリジンにコピーされるように、navigator.credentials.store()
を使用してパスワードを明示的に保存する必要があります。
保存されたパスワードは、まったく同じオリジン www.example.com
以降で認証情報として使用できます。
次のスクリーンショットでは、login.aliexpress.com
に保存されている認証情報は m.aliexpress.com
に表示され、ユーザーが選択できます。
Chrome 60
Chrome 60 では、認証情報管理 API にいくつかの重要な変更が導入されています。
パスワードの取得にカスタム
fetch()
関数が必要なくなったため、この関数はまもなく非推奨になります。navigator.credentials.get()
が、ブール値フラグunmediated
ではなく列挙型mediation
を受け入れるようになりました。新しいメソッド
navigator.credentials.create()
は、認証情報オブジェクトを非同期で作成します。
機能検出に注意が必要
パスワードベースの認証情報と連携認証情報にアクセスするための Credential Management API が使用可能かどうかを確認するには、window.PasswordCredential
または window.FederatedCredential
が使用可能かどうかを確認します。
if (window.PasswordCredential || window.FederatedCredential) {
// The Credential Management API is available
}
PasswordCredential
オブジェクトにパスワードが含まれるようになりました
認証情報マネージメント API は、パスワードの処理に保守的なアプローチを採用していました。JavaScript からパスワードを隠蔽するため、デベロッパーは fetch()
API の拡張機能を使用して、PasswordCredential
オブジェクトをサーバーに直接送信して検証する必要がありました。
ただし、このアプローチにはいくつかの制限がありました。デベロッパーから、次のような理由で API を使用できないというフィードバックが寄せられました。
パスワードを JSON オブジェクトの一部として送信する必要がありました。
パスワードのハッシュ値をサーバーに送信する必要がありました。
セキュリティ分析を実施した結果、JavaScript からパスワードを隠しても、期待したほど効果的にすべての攻撃ベクトルを防ぐことができなかったため、変更を決定しました。
Credential Management API では、返された認証情報オブジェクトに未加工のパスワードが含まれるようになりました。これにより、プレーンテキストとしてパスワードにアクセスできるようになりました。既存の方法を使用して、認証情報の情報をサーバーに提供できます。
navigator.credentials.get({
password: true,
federated: {
providers: [ 'https://accounts.google.com' ]
},
mediation: 'silent'
}).then(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()
関数を使用しているかどうかを確認するには、credentials
プロパティの値として PasswordCredential
オブジェクトと FederatedCredential
オブジェクトのどちらが使用されているかを確認します。次に例を示します。
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'
}).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: 'https://*****'
}
});
移行ガイド
Credential Management API の既存の実装はありますか?新しいバージョンにアップグレードする際は、移行ガイドのドキュメントを参照してください。