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

Некоторые из описанных здесь обновлений объясняются в сессии Google I/O «Безопасный и простой вход: поддержание вовлеченности пользователей »:

Хром 57

В Chrome 57 появилось важное изменение в 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 управления учетными данными? У нас есть руководство по миграции, которому вы можете следовать, чтобы перейти на новую версию.