การอัปเดตล่าสุดของ 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'
}).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);
});

เราจะเลิกใช้งานการดึงข้อมูลที่กำหนดเองในเร็วๆ นี้

หากต้องการตรวจสอบว่าคุณใช้ฟังก์ชัน 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&>#39;
}).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://*****'
    }
});

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

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