การอัปเดตล่าสุดของ API การจัดการข้อมูลเข้าสู่ระบบ

การอัปเดตบางอย่างที่อธิบายไว้ที่นี่มีคำอธิบายอยู่ในเซสชัน Google I/O เรื่องการลงชื่อเข้าใช้ที่ปลอดภัยและราบรื่น: คงการมีส่วนร่วมของผู้ใช้

Chrome 57

Chrome 57 ได้เปิดตัวการเปลี่ยนแปลงที่สําคัญนี้ใน Credential Management API

คุณสามารถแชร์ข้อมูลเข้าสู่ระบบจากโดเมนย่อยอื่นได้

ตอนนี้ Chrome สามารถดึงข้อมูลเข้าสู่ระบบที่จัดเก็บไว้ในโดเมนย่อยอื่นได้โดยใช้ Credential Management API ตัวอย่างเช่น หากมีการจัดเก็บรหัสผ่านใน login.example.com นั้น สคริปต์ใน www.example.com จะแสดงรหัสผ่านดังกล่าวเป็นหนึ่งในรายการบัญชีในกล่องโต้ตอบเครื่องมือเลือกบัญชีได้

คุณต้องจัดเก็บรหัสผ่านโดยใช้ navigator.credentials.store() อย่างชัดแจ้ง เพื่อให้ระบบส่งและคัดลอกรหัสผ่านไปยังต้นทางปัจจุบันเมื่อผู้ใช้เลือกข้อมูลเข้าสู่ระบบโดยการแตะกล่องโต้ตอบ

เมื่อจัดเก็บแล้ว รหัสผ่านจะพร้อมใช้งานเป็นข้อมูลเข้าสู่ระบบในต้นทางเดียวกันตั้งแต่www.example.comเป็นต้นไป

ในภาพหน้าจอต่อไปนี้ ข้อมูลเข้าสู่ระบบที่เก็บไว้ภายใต้ login.aliexpress.com จะแสดงให้ m.aliexpress.com เห็นและพร้อมให้ผู้ใช้เลือก

เครื่องมือเลือกบัญชีที่แสดงรายละเอียดการเข้าสู่ระบบโดเมนย่อยที่เลือก

Chrome 60

Chrome 60 มีการเปลี่ยนแปลงที่สําคัญหลายอย่างใน Credential Management API ดังนี้

การตรวจหาองค์ประกอบต้องดำเนินการ

หากต้องการตรวจสอบว่า Credential Management API สําหรับการเข้าถึงข้อมูลเข้าสู่ระบบที่ใช้รหัสผ่านและข้อมูลเข้าสู่ระบบที่รวมศูนย์พร้อมใช้งานหรือไม่ ให้ตรวจสอบว่า window.PasswordCredential หรือ window.FederatedCredential พร้อมใช้งานหรือไม่

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

ตอนนี้ออบเจ็กต์ PasswordCredential มีรหัสผ่านแล้ว

Credential Management API ใช้แนวทางที่อนุรักษ์นิยมในการจัดการรหัสผ่าน ซึ่งจะปกปิดรหัสผ่านจาก JavaScript โดยกำหนดให้นักพัฒนาแอปส่งออบเจ็กต์ PasswordCredential ไปยังเซิร์ฟเวอร์โดยตรงเพื่อตรวจสอบผ่านส่วนขยายของ fetch() API

แต่วิธีการนี้มีข้อจํากัดหลายประการ เราได้รับความคิดเห็นว่านักพัฒนาแอปใช้ API ไม่ได้เนื่องจากสาเหตุต่อไปนี้

  • โดยต้องส่งรหัสผ่านเป็นส่วนหนึ่งของออบเจ็กต์ JSON

  • ผู้ใช้ต้องส่งค่าแฮชของรหัสผ่านไปยังเซิร์ฟเวอร์

หลังจากทำการวิเคราะห์ความปลอดภัยและพบว่าการปกปิดรหัสผ่านจาก JavaScript ไม่ได้ป้องกันเวกเตอร์การโจมตีทั้งหมดได้อย่างมีประสิทธิภาพตามที่คาดหวัง เราจึงตัดสินใจที่จะเปลี่ยนแปลง

ตอนนี้ Credential Management 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 ที่ไม่บังคับ ด้วย Flag บูลีน เช่น

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

    // Sign-in
});

การตั้งค่า unmediated: true ป้องกันไม่ให้เบราว์เซอร์แสดงเครื่องมือเลือกบัญชีเมื่อส่งข้อมูลเข้าสู่ระบบ

ตอนนี้การแจ้งว่าไม่เหมาะสมได้ขยายการให้บริการเป็นสื่อกลางแล้ว การสื่อกลางของผู้ใช้อาจเกิดขึ้นในกรณีต่อไปนี้

  • ผู้ใช้ต้องเลือกบัญชีที่จะลงชื่อเข้าใช้

  • ผู้ใช้ต้องการลงชื่อเข้าใช้อย่างชัดเจนหลังจากnavigator.credentials.requireUseMediation()โทร

เลือกตัวเลือกใดตัวเลือกหนึ่งต่อไปนี้สำหรับค่า mediation

ค่า mediation เมื่อเทียบกับ Flag แบบบูลีน พฤติกรรม
silent เท่ากับ unmediated: true ส่งข้อมูลเข้าสู่ระบบโดยไม่ได้แสดงเครื่องมือเลือกบัญชี
optional เท่ากับ unmediated: false แสดงเครื่องมือเลือกบัญชีหากเรียกใช้ preventSilentAccess() ก่อนหน้านี้
required ตัวเลือกใหม่ แสดงเครื่องมือเลือกบัญชีเสมอ มีประโยชน์เมื่อคุณต้องการอนุญาตให้ผู้ใช้เปลี่ยนบัญชีโดยใช้กล่องโต้ตอบตัวเลือกบัญชีแบบดั้งเดิม

ในตัวอย่างนี้ ระบบจะส่งผ่านข้อมูลเข้าสู่ระบบโดยไม่แสดงเครื่องมือเลือกบัญชี ซึ่งเทียบเท่ากับ Flag ก่อนหน้า unmediated: true

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

    // Sign-in
});

เปลี่ยนชื่อ requireUserMediation() เป็น preventSilentAccess()

เราได้เปลี่ยนชื่อเมธอด navigator.credentials.requireUserMediation() เป็น navigator.credentials.preventSilentAccess() เพื่อให้สอดคล้องกับพร็อพเพอร์ตี้ mediation ใหม่ที่เสนอในการเรียก get()

เมธอดที่เปลี่ยนชื่อจะป้องกันไม่ให้ส่งข้อมูลเข้าสู่ระบบโดยไม่แสดงเครื่องมือเลือกบัญชี (บางครั้งเรียกว่า "ไม่มีสื่อกลางของผู้ใช้") ซึ่งจะมีประโยชน์เมื่อผู้ใช้ออกจากระบบเว็บไซต์หรือยกเลิกการลงทะเบียนในเว็บไซต์ และไม่ต้องการลงชื่อเข้าใช้อีกครั้งโดยอัตโนมัติเมื่อเข้าชมครั้งถัดไป

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://*****'
    }
});

คำแนะนำในการย้ายข้อมูล

มีการใช้งาน Credential Management API อยู่แล้วใช่ไหม เรามีเอกสารคำแนะนำในการย้ายข้อมูลไว้ให้คุณสามารถอัปเกรดเป็นเวอร์ชันใหม่