Последние обновления API управления учетными данными

Некоторые из описанных здесь обновлений описаны в сеансе ввода-вывода Google «Безопасный и простой вход: поддержание активности пользователей» :

Хром 57

В Chrome 57 появилось это важное изменение в Credential Management API .

Учетные данные могут быть переданы из другого субдомена.

Chrome теперь может получить учетные данные, хранящиеся в другом субдомене, с помощью API управления учетными данными . Например, если пароль хранится в login.example.com , сценарий на www.example.com может отобразить его как один из элементов учетной записи в диалоговом окне выбора учетной записи.

Вы должны явно сохранить пароль с помощью navigator.credentials.store() , чтобы, когда пользователь выбирает учетные данные, нажав на диалоговое окно, пароль передавался и копировался в текущий источник.

После сохранения пароль становится доступным в качестве учетных данных в том же источнике www.example.com и далее.

На следующем снимке экрана информация об учетных данных, хранящаяся под login.aliexpress.com , видна m.aliexpress.com и доступна пользователю на выбор:

Средство выбора учетной записи, показывающее данные для входа в выбранный субдомен.

Хром 60

Chrome 60 представляет несколько важных изменений в API управления учетными данными :

Обнаружение функций требует внимания

Чтобы узнать, доступен ли API управления учетными данными для доступа к учетным данным на основе пароля и федеративным учетным данным, проверьте, доступен ли window.PasswordCredential или window.FederatedCredential .

if (window.PasswordCredential || window.FederatedCredential) {
  // The Credential Management API is available
}

Объект PasswordCredential теперь включает пароль.

API управления учетными данными использует консервативный подход к обработке паролей. Он скрывал пароли от JavaScript, требуя от разработчиков отправлять объект PasswordCredential непосредственно на свой сервер для проверки через расширение API fetch() .

Но такой подход ввел ряд ограничений. Мы получили отзывы о том, что разработчики не могут использовать API, потому что:

  • Им пришлось отправить пароль как часть объекта JSON.

  • Им пришлось отправить хэш-значение пароля на свой сервер.

Проведя анализ безопасности и осознав, что сокрытие паролей от JavaScript не предотвратило все направления атак так эффективно, как мы надеялись, мы решили внести изменения.

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() , проверьте, использует ли она объект PasswordCredential или объект FederatedCredential в качестве значения свойства credentials , например:

fetch('/signin', {
    method: 'POST',
    credentials: c
})

Рекомендуется использовать обычную функцию fetch() как показано в предыдущем примере кода, или XMLHttpRequest .

До версии 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()

Для лучшего соответствия новому свойству mediation , предлагаемому в вызове get() , метод 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://*****'
    }
});

Руководство по миграции

У вас уже есть реализация API управления учетными данными? У нас есть руководство по миграции, которому вы можете следовать, чтобы перейти на новую версию.