OTP เก่า ต่างจาก OTP หมดอายุและ OTP ที่ใช้แล้วอย่างไร?
OTP คือรหัสสำหรับยืนยันแบบใช้ครั้งเดียว แต่คำว่า “เก่า” ในงานทดสอบอาจหมายถึงคนละปัญหา รหัสอาจยังไม่หมดอายุ แต่เป็นของคำขอที่ถูกแทนที่ไปแล้ว หรือเป็นรหัสของคำขอปัจจุบันที่ใช้สำเร็จไปแล้วก็ได้
สำหรับแอปที่คุณควบคุมระบบออกและตรวจรหัสเอง ให้กำหนดนโยบายให้ชัดก่อนเขียนชุดทดสอบ ตัวอย่างในบทนี้เลือกนโยบาย เมื่อขอรหัสใหม่ ให้คำขอใหม่แทนที่คำขอเดิม ภายในผู้ใช้ วัตถุประสงค์ และบริบทเซสชันเดียวกัน
| ประเภทของรหัส | ความหมายในตัวอย่างนี้ | ผลที่ต้องการ |
|---|---|---|
| รหัสจากคำขอก่อนหน้า | มีคำขอใหม่มาแทนที่แล้ว แม้ยังไม่ถึงเวลาหมดอายุ | ปฏิเสธ |
| รหัสหมดอายุ | เวลาฝั่งเซิร์ฟเวอร์ถึงหรือเลยจุดหมดอายุ | ปฏิเสธ |
| รหัสที่ใช้แล้ว | เคยยืนยันสำเร็จด้วยรหัสของคำขอนี้ | ปฏิเสธ |
| รหัสปัจจุบัน | ตรงคำขอ ยังไม่หมดอายุ และยังไม่ถูกใช้ | รับได้เมื่อผ่านเงื่อนไขอื่นครบ |
แยกเวลาอย่างน้อยเป็นเวลาเริ่มคำขอ เวลาออกรหัส เวลาหมดอายุ และเวลาที่อีเมลมาถึง อย่าใช้เวลาที่อีเมลมาถึงแทนเวลาออกรหัสหรือเริ่มนับอายุรหัสใหม่เมื่ออ่านอีเมลได้
ใน เอกสาร message ของ Microsoft Graph ฟิลด์ receivedDateTime หมายถึงเวลาที่ได้รับข้อความ ส่วน sentDateTime คือเวลาที่ส่งข้อความ ทั้งคู่เป็นเวลาเกี่ยวกับอีเมล ไม่ใช่เวลาหมดอายุของคำขอยืนยันในแอปคุณ
ลองกำหนดกรณีทดสอบให้ขอรหัสรอบ A แล้วขอรอบ B จากนั้นส่งอีเมลของ B ให้ถึงก่อนอีเมลของ A รหัสทั้งสองแสดงเป็น [ปกปิด] ในบันทึก เมื่ออีเมล A มาถึงทีหลัง ชุดทดสอบต้องไม่ถือว่า A กลับมาเป็นคำขอปัจจุบันเพียงเพราะอยู่บนสุดของรายการ

ต้องตรวจอะไรที่เซิร์ฟเวอร์ก่อนรับ OTP?
อย่าให้การเลือกอีเมลถูกฉบับเป็นเงื่อนไขความปลอดภัยเพียงชั้นเดียว แม้ชุดทดสอบจะเลือกผิด เซิร์ฟเวอร์ก็ควรปฏิเสธรหัสที่ใช้ไม่ได้อยู่ดี สำหรับแอปของคุณเอง ให้ออกแบบการตรวจรับตามลำดับนี้
- สร้างคำขอยืนยันที่มีบริบทชัดเจน ผูกคำขอกับผู้ใช้ วัตถุประสงค์ เช่น การเข้าสู่ระบบ และบริบทเซสชันตามการออกแบบของแอป อย่าค้นหาเพียงว่ามีรหัสตัวเลขตรงกันอยู่ที่ใดในระบบ
- กำหนดอายุและนโยบายการขอใหม่ ใช้เวลาของเซิร์ฟเวอร์กำหนดจุดหมดอายุ สำหรับนโยบายตัวอย่างนี้ การเปิดคำขอใหม่ต้องทำให้คำขอก่อนหน้าในบริบทเดียวกันใช้ยืนยันต่อไม่ได้ ไม่ใช่แค่เปลี่ยนรหัสที่แสดงในหน้าเว็บ
- ตรวจเงื่อนไขก่อนยอมรับ คำขอต้องยังเป็นคำขอปัจจุบัน รหัสต้องตรง ยังไม่หมดอายุ และยังไม่เคยใช้สำเร็จ พร้อมจำกัดจำนวนครั้งที่ลองตามนโยบายของแอป ตรวจบริบทผู้ใช้และวัตถุประสงค์ด้วย ไม่ใช่ตรวจรหัสอย่างเดียว
- ตรวจและบันทึกการใช้แบบอะตอมมิก ให้การตัดสินว่ารหัสยังใช้ได้กับการเปลี่ยนสถานะเป็นใช้แล้วเกิดในธุรกรรมเดียวกัน หรือใช้การอัปเดตแบบมีเงื่อนไขที่ให้ผู้ชนะได้เพียงคำขอเดียว อย่าอ่านว่า “ยังไม่ใช้” แล้วค่อยบันทึกภายหลังโดยไม่มีการป้องกันคำขอพร้อมกัน
คำว่า “ปัจจุบัน” “ถูกแทนที่” และ “ใช้แล้ว” ในขั้นตอนนี้เป็นสถานะที่คุณออกแบบในแอป ไม่ใช่ฟิลด์ของ Mailera หากการขอรหัสใหม่ชนกับการยืนยันรหัสเดิม การตรวจว่าคำขอยังเป็นปัจจุบันก็ควรอยู่ในขอบเขตการทำงานแบบอะตอมมิกเดียวกันด้วย
ระบุเงื่อนไขเวลาหมดอายุในข้อกำหนดของแอปให้ชัดเจน เช่น ตัวอย่างนี้ยอมรับเฉพาะเมื่อเวลาปัจจุบันน้อยกว่าเวลาหมดอายุ ดังนั้นเมื่อเวลาเท่ากันต้องปฏิเสธ ใช้กติกาเดียวกันในโค้ดและชุดทดสอบ
ข้อกำหนด TOTP ใน RFC 6238 ระบุว่าผู้ตรวจต้องไม่รับ OTP เดิมซ้ำหลังยืนยันสำเร็จครั้งแรก เอกสารนี้นิยามอัลกอริทึม TOTP ที่อิงเวลา ไม่ใช่ข้อกำหนดอายุของรหัสทุกชนิดที่ส่งทางอีเมล สำหรับระบบออก OTP ของคุณ ให้กำหนดอายุและเงื่อนไขการใช้ครั้งเดียวไว้อย่างชัดเจน แทนการยืมช่วงเวลาของ TOTP มาใช้โดยอัตโนมัติ

จะใช้ Mailera อ่าน OTP โดยไม่หยิบรหัสจากรอบก่อนอย่างไร?
Mailera เชื่อมกล่องจดหมายที่คุณมีอยู่ ให้แอปอ่านผ่าน API ได้ แต่ไม่สร้างกล่องจดหมายหรือที่อยู่อีเมลใหม่ให้ เตรียมกล่องจดหมายทดสอบของคุณเองก่อน หากยังไม่ได้วางขั้นตอนอ่านรหัส ดู การอ่าน OTP จากกล่องจดหมายของตนเอง สำหรับภาพรวม
เตรียมสิทธิ์และบริบทก่อนสั่งส่งรหัส
- ไปที่ การตั้งค่า แล้วเลือก สร้าง API key กำหนด ขอบเขตกล่องจดหมาย ให้เป็นกลุ่มที่ใช้ทดสอบ และให้สิทธิ์
readซึ่งเป็นสิทธิ์ที่getOtpต้องใช้ งานอ่านรหัสไม่จำเป็นต้องมีสิทธิ์sendหรือmanage - ก่อนสั่งให้แอปส่ง OTP ให้ชุดทดสอบเก็บตัวระบุรอบทดสอบ ตัวระบุคำขอ กล่องจดหมายปลายทาง และเวลาเริ่มคำขอไว้ เวลาเริ่มนี้ช่วยคัดเลือกอีเมล แต่ไม่ใช่นาฬิกาที่ตัดสินอายุรหัส
- ถ้าคุณควบคุมแม่แบบอีเมล ให้ใส่ตัวระบุคำขอที่ไม่เป็นความลับในหัวเรื่องหรือเนื้อหา เพื่อให้ชุดทดสอบจับคู่กลับไปยังคำขอได้ชัดเจน ผู้ส่งกับหัวเรื่องทั่วไปเพียงอย่างเดียวอาจแยกรอบ A ออกจากรอบ B ไม่ได้
รายละเอียดการใช้ REST API อยู่ใน หน้าสำหรับนักพัฒนา ส่วนขั้นตอนเตรียมการเชื่อมต่ออ่านได้ใน คู่มือรหัสผ่านสำหรับแอปของกล่องจดหมายเอเจนต์ หากใช้ Outlook ให้ดู การอ่านรหัสยืนยัน Outlook ผ่าน API
อ่านรหัส แล้วตรวจว่าเป็นของคำขอใด
GET /mailboxes/{id}/otp เป็น operation getOtp สำหรับอ่าน OTP ล่าสุด และรับพารามิเตอร์ from, subject และ since_minutes ดูรายละเอียดปลายทางใน เอกสาร API ของ Mailera
กำหนด $MAILERA_API_KEY และ $MAILBOX_ID ในสภาพแวดล้อมของคุณก่อนใช้ตัวอย่าง เปลี่ยนผู้ส่งและหัวเรื่องสมมติให้ตรงกับอีเมลทดสอบของคุณ ตัวอย่างนี้ส่ง since_minutes=5
curl --get "https://mailera.app/api/public/v1/mailboxes/$MAILBOX_ID/otp" \
-H "Authorization: Bearer $MAILERA_API_KEY" \
--data-urlencode "from=otp@example.com" \
--data-urlencode "subject=OTP test" \
--data-urlencode "since_minutes=5"เมื่ออ่านรหัสได้ ให้แอปของคุณตรวจคำขอปัจจุบัน เวลาหมดอายุ และสถานะการใช้รหัสแยกต่างหาก คำว่า “ล่าสุด” ไม่ควรเป็นเหตุผลให้ข้ามการจับคู่คำขอ
เมื่อต้องตรวจบริบทเพิ่มเติม ให้อ่านรายการข้อความด้วย GET /mailboxes/{id}/messages ตัวอย่างนี้เลือกโฟลเดอร์กล่องจดหมายเข้าเท่านั้น
curl --get "https://mailera.app/api/public/v1/mailboxes/$MAILBOX_ID/messages" \
-H "Authorization: Bearer $MAILERA_API_KEY" \
--data-urlencode "folder=inbox" \
--data-urlencode "from=otp@example.com"ในผลลัพธ์ data[] มี id, mailbox_id, from, to, subject, received_at และ is_unread ให้ตรวจกล่องจดหมายและคู่ผู้ส่งผู้รับก่อน แล้วใช้หัวเรื่องหรือเนื้อหาจับคู่กับคำขอ หากผลลัพธ์มี next_cursor และยังต้องอ่านต่อ ให้ส่งค่านั้นกลับในพารามิเตอร์ cursor
นำ id ของข้อความที่ต้องตรวจมาใส่ใน $MESSAGE_ID แล้วอ่านเนื้อหา:
curl "https://mailera.app/api/public/v1/mailboxes/$MAILBOX_ID/messages/$MESSAGE_ID" \
-H "Authorization: Bearer $MAILERA_API_KEY"เนื้อหาอยู่ใน data.body.text และ data.body.html ใช้ตัวระบุที่แอปใส่ไว้จับคู่คำขอ ไม่ถือว่า data.id ของอีเมลเป็นตัวระบุคำขอยืนยันโดยอัตโนมัติ และอย่าเก็บผลลัพธ์ทั้งฉบับลงบันทึก CI เพราะอาจมีรหัสจริงอยู่ในเนื้อหา
หากระบุคำขอไม่ได้ ให้หยุดรอบทดสอบพร้อมเหตุผลว่าแยกคำขอไม่ได้ อย่าเดาเลือกรหัส และอย่าย้อนกลับไปหยิบรหัสของรอบก่อนเพื่อให้การทดสอบดำเนินต่อ
กำหนดเวลารอสูงสุดและช่วงเรียกซ้ำไว้ในชุดทดสอบ เมื่อหมดเวลารอให้รายงานว่าไม่พบอีเมลที่จับคู่ได้ แยกจากกรณีที่เซิร์ฟเวอร์ปฏิเสธ OTP สำหรับการนำขั้นตอนนี้ไปใช้กับเบราว์เซอร์ ดู ชุดทดสอบเข้าสู่ระบบด้วย Playwright และกล่องจดหมายเดิม ส่วนการแยกรอบที่ทำงานพร้อมกันอยู่ใน การทดสอบ OTP หลายชุดโดยไม่สลับกล่องจดหมาย
ควรทดสอบกรณีใดเพื่อยืนยันว่า OTP เก่าถูกปฏิเสธ?
แยกผลทดสอบเป็นสองส่วนเสมอ: ชุดทดสอบเลือกอีเมลของคำขอถูกหรือไม่ และเซิร์ฟเวอร์รับหรือปฏิเสธรหัสถูกหรือไม่ การอ่านรหัสได้ไม่ได้หมายความว่าการยืนยันผ่าน และการยืนยันไม่ผ่านก็อาจเกิดจากชุดทดสอบเลือกอีเมลผิด
ตารางนี้ใช้กับนโยบายที่คำขอใหม่แทนที่คำขอเดิม เก็บตัวระบุรอบและเหตุการณ์แทนค่ารหัสจริง
| สถานการณ์ | ลำดับเหตุการณ์ | ผลที่คาดหวัง | หลักฐานที่ต้องเก็บ |
|---|---|---|---|
| รหัสปัจจุบัน | ออกคำขอ อ่านอีเมลที่ตรงกัน แล้วยืนยันก่อนหมดอายุ | ยืนยันสำเร็จครั้งเดียว | คำขอที่จับคู่ได้ ผลยืนยัน และสถานะหลังใช้ |
| รหัสหมดอายุ | ออกรหัส เลื่อนนาฬิกาทดสอบให้พ้นจุดหมดอายุ แล้วส่งรหัส | เซิร์ฟเวอร์ปฏิเสธ | เวลาอ้างอิงฝั่งเซิร์ฟเวอร์และเหตุผลที่ปฏิเสธ |
| รหัสที่ใช้แล้ว | ยืนยันสำเร็จ แล้วส่งรหัสของคำขอเดิมอีกครั้ง | ครั้งถัดไปถูกปฏิเสธ | ผลทั้งสองครั้งและจำนวนการยืนยันสำเร็จ |
| รหัสเดิมหลังขอใหม่ | ออก A แล้วออก B จากนั้นส่งรหัสของ A | A ถูกปฏิเสธ | เหตุการณ์แทนที่คำขอและผลตรวจ A |
| อีเมลมาสลับลำดับ | ออก A แล้ว B แต่ให้อีเมล B ถึงก่อน A | ชุดทดสอบไม่เลือก A ให้คำขอ B | ลำดับที่อีเมลมาถึงและผลจับคู่คำขอ |
| อ่านอีเมลเดิมซ้ำ | อ่านข้อความเดิมอีกหลังยืนยันสำเร็จ | การอ่านซ้ำไม่ทำให้ยืนยันซ้ำสำเร็จ | ตัวระบุข้อความ คำขอ และผลตรวจรับครั้งถัดไป |
| ยืนยันพร้อมกัน | ส่งรหัสเดียวกันของคำขอที่ยังใช้ได้พร้อมกันสองคำขอ | สำเร็จเพียงหนึ่งคำขอ | ผลตอบกลับทั้งคู่และสถานะสุดท้ายในฐานข้อมูล |
| บริบทไม่ตรง | ส่งรหัสพร้อมบริบทผู้ใช้หรือวัตถุประสงค์อื่น | เซิร์ฟเวอร์ปฏิเสธ | บริบทจำลองและผลตรวจรับโดยไม่เก็บรหัส |
สำหรับขอบเวลา ให้ใช้กลไกนาฬิกาที่ควบคุมได้ในตัวตรวจ OTP ของแอป แล้วทดสอบก่อนหมดอายุ ตรงเวลาหมดอายุ และหลังหมดอายุ ตามกติกาตัวอย่าง เฉพาะกรณีก่อนหมดอายุเท่านั้นที่มีสิทธิ์ผ่านเมื่อเงื่อนไขอื่นครบ อย่าใช้การรออีเมลจริงเป็นตัวกำหนดว่าทดสอบขอบเวลาได้ตรงหรือไม่
กรณีส่งพร้อมกันต้องตรวจมากกว่าข้อความตอบกลับ ตรวจด้วยว่ามีการบันทึกความสำเร็จและผลข้างเคียงของการยืนยันเพียงครั้งเดียว ส่วนกรณีอ่านอีเมลซ้ำควรส่งไปยังตัวตรวจของแอปจริงในสภาพแวดล้อมทดสอบ ไม่ใช่เพียงตรวจว่าฟังก์ชันอ่านอีเมลคืนค่าเดิมหรือไม่
ข้อผิดพลาดที่พบบ่อยคืออะไร?
เลือกอีเมลล่าสุดหรืออีเมลที่ยังไม่อ่านอย่างเดียว สถานะ is_unread เป็นข้อมูลของข้อความ อย่าใช้แทนสถานะว่า OTP ยังไม่เคยถูกใช้ ให้จับคู่คำขอและตรวจสถานะการใช้ที่เซิร์ฟเวอร์
พบรหัสแล้วถือว่ายังใช้ได้ หากพบอีเมลจากหลายรอบ ให้แยกด้วยบริบทคำขอ ไม่ใช่เลือกรหัสแรกที่แยกออกมาได้ แล้วให้แอปตรวจเวลาหมดอายุและสถานะการใช้รหัส
ใช้นาฬิกาเครื่องทดสอบตัดสินอายุ OTP ให้เครื่องทดสอบใช้เวลาสำหรับควบคุมการรอ ส่วนอายุรหัสให้ตัวตรวจฝั่งเซิร์ฟเวอร์ตัดสิน เมื่อต้องเปรียบเทียบบันทึกข้ามระบบ ให้ใช้รูปแบบเวลาที่ระบุเขตเวลาอย่างชัดเจน
แยกการตรวจออกจากการบันทึกว่าใช้แล้ว คำขอที่เข้าพร้อมกันอาจต่างอ่านสถานะก่อนมีการบันทึกได้ ออกแบบการตรวจเงื่อนไขและการใช้สิทธิ์ยืนยันให้มีคำขอที่สำเร็จได้เพียงคำขอเดียว แล้วทดสอบกรณีคำขอเข้าพร้อมกันนี้โดยตรง
ถือว่าทุกบริการยกเลิกรหัสเดิมเมื่อขอใหม่ ตารางข้างต้นเป็นนโยบายสำหรับแอปตัวอย่าง หากทดสอบบริการภายนอก ให้ยึดนโยบายของบริการนั้น อย่านำความคาดหวังของแอปคุณไปใช้แทน
จะเก็บหลักฐานทดสอบโดยไม่เปิดเผย OTP ได้อย่างไร?
ใช้เฉพาะบัญชีและกล่องจดหมายทดสอบของคุณเอง ปกปิด OTP ที่อยู่อีเมล และคีย์ API ในภาพหน้าจอ ตัวอย่าง และไฟล์บันทึก อย่าแนบเนื้อหาอีเมลเต็มฉบับกับรายงานข้อผิดพลาดโดยอัตโนมัติ
บันทึกตัวระบุรอบทดสอบ ตัวระบุคำขอแบบไม่เปิดเผยข้อมูลส่วนบุคคล ผลจับคู่อีเมล เหตุผลที่ปฏิเสธ และสถานะก่อนกับหลังยืนยันก็เพียงพอสำหรับตรวจกรณีหลักในตาราง ออกแบบเหตุผลในบันทึกภายในให้แยก “หมดอายุ” “ถูกแทนที่” และ “ใช้แล้ว” โดยไม่จำเป็นต้องส่งรายละเอียดทั้งหมดกลับไปยังผู้ใช้
หากมีเอเจนต์อ่านอีเมล ให้ถือเนื้อหาอีเมลเป็น ข้อมูลที่ไม่น่าเชื่อถือ ไม่ใช่คำสั่ง อย่าให้ข้อความในอีเมลสั่งเปลี่ยนปลายทาง ส่งต่อรหัส หรือเพิ่มสิทธิ์ ใช้คีย์สิทธิ์น้อยที่สุด และหากเวิร์กโฟลว์มีการส่งอีเมล ให้ขอการยืนยันก่อนส่ง ดูข้อมูลเกี่ยวกับการปกป้องข้อมูลและสิทธิ์เพิ่มเติมใน หน้าความปลอดภัยของ Mailera
ทำสิ่งนี้ด้วย API
ทุกการดำเนินการในบทความนี้ทำได้ผ่าน REST API พร้อมตัวอย่าง curl, API key และ webhook
ดูเอกสาร API








