Neueste Updates zur Credential Management API

Einige der hier beschriebenen Änderungen werden in der Google I/O-Sitzung Secure and Seamless Sign-In: Keeping Users Engaged (Sichere und nahtlose Anmeldung: Nutzer binden) erläutert:

Chrome 57

In Chrome 57 wurde diese wichtige Änderung an der Credential Management API eingeführt.

Anmeldedaten können über eine andere Subdomain freigegeben werden

Chrome kann jetzt mithilfe der Credential Management API Anmeldedaten abrufen, die in einer anderen Subdomain gespeichert sind. Wenn beispielsweise ein Passwort in login.example.com gespeichert ist, kann es in einem Script auf login.example.com im Dialogfeld für die Kontoauswahl als eines der Kontoelemente angezeigt werden.www.example.com

Sie müssen das Passwort explizit mit navigator.credentials.store() speichern, damit das Passwort übergeben und in den aktuellen Ursprung kopiert wird, wenn ein Nutzer durch Tippen auf das Dialogfeld Anmeldedaten auswählt.

Nach dem Speichern ist das Passwort ab www.example.com als Anmeldedaten an genau derselben Quelle verfügbar.

Im folgenden Screenshot sind unter login.aliexpress.com gespeicherte Anmeldedaten für m.aliexpress.com sichtbar und stehen dem Nutzer zur Auswahl:

Kontoauswahl mit Anmeldedaten für die ausgewählte Subdomain

Chrome 60

Mit Chrome 60 werden mehrere wichtige Änderungen an der Credential Management API eingeführt:

Funktionserkennung erfordert Aufmerksamkeit

Ob die Credential Management API für den Zugriff auf passwortbasierte und föderierte Anmeldedaten verfügbar ist, erkennen Sie daran, ob window.PasswordCredential oder window.FederatedCredential verfügbar ist.

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

Das PasswordCredential-Objekt enthält jetzt das Passwort

Bei der Credential Management API wurde ein konservativer Ansatz für die Passwortverwaltung gewählt. Sie hat Passwörter vor JavaScript verborgen, sodass Entwickler das PasswordCredential-Objekt zur Validierung über eine Erweiterung der fetch() API direkt an ihren Server senden mussten.

Dieser Ansatz führte jedoch zu einer Reihe von Einschränkungen. Wir haben Feedback erhalten, dass Entwickler die API nicht verwenden konnten, weil:

  • Das Passwort wurde als Teil eines JSON-Objekts gesendet.

  • Sie mussten den Hashwert des Passworts an ihren Server senden.

Nach einer Sicherheitsanalyse haben wir festgestellt, dass das Verstecken von Passwörtern vor JavaScript nicht alle Angriffsvektoren so effektiv verhindert, wie wir gehofft hatten. Deshalb haben wir uns entschlossen, eine Änderung vorzunehmen.

Die Credential Management API enthält jetzt ein Rohpasswort in einem zurückgegebenen Anmeldedatenobjekt, sodass Sie darauf als Klartext zugreifen können. Sie können vorhandene Methoden verwenden, um Anmeldedaten an Ihren Server zu senden:

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

Der benutzerdefinierte Abruf wird bald eingestellt

Ob Sie eine benutzerdefinierte fetch()-Funktion verwenden, erkennen Sie daran, ob ein PasswordCredential-Objekt oder ein FederatedCredential-Objekt als Wert der credentials-Property verwendet wird, z. B.:

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

Es wird empfohlen, eine reguläre fetch()-Funktion wie im vorherigen Codebeispiel gezeigt oder eine XMLHttpRequest zu verwenden.

Bis Chrome 60 wurde für navigator.credentials.get() eine optionale unmediated-Eigenschaft mit einem booleschen Flag akzeptiert. Beispiel:

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

    // Sign-in
});

Wenn Sie unmediated: true festlegen, wird die Kontoauswahl nicht angezeigt, wenn Anmeldedaten übergeben werden.

Das Flag wird jetzt als Vermittlung erweitert. Die Nutzervermittlung kann in folgenden Fällen erfolgen:

  • Ein Nutzer muss ein Konto für die Anmeldung auswählen.

  • Ein Nutzer möchte sich nach dem navigator.credentials.requireUseMediation()-Aufruf explizit anmelden.

Wählen Sie einen der folgenden Werte für mediation aus:

mediation Wert Im Vergleich zu einem booleschen Flag Verhalten
silent Ist gleich unmediated: true Anmeldedaten wurden bestanden, ohne dass eine Kontoauswahl angezeigt wird.
optional Ist gleich unmediated: false Zeigt eine Kontoauswahl an, wenn preventSilentAccess() zuvor aufgerufen wurde.
required Neue Option Kontoauswahl immer anzeigen. Nützlich, wenn Sie Nutzern erlauben möchten, über das native Auswahlfenster für Konten das Konto zu wechseln.

In diesem Beispiel werden die Anmeldedaten übergeben, ohne dass eine Kontoauswahl angezeigt wird. Das entspricht dem vorherigen Flag unmediated: true:

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

    // Sign-in
});

requireUserMediation() in preventSilentAccess() umbenannt

Um die neue mediation-Eigenschaft im get()-Aufruf besser zu unterstützen, wurde die Methode navigator.credentials.requireUserMediation() in navigator.credentials.preventSilentAccess() umbenannt.

Durch die umbenannte Methode werden Anmeldedaten nicht übergeben, ohne dass die Kontoauswahl angezeigt wird (manchmal ohne Nutzervermittlung aufgerufen). Das ist nützlich, wenn sich ein Nutzer von einer Website abmeldet oder sich dort abmeldet und nicht beim nächsten Besuch automatisch wieder angemeldet werden möchte.

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

Anmeldedatenobjekte asynchron mit der neuen Methode navigator.credentials.create() erstellen

Mit der neuen Methode navigator.credentials.create() können Sie jetzt asynchron Anmeldedatenobjekte erstellen. Im Folgenden finden Sie einen Vergleich zwischen dem synchronen und dem asynchronen Ansatz.

PasswordCredential-Objekt erstellen

Synchronisierungsansatz
let c = new PasswordCredential(form);
Asynchroner Ansatz (neu)
let c = await navigator.credentials.create({
    password: form
});

oder

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

FederatedCredential-Objekt erstellen

Synchronisierungsansatz
let c = new FederatedCredential({
    id:       'agektmr',
    name:     'Eiji Kitamura',
    provider: 'https://accounts.google.com',
    iconURL:  'https://*****'
});
Asynchroner Ansatz (neu)
let c = await navigator.credentials.create({
    federated: {
    id:       'agektmr',
    name:     'Eiji Kitamura',
    provider: 'https://accounts.google.com',
    iconURL:  'https://*****'
    }
});

Migrationsanleitung

Du hast die Credential Management API bereits implementiert? In unserem Migrationsleitfaden finden Sie eine Anleitung zum Upgrade auf die neue Version.