แนวทางปฏิบัติแนะนำสำหรับแบบฟอร์ม SMS OTP

โดยทั่วไปแล้ว เราจะขอให้ผู้ใช้ระบุรหัสผ่านที่สามารถใช้งานได้เพียงครั้งเดียว (OTP) เพื่อยืนยันตัวตน ด้วยการส่ง SMS กรณีการใช้งาน OTP ทาง SMS บางส่วนมีดังนี้

  • การตรวจสอบสิทธิ์แบบ 2 ปัจจัย นอกจากชื่อผู้ใช้และรหัสผ่านแล้ว OTP ทาง SMS ยังใช้เป็นสัญญาณที่รัดกุมได้ว่าบัญชีเป็นของบุคคลที่ได้รับ OTP ทาง SMS
  • การยืนยันหมายเลขโทรศัพท์ บางบริการใช้หมายเลขโทรศัพท์เป็นตัวระบุหลักของผู้ใช้ ในบริการดังกล่าว ผู้ใช้สามารถป้อนหมายเลขโทรศัพท์และ OTP ที่ได้รับทาง SMS เพื่อพิสูจน์ตัวตน บางครั้งก็ใช้ร่วมกับ PIN เพื่อสร้างการตรวจสอบสิทธิ์แบบ 2 ปัจจัย
  • การกู้คืนบัญชี เมื่อผู้ใช้สูญเสียสิทธิ์เข้าถึงบัญชี จะต้องมีวิธีในการกู้คืนบัญชี การส่งอีเมลไปยังอีเมลที่ลงทะเบียนไว้หรือ การส่ง OTP ทาง SMS ไปยังหมายเลขโทรศัพท์เป็นวิธีการกู้คืนบัญชีที่ใช้กันโดยทั่วไป
  • การยืนยันการชำระเงิน ในระบบการชำระเงิน ธนาคารหรือผู้ออกบัตรเครดิตบางราย ขอการตรวจสอบสิทธิ์เพิ่มเติมจากผู้ชำระเงินด้วยเหตุผลด้านความปลอดภัย โดยทั่วไปแล้วจะใช้ OTP ทาง SMS เพื่อวัตถุประสงค์ดังกล่าว

อ่านต่อเพื่อดูแนวทางปฏิบัติแนะนำในการสร้างแบบฟอร์ม OTP ทาง SMS สำหรับกรณีการใช้งานเหล่านี้

เช็กลิสต์

หากต้องการมอบประสบการณ์การใช้งานที่ดีที่สุดให้แก่ผู้ใช้ด้วย OTP ทาง SMS ให้ทำตามขั้นตอนต่อไปนี้

  • ใช้องค์ประกอบ <input> กับรายการต่อไปนี้
    • type="text"
    • inputmode="numeric"
    • autocomplete="one-time-code"
  • ใช้ @BOUND_DOMAIN #OTP_CODE เป็นบรรทัดสุดท้ายของข้อความ SMS ที่มีรหัส OTP
  • ใช้ WebOTP API

ใช้องค์ประกอบ <input>

การใช้แบบฟอร์มที่มีองค์ประกอบ <input> เป็นแนวทางปฏิบัติแนะนำที่สำคัญที่สุดที่คุณ ทำตามได้ เนื่องจากใช้ได้ในทุกเบราว์เซอร์ แม้ว่าคำแนะนำอื่นๆ จากโพสต์นี้จะใช้ไม่ได้ในบางเบราว์เซอร์ แต่ผู้ใช้จะยังคงป้อนและส่ง OTP ได้ด้วยตนเอง

<form action="/verify-otp" method="POST">
  <input type="text"
      inputmode="numeric"
      autocomplete="one-time-code"
      pattern="\d{6}"
      required>
</form>

ต่อไปนี้เป็นแนวคิดบางส่วนที่จะช่วยให้ช่องป้อนข้อมูลได้รับประโยชน์สูงสุดจากฟังก์ชันการทำงานของเบราว์เซอร์

type="text"

เนื่องจากโดยปกติแล้ว OTP จะเป็นตัวเลข 5 หรือ 6 หลัก การใช้ type="number" สำหรับช่องป้อนข้อมูลจึงอาจดูใช้งานง่ายเนื่องจากจะเปลี่ยนแป้นพิมพ์บนอุปกรณ์เคลื่อนที่ ให้เป็นตัวเลขเท่านั้น เราไม่แนะนำให้ทำเช่นนี้เนื่องจากเบราว์เซอร์คาดหวังว่าช่องป้อนข้อมูลจะเป็นตัวเลขที่นับได้ ไม่ใช่ลำดับของตัวเลขหลายตัว ซึ่งอาจทำให้เกิดลักษณะการทำงานที่ไม่คาดคิด การใช้ type="number" จะทำให้ปุ่มขึ้นและลง ปรากฏข้างช่องป้อนข้อมูล การกดปุ่มเหล่านี้ จะเพิ่มหรือลดตัวเลข และอาจนำหน้าเลข 0 ออก

โปรดใช้ type="text" แทน การดำเนินการนี้จะไม่เปลี่ยนแป้นพิมพ์บนอุปกรณ์เคลื่อนที่ให้แสดงเฉพาะตัวเลข แต่ไม่เป็นไรเนื่องจากเคล็ดลับถัดไปสำหรับการใช้ inputmode="numeric" จะ ทำหน้าที่ดังกล่าว

inputmode="numeric"

ใช้ inputmode="numeric" เพื่อเปลี่ยนแป้นพิมพ์บนอุปกรณ์เคลื่อนที่ให้แสดงเฉพาะตัวเลข

บางเว็บไซต์ใช้ type="tel" สำหรับช่องป้อน OTP เนื่องจากจะเปลี่ยนแป้นพิมพ์บนอุปกรณ์เคลื่อนที่เป็นตัวเลขเท่านั้น (รวมถึง * และ #) เมื่อโฟกัส เคล็ดลับนี้ใช้ในอดีตเมื่อinputmode="numeric" ยังไม่ได้รับการรองรับอย่างแพร่หลาย เนื่องจาก Firefox เริ่มรองรับ inputmode="numeric" จึงไม่จำเป็นต้องใช้แฮ็ก type="tel" ที่ไม่ถูกต้องในเชิงความหมาย

autocomplete="one-time-code"

autocomplete ช่วยให้นักพัฒนาแอประบุสิทธิ์ที่เบราว์เซอร์ ต้องให้ความช่วยเหลือในการเติมข้อความอัตโนมัติ และแจ้งให้เบราว์เซอร์ทราบเกี่ยวกับ ประเภทข้อมูลที่คาดหวังในช่อง

เมื่อใดก็ตามที่ผู้ใช้ได้รับข้อความ SMS ขณะที่เปิดแบบฟอร์มอยู่ ระบบปฏิบัติการจะแยกวิเคราะห์ OTP ใน SMS โดยใช้ฮิวริสติก และแป้นพิมพ์จะแนะนำ OTP ให้ผู้ใช้ป้อนautocomplete="one-time-code" โดยจะใช้ได้เฉพาะใน Safari 12 ขึ้นไปบน iOS, iPadOS และ macOS แต่เราขอแนะนำให้ใช้ เนื่องจากเป็นวิธีที่ดีกว่าในการปรับปรุงประสบการณ์ OTP ทาง SMS บนแพลตฟอร์มเหล่านั้น

autocomplete="one-time-code" กำลังดำเนินการ

autocomplete="one-time-code" ช่วยปรับปรุงประสบการณ์ของผู้ใช้ แต่คุณยังทำได้มากกว่านี้ด้วยการตรวจสอบว่าข้อความ SMS เป็นไปตามรูปแบบข้อความที่ผูกกับต้นทาง

แอตทริบิวต์ที่ไม่บังคับ

แอตทริบิวต์ที่ไม่บังคับมีดังนี้

อ่านคำแนะนำเพิ่มเติมได้ในแนวทางปฏิบัติแนะนำเกี่ยวกับแบบฟอร์มลงชื่อเข้าใช้

จัดรูปแบบข้อความ SMS

ปรับปรุงประสบการณ์ของผู้ใช้ในการป้อน OTP โดยการปฏิบัติตามข้อกำหนดของ รหัสแบบครั้งเดียวที่ผูกกับต้นทางซึ่งส่งทาง SMS

โดยหลักการแล้ว กฎรูปแบบมีดังนี้ จบข้อความ SMS ด้วยโดเมนผู้รับที่ขึ้นต้นด้วย @ และ OTP ที่ขึ้นต้นด้วย #

เช่น

Your OTP is 123456

@web-otp.glitch.me #123456

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

กฎการจัดรูปแบบที่แม่นยำ

กฎที่แน่นอนมีดังนี้

  • ข้อความจะเริ่มต้นด้วยข้อความที่มนุษย์อ่านได้ (ไม่บังคับ) ซึ่งมีสตริงอักขระที่เป็นตัวอักษรและตัวเลขคละกัน 4-10 ตัวที่มีตัวเลขอย่างน้อย 1 ตัว โดยเว้นบรรทัดสุดท้ายไว้สำหรับ URL และ OTP
  • ส่วนโดเมนของ URL ของเว็บไซต์ที่เรียกใช้ API ต้องขึ้นต้นด้วย @
  • URL ต้องมี # ตามด้วย OTP จำนวนอักขระต้องไม่เกิน 140 ตัว

การใช้รูปแบบนี้มีประโยชน์ 2 ประการ ดังนี้

  • โดย OTP จะเชื่อมโยงกับโดเมน หากผู้ใช้ใช้โดเมนอื่นที่ไม่ใช่โดเมนที่ระบุในข้อความ SMS คำแนะนำ OTP จะไม่ปรากฏ นอกจากนี้ยังช่วยลดความเสี่ยงจากการโจมตีแบบฟิชชิงและการลักลอบใช้บัญชี
  • ตอนนี้เบราว์เซอร์จะสามารถดึง OTP ได้อย่างน่าเชื่อถือโดยไม่ต้องอาศัยฮิวริสติกที่ซับซ้อนและไม่แน่นอน

เมื่อเว็บไซต์ใช้ autocomplete="one-time-code", Safari ใน iOS 14 ขึ้นไป จะแนะนำ OTP ตามกฎต่อไปนี้

รูปแบบข้อความ SMS นี้ยังมีประโยชน์ต่อเบราว์เซอร์อื่นๆ นอกเหนือจาก Safari ด้วย Chrome, Opera และ Vivaldi ใน Android ยังรองรับกฎรหัสแบบใช้ครั้งเดียวที่เชื่อมโยงกับต้นทางด้วย WebOTP API แต่ไม่รองรับผ่าน autocomplete="one-time-code"

ใช้ WebOTP API

WebOTP API ให้สิทธิ์เข้าถึง OTP ที่ได้รับในข้อความ SMS การเรียกใช้ navigator.credentials.get() ด้วยประเภท otp (OTPCredential) ที่ transport มี sms เว็บไซต์ จะรอ SMS ที่เป็นไปตามรหัสแบบใช้ครั้งเดียวที่ผูกกับต้นทางเพื่อ ส่งและให้ผู้ใช้สิทธิ์เข้าถึง เมื่อส่ง OTP ไปยัง JavaScript แล้ว เว็บไซต์จะใช้ OTP ในแบบฟอร์มหรือ POST ไปยังเซิร์ฟเวอร์โดยตรงได้

navigator.credentials.get({
  otp: {transport:['sms']}
})
.then(otp => input.value = otp.code);
WebOTP API ในการทำงาน

ดูวิธีใช้ WebOTP API โดยละเอียดได้ในยืนยันหมายเลขโทรศัพท์บนเว็บ ด้วย WebOTP API หรือคัดลอกและวางข้อมูลโค้ดต่อไปนี้ อย่าลืมตั้งค่าแอตทริบิวต์ action และ method ใน <form>

// Feature detection
if ('OTPCredential' in window) {
  window.addEventListener('DOMContentLoaded', e => {
    const input = document.querySelector('input[autocomplete="one-time-code"]');
    if (!input) return;
    // Cancel the WebOTP API if the form is submitted manually.
    const ac = new AbortController();
    const form = input.closest('form');
    if (form) {
      form.addEventListener('submit', e => {
        // Cancel the WebOTP API.
        ac.abort();
      });
    }
    // Invoke the WebOTP API
    navigator.credentials.get({
      otp: { transport:['sms'] },
      signal: ac.signal
    }).then(otp => {
      input.value = otp.code;
      // Automatically submit the form when an OTP is obtained.
      if (form) form.submit();
    }).catch(err => {
      console.log(err);
    });
  });
}