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

ดูวิธีเพิ่มประสิทธิภาพแบบฟอร์ม SMS OTP และปรับปรุงประสบการณ์ของผู้ใช้

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

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

โพสต์นี้อธิบายแนวทางปฏิบัติแนะนำในการสร้างแบบฟอร์ม OTP สำหรับ SMS สำหรับการใช้งานข้างต้น กรณี

เช็กลิสต์

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

  • ใช้องค์ประกอบ <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" สาเหตุการเพิ่มขึ้นและลดลง แสดงข้างฟิลด์ป้อนข้อมูล การกดปุ่มเหล่านี้ เพิ่มหรือลดจำนวนและอาจลบเลขศูนย์ที่อยู่ก่อนหน้า

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

inputmode="numeric"

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

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

autocomplete="one-time-code"

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

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

`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 กับ เว็บไซต์ทำให้หลอกลวงผู้ใช้ให้ใช้รหัสในเว็บไซต์ที่เป็นอันตรายได้ยากขึ้น

การใช้รูปแบบนี้มีข้อดีหลายประการ ได้แก่

  • 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 เว็บไซต์สามารถใช้แบบฟอร์มหรือ POST ไปยังเซิร์ฟเวอร์โดยตรง

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

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

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

รูปภาพโดย Jason Leung บน หน้าจอแนะนํา