Algunas de las actualizaciones que se describen aquí se explican en la sesión de Google I/O Acceso seguro y sin problemas: mantener la participación de los usuarios:
Chrome 57
En Chrome 57, se introdujo este cambio importante en la API de Credential Management.
Las credenciales se pueden compartir desde otro subdominio
Ahora Chrome puede recuperar una credencial almacenada en un subdominio diferente mediante la API de Credential Management.
Por ejemplo, si una contraseña se almacena en login.example.com
, una secuencia de comandos en www.example.com
puede mostrarla como uno de los elementos de cuenta en el diálogo del selector de cuentas.
Debes almacenar la contraseña de manera explícita con navigator.credentials.store()
, de modo que, cuando un usuario elija una credencial presionando el diálogo, la contraseña se pase y se copie en el origen actual.
Una vez que se almacena, la contraseña está disponible como una credencial en exactamente el mismo origen www.example.com
y en adelante.
En la siguiente captura de pantalla, la información de credenciales almacenada en login.aliexpress.com
es visible para m.aliexpress.com
y está disponible para que el usuario la elija:
Chrome 60
Chrome 60 presenta varios cambios importantes en la API de Credential Management:
Dado que la función
fetch()
personalizada ya no es necesaria para recuperar la contraseña, pronto dejará de estar disponible.navigator.credentials.get()
ahora acepta una enumeraciónmediation
en lugar de la marca booleanaunmediated
Se cambió el nombre de
requireUserMediation()
porpreventSilentAccess()
.El nuevo método
navigator.credentials.create()
crea objetos de credenciales de forma asíncrona.
La detección de funciones requiere atención
Para ver si la API de Credential Management para acceder a credenciales federadas y basadas en contraseña está disponible, verifica si window.PasswordCredential
o window.FederatedCredential
están disponibles.
if (window.PasswordCredential || window.FederatedCredential) {
// The Credential Management API is available
}
El objeto PasswordCredential
ahora incluye una contraseña
La API de Credential Management adoptó un enfoque conservador para el manejo de las contraseñas.
Ocultó las contraseñas de JavaScript, por lo que los desarrolladores debían enviar el objeto PasswordCredential
directamente a su servidor para su validación a través de una extensión de la API fetch()
.
Sin embargo, este enfoque introdujo varias restricciones. Recibimos comentarios que indicaban que los desarrolladores no podían usar la API por los siguientes motivos:
Debieron enviar la contraseña como parte de un objeto JSON.
Debía enviar el valor hash de la contraseña al servidor.
Después de realizar un análisis de seguridad y reconocer que ocultar las contraseñas de JavaScript no impedía a todos los vectores de ataque con la eficacia que esperábamos, decidimos hacer un cambio.
La API de Credential Management ahora incluye una contraseña sin procesar en un objeto de credenciales que se muestra para que puedas acceder a ella como texto sin formato. Puedes usar los métodos existentes para entregar información de credenciales a tu servidor:
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);
});
La recuperación personalizada dejará de estar disponible pronto
Para determinar si usas una función fetch()
personalizada,
verifica si usa un objeto PasswordCredential
o FederatedCredential
como un valor de la propiedad credentials
, por ejemplo:
fetch('/signin', {
method: 'POST',
credentials: c
})
Se recomienda usar una función fetch()
normal como se muestra en el ejemplo de código anterior o un XMLHttpRequest
.
navigator.credentials.get()
ahora acepta una mediación de tipo enum
Hasta Chrome 60, navigator.credentials.get()
aceptaba una propiedad unmediated
opcional con una marca booleana. Por ejemplo:
navigator.credentials.get({
password: true,
federated: {
providers: [ 'https://accounts.google.com' ]
},
unmediated: true
}).then(c => {
// Sign-in
});
Si se configura unmediated: true
, se evita que el navegador muestre el selector de cuentas cuando se pasa una credencial.
La marca ahora se extiende como mediación. La mediación del usuario podría ocurrir en los siguientes casos:
El usuario debe elegir una cuenta para acceder.
Un usuario quiere acceder explícitamente después de la llamada a
navigator.credentials.requireUseMediation()
.
Elige una de las siguientes opciones para el valor mediation
:
Valor mediation |
En comparación con la marca booleana | Comportamiento | |
---|---|---|---|
silent |
Es igual a unmediated: true |
Se aprobó la credencial sin mostrar un selector de cuentas. | |
optional |
Es igual a unmediated: false |
Muestra un selector de cuentas si preventSilentAccess() llamó anteriormente. |
|
required |
Una opción nueva | Mostrar siempre un selector de cuentas Es útil cuando quieres permitir que un usuario cambie de cuenta mediante el diálogo del selector de cuentas nativo. |
En este ejemplo, la credencial se pasa sin mostrar un selector de cuentas, el equivalente de la marca anterior, unmediated: true
:
navigator.credentials.get({
password: true,
federated: {
providers: [ 'https://accounts.google.com' ]
},
mediation: 'silent'
}).then(c => {
// Sign-in
});
Se cambió el nombre de requireUserMediation()
por preventSilentAccess()
Para alinearse bien con la nueva propiedad mediation
que se ofrece en la llamada a get()
, se cambió el nombre del método navigator.credentials.requireUserMediation()
por navigator.credentials.preventSilentAccess()
.
El método con el nombre cambiado evita que se pase una credencial sin mostrar el selector de cuentas (a veces se llama sin mediación del usuario). Esto resulta útil cuando un usuario sale de su cuenta en un sitio web o cancela su registro en uno de ellos, y no quiere volver a acceder automáticamente en la próxima visita.
signoutUser();
if (navigator.credentials) {
navigator.credentials.preventSilentAccess();
}
Crea objetos de credenciales de forma asíncrona con el nuevo método navigator.credentials.create()
.
Ahora tienes la opción de crear objetos de credenciales de forma asíncrona con el nuevo método, navigator.credentials.create()
.
Continúa leyendo para obtener una comparación entre los enfoques síncronos y asíncronos.
Crea un objeto PasswordCredential
Enfoque de sincronización
let c = new PasswordCredential(form);
Enfoque asíncrono (nuevo)
let c = await navigator.credentials.create({
password: form
});
o bien
let c = await navigator.credentials.create({
password: {
id: id,
password: password
}
});
Crea un objeto FederatedCredential
Enfoque de sincronización
let c = new FederatedCredential({
id: 'agektmr',
name: 'Eiji Kitamura',
provider: 'https://accounts.google.com',
iconURL: 'https://*****'
});
Enfoque asíncrono (nuevo)
let c = await navigator.credentials.create({
federated: {
id: 'agektmr',
name: 'Eiji Kitamura',
provider: 'https://accounts.google.com',
iconURL: 'https://*****'
}
});
Guía de migración
¿Tienes una implementación existente de la API de Credential Management? Tenemos un documento de guía de migración que puedes seguir para actualizar a la nueva versión.