PromptPay.io 2.0

วิสัยทัศน์ของ PromptPay.io คือการเป็น DNS สำหรับเงินโอน ที่ใช้งานง่ายที่สุด ดังนั้นพันธกิจของ 2.0 ก็คือการเปิดให้ทุกคนสามารถตั้งชื่อ username ของตัวเองได้ แปลว่าต้องทำระบบสมัครสมาชิก

ตอนแรกก็นึกไม่ออกว่าจะเขียนระบบสมาชิกให้ใช้งานง่ายๆ โดยไม่ต้องจำ username, password อีกชุด หรือไม่ต้อง validate email ได้ยังไง ทางนึงก็คือใช้ social network OAuth แล้วตั้ง username ตาม social network แต่ก็ต้องมาปวดหัวกับ edge case การเปลี่ยนชื่ออีก สุดท้ายเลยตัดสินใจทำ OTP login แล้วให้จองชื่อกันเองแบบมาก่อนได้ก่อนนี่ล่ะ

การยืนยันตัวตนผ่าน SMS จะมี 2 ขั้นตอน คือ

  1. ส่งเบอร์โทรเพื่อร้องขอให้มีการส่ง OTP มาทาง SMS
  2. ส่ง OTP ที่ได้รับทาง SMS นั้นกลับมาทาง form เพื่อรับ authentication token (คิดแบบบ้านๆ ก็คือ cookie) ที่จะใช้อยู่ในระบบต่อไป

จากสถาปัตยกรรมแบบ serverless ก็นำมาสู่ data structure ที่ stateless ซึ่งสามารถ authenticate ได้จนจบกระบวนการโดยไม่ต้องเก็บ token อะไรไว้ใน database เลย ทำได้ยังไง?

ในขั้นตอนแรก เราใช้ HMAC สร้าง time-based OTP ซึ่งเป็นลายเซ็นที่รับรองเบอร์โทรศัพท์นี้ + เวลานี้ + symmetric key ของ app ไว้ มีเพียง app เราที่สามารถสร้างลายเซ็นนี้ได้ คุณสมบัติของ HMAC คือเมื่อได้ hash ออกมาแล้วจะไม่สามารถคิดย้อนกลับไปหา symmetric key ได้ ถึงแม้ผู้ใช้จะมีข้อมูลชิ้นอื่นๆ ก็ตาม เสร็จแล้วเราจึงนำ hash นี้ไปทำ modulo ให้เหลือเป็นเลข 6 หลัก แล้วส่งไปทาง SMS

TOTP(K, t, id) = H((K’ ⊕ opad || H((K’ ⊕ ipad) || id || t)) mod 10e6

โดยที่ H คือ hash function SHA-256 และ opad/ipad คือค่าคงที่ซึ่งออกแบบมาเพื่อลดโอกาสในการ exploit จุดอ่อนของ H

ในขั้นตอนการยืนยัน OTP เราก็รันกระบวนท่าเดิมซ้ำอีกรอบแล้วเทียบว่าเลขเท่ากันหรือเปล่า ต่างกันที่เวลาจะไม่ตรงกับตอน generate ดังนั้นจึงต้องปัดเศษวินาทีออก (quantization) และเปิดโอกาสให้ใช้ OTP จากช่วงเวลาก่อนๆ ได้ด้วย ยกตัวอย่างเช่นตอน generate อาจจะเป็นเวลา 19:35:57 แต่ตอน verify เป็น 19:36:01 ซึ่งจะมี hash คนละค่ากัน ระบบ TOTP ส่วนมากก็จะเผื่อช่วงเหลื่อมนี้ไว้ 1-2 บล็อก

เมื่อยืนยันตัวตนผ่าน เราก็สร้าง token ที่จะอนุมัติสิทธิ์ในการเรียกใช้ API อื่นๆ มาตรฐานที่ได้รับความนิยมตอนนี้คือ JSON Web Token (jwt.io) การทำงานของมันก็มีหัวใจอยู่ที่ cryptographic hashing เช่นเดียวกัน แต่คราวนี้เป็นการเซ็นรับรองข้อมูลทั้งชุด ว่าผู้ใช้คนนี้เบอร์โทรอะไร ชื่ออะไร เริ่มล็อกอินเวลาใดและอยู่ในระบบได้ถึงกี่โมง ทำให้ client library ตลอดจน API อื่นๆ สามารถเชื่อใจข้อมูลตรงนี้ และนำไปใช้งานได้ทันทีโดยไม่ต้อง query จาก database อีกรอบ

สุดท้ายในขั้นตอนเก็บ username/phone mapping เผลอไปใช้ RDBMS เป็นฐานข้อมูล ถึงรู้ซึ้งว่า serverless ควรเลี่ยงการใช้ SQL เนื่องจากเป็น protocol ที่ใช้เวลา set-up/teardown นาน เมื่อไม่สามารถทำ connection pool ได้ ต้อง reconnect ทุกครั้ง จะแพงค่า execution time แต่ควรไปใช้ NoSQL ที่ยิงคำสั่งผ่าน REST API แทน

ทั้งหมดนี้ serve ผ่าน API Gateway ซึ่งทำให้เราได้ SSL termination + CDN + caching + throttling มาฟรีๆ เหมือนเดิม

ไปลองเล่นกันได้นะครับ ก่อน URL สวยๆ จะหมด ➡️ https://promptpay.io/

 
4
Kudos
 
4
Kudos

Now read this

Single Gateway

คุณคิดวาอะไรคือสิงประดิษฐทีนาอัศจรรยทีสุดทีเคยมีมา? พีระมิด เพนิซิลลิน กระสวยอวกาศ? สำหรับผม ไมวาจะวัดดวยมิติไหน กไมมีอะไรทีนาทึงไปกวาอินเตอรเนต ทุกครังทีไปเทียวทะเล ผมชอบมองไปสุดสายตา บนโลกนีไมมีอะไรกวางกวามหาสมุทร แตความลับคือ ณ ท... Continue →