ดูวิธีเพิ่มประสิทธิภาพแบบฟอร์ม SMS OTP และปรับปรุงประสบการณ์ของผู้ใช้
การขอให้ผู้ใช้ระบุ OTP (รหัสผ่านที่สามารถใช้งานได้เพียงครั้งเดียว) ที่ส่งผ่าน SMS เป็นวิธีการทั่วไปในการยืนยันหมายเลขโทรศัพท์ของผู้ใช้ ตัวอย่างการใช้ SMS OTP มีดังนี้
- การตรวจสอบสิทธิ์แบบ 2 ปัจจัย นอกจากชื่อผู้ใช้และรหัสผ่านแล้ว SMS OTP ยังใช้เป็นสัญญาณที่ชัดเจนซึ่งแจ้งให้ทราบว่าบัญชีเป็นของผู้ใช้ที่ได้รับ SMS OTP
- การยืนยันหมายเลขโทรศัพท์ บริการบางอย่างใช้หมายเลขโทรศัพท์เป็นตัวระบุหลักของผู้ใช้ ในบริการดังกล่าว ผู้ใช้สามารถป้อนหมายเลขโทรศัพท์และ OTP ที่ได้รับผ่าน SMS เพื่อยืนยันตัวตน บางครั้งการนำ PIN มารวมกับ PIN ประกอบกันเป็นการตรวจสอบสิทธิ์แบบ 2 ปัจจัย
- การกู้คืนบัญชี เมื่อผู้ใช้สูญเสียสิทธิ์การเข้าถึงบัญชีของตนเอง จะต้องมีวิธีกู้คืนบัญชี การส่งอีเมลไปยังอีเมลที่ลงทะเบียนหรือ SMS OTP ไปยังหมายเลขโทรศัพท์เป็นวิธีการกู้คืนบัญชีที่ใช้กันทั่วไป
- การยืนยันการชำระเงินในระบบการชำระเงิน ธนาคารหรือผู้ออกบัตรเครดิตบางแห่งขอการตรวจสอบสิทธิ์เพิ่มเติมจากผู้ชำระเงินเพื่อเหตุผลด้านความปลอดภัย SMS OTP มักใช้เพื่อวัตถุประสงค์ดังกล่าว
โพสต์นี้จะอธิบายแนวทางปฏิบัติแนะนำในการสร้างแบบฟอร์ม SMS OTP สำหรับกรณีการใช้งานข้างต้น
เช็กลิสต์
ทำตามขั้นตอนต่อไปนี้เพื่อมอบประสบการณ์การใช้งานที่ดีที่สุดแก่ผู้ใช้ด้วย 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"
จะทำให้ปุ่มขึ้นและลงแสดงข้างช่องป้อนข้อมูล การกดปุ่มเหล่านี้จะเพิ่มหรือลดจำนวนตัวเลข และอาจนำเลข 0 ที่อยู่ก่อนหน้าออก
โปรดใช้ 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"
ช่วยปรับปรุงประสบการณ์ของผู้ใช้ แต่คุณยังทำอย่างอื่นได้ด้วยการตรวจสอบว่าข้อความ SMS เป็นไปตามรูปแบบข้อความที่เชื่อมโยงกับต้นทาง
จัดรูปแบบข้อความ SMS
ปรับปรุงประสบการณ์ของผู้ใช้ในการป้อน OTP โดยให้สอดคล้องกับข้อกำหนดรหัสแบบใช้ครั้งเดียวจากต้นทางที่ส่งผ่าน SMS
กฎการจัดรูปแบบนั้นง่ายมาก คือให้ส่งข้อความ SMS ให้เสร็จโดยใส่โดเมนของผู้รับซึ่งขึ้นต้นด้วย @
และ OTP นำหน้าด้วย #
เช่น
Your OTP is 123456
@web-otp.glitch.me #123456
การใช้รูปแบบมาตรฐานสำหรับข้อความ OTP ช่วยให้การดึงรหัส จากข้อความเหล่านั้นง่ายและน่าเชื่อถือมากขึ้น การเชื่อมโยงรหัส OTP กับเว็บไซต์ ทำให้การหลอกให้ผู้ใช้ให้รหัสแก่เว็บไซต์ที่เป็นอันตรายทำได้ยากขึ้น
การใช้รูปแบบนี้มีประโยชน์ 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 หรือคัดลอกและวางข้อมูลโค้ดต่อไปนี้ (ตรวจสอบว่าองค์ประกอบ <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 ใน Unsplash