Najnowsze aktualizacje interfejsu API do zarządzania danymi logowania

Niektóre z opisanych tu aktualizacji zostały wyjaśnione podczas sesji Google I/O Bezpieczne i płynne logowanie: utrzymywanie zaangażowania użytkowników:

Chrome 57

W Chrome 57 wprowadziliśmy tę ważną zmianę w interfejsie Credential Management API.

Dane logowania można udostępniać z innej subdomeny

Chrome może teraz pobierać dane logowania przechowywane w innej subdomenie za pomocą interfejsu Credential Management API. Jeśli na przykład hasło jest przechowywane w login.example.com, skrypt w www.example.com może wyświetlić je jako jeden z elementów konta w oknie wyboru konta.

Musisz jawnie zapisać hasło za pomocą navigator.credentials.store(), aby po wybraniu przez użytkownika danych logowania przez kliknięcie okna hasło zostało przekazane i skopiowane do bieżącego źródła.

Po zapisaniu hasło jest dostępne jako dane logowania w tym samym miejscu pochodzenia (www.example.com).

Na zrzucie ekranu poniżej dane logowania przechowywane w login.aliexpress.com są widoczne dla m.aliexpress.com i dostępne dla użytkownika:

Selektor konta z danymi logowania do wybranej subdomeny

Chrome 60

Chrome 60 wprowadza kilka ważnych zmian w interfejsie Credential Management API:

Wykrywanie funkcji wymaga uwagi

Aby sprawdzić, czy interfejs Credential Management API umożliwiający dostęp do danych logowania opartych na hasłach i danych logowania sfederowanych jest dostępny, sprawdź, czy dostępny jest window.PasswordCredential lub window.FederatedCredential.

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

Obiekt PasswordCredential zawiera teraz hasło

Interfejs Credential Management API stosował konserwatywne podejście do obsługi haseł. Ukrywało hasła przed JavaScriptem, wymagając od deweloperów wysyłania obiektu PasswordCredential bezpośrednio na serwer w celu weryfikacji za pomocą rozszerzenia interfejsu API fetch().

Takie podejście wiązało się jednak z pewnymi ograniczeniami. Otrzymaliśmy opinie, że deweloperzy nie mogli korzystać z interfejsu API, ponieważ:

  • Musieli wysłać hasło jako część obiektu JSON.

  • Musieli wysłać wartość skrótu hasła na swój serwer.

Po przeprowadzeniu analizy bezpieczeństwa i stwierdzeniu, że ukrywanie haseł przed JavaScriptem nie zapobiega wszystkim wektorom ataku tak skutecznie, jak się spodziewaliśmy, postanowiliśmy wprowadzić zmianę.

Interfejs Credential Management API zawiera teraz nieprzetworzone hasło w zwracanym obiekcie danych logowania, dzięki czemu masz do niego dostęp w formie zwykłego tekstu. Możesz użyć dotychczasowych metod, aby dostarczyć informacje o danych logowania na serwer:

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);
});

Pobieranie niestandardowe zostanie wkrótce wycofane

Aby sprawdzić, czy używasz niestandardowej funkcji fetch(), sprawdź, czy używa ona obiektu PasswordCredential lub FederatedCredential jako wartości właściwości credentials, na przykład:

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

Zalecamy użycie zwykłej funkcji fetch(), jak pokazano w poprzednim przykładzie kodu, lub funkcji XMLHttpRequest.

Do wersji Chrome 60 navigator.credentials.get() akceptował opcjonalną właściwość unmediated z flagą logiczną. Na przykład:

navigator.credentials.get({
    password: true,
    federated: {
    providers: [ 'https://accounts.google.com' ]
    },
    unmediated: true
}).>then(c = {

    // Sign-in
});

Ustawienie unmediated: true uniemożliwia przeglądarce wyświetlanie selektora konta podczas przekazywania danych logowania.

Flaga została rozszerzona jako zapośredniczenie. Zapośredniczenie użytkownika może nastąpić, gdy:

  • Użytkownik musi wybrać konto, na które chce się zalogować.

  • Użytkownik chce się zalogować po wywołaniu navigator.credentials.requireUseMediation().

Wybierz jedną z tych opcji dla wartości mediation:

Wartość mediation W porównaniu z flagą logiczną Zachowanie
silent Równe unmediated: true Dane logowania zostały przekazane bez wyświetlania Account Chooser.
optional Równe unmediated: false Wyświetla selektor konta, jeśli wcześniej wywołano funkcję preventSilentAccess().
required Nowa opcja Zawsze pokazuj wybór konta. Przydatne, gdy chcesz umożliwić użytkownikowi przełączenie konta za pomocą natywnego okna wyboru konta.

W tym przykładzie dane logowania są przekazywane bez wyświetlania Account Chooser, co odpowiada poprzedniej fladze unmediated: true:

navigator.credentials.get({
    password: true,
    federated: {
    providers: [ 'https://accounts.google.com' ]
    },
    mediation: 'silent&>#39;
}).then(c = {

    // Sign-in
});

Zmieniono nazwę z requireUserMediation() na preventSilentAccess()

Aby dopasować do nowej właściwości mediation oferowanej w wywołaniu get(), zmieniliśmy nazwę metody navigator.credentials.requireUserMediation() na navigator.credentials.preventSilentAccess().

Zmieniona nazwa metody uniemożliwia przekazywanie danych logowania bez wyświetlania selektora konta (czasami nazywanego bez pośrednictwa użytkownika). Jest to przydatne, gdy użytkownik wyloguje się z witryny lub wyrejestruje się z niej i nie chce być automatycznie logowany przy następnej wizycie.

signoutUser();
if (navigator.credentials) {
    navigator.credentials.preventSilentAccess();
}

Asynchroniczne tworzenie obiektów danych logowania za pomocą nowej metody navigator.credentials.create()

Teraz możesz tworzyć obiekty danych logowania asynchronicznie za pomocą nowej metody navigator.credentials.create(). Poniżej znajdziesz porównanie podejścia synchronicznego i asynchronicznego.

Tworzenie obiektu PasswordCredential

Metoda synchronizacji
let c = new PasswordCredential(form);
Podejście asynchroniczne (nowe)
let c = await navigator.credentials.create({
    password: form
});

lub

let c = await navigator.credentials.create({
    password: {
    id: id,
    password: password
    }
});

Tworzenie obiektu FederatedCredential

Metoda synchronizacji
let c = new FederatedCredential({
    id:       'agektmr',
    name:     'Eiji Kitamura',
    provider: 'https://accounts.google.com',
    iconURL:  'https://*****'
});
Podejście asynchroniczne (nowość)
let c = await navigator.credentials.create({
    federated: {
    id:       'agektmr',
    name:     'Eiji Kitamura',
    provider: 'https://accounts.google.com',
    iconURL:  'https://*****'
    }
});

Przewodnik po migracji

Masz już wdrożony interfejs Credential Management API? Aby przejść na nową wersję, możesz skorzystać z przewodnika po migracji.