เมื่อวานนี้ธนาคารแห่งประเทศไทยเปิดตัว PromptPay QR แต่การใช้งานก็ยังจำกัดบางพื้นที่โดยต้องใช้แอปพลิเคชั่นของธนาคารในการสร้างตัว QR อย่างไรก็ดี PromptPay QR นี้เป็นมาตรฐานเปิดของ EMVco ที่เปิดให้อ่านฟรีโดยไม่ต้องเป็นหน่วยงานที่เกี่ยวข้องแต่อย่างใด เอกสารฉบับนี้คือ "EMVCo QR Code Specification for Payment Systems: Merchant-Presented Mode" หรือสเปคสำหรับการสร้าง QR จากฝั่งผู้ขายเพื่อขอรับเงินจากผู้รับ
ตอนนี้เราจะมาดูกันว่าข้อมูลใน QR นี้มีข้อมูลอะไรบ้าง อย่างไรก็ดีบทความนี้ข้ามข้อมูลที่ยังไม่สามารถหาได้ จากการดู QR ที่เปิดเผยออกมา

หากเราสแกน QR ที่ใช้จ่ายเงินตอนนี้ด้วยแอปพลิเคชั่นสแกน QR โดยเฉพาะ ไม่ใช่แอปของธนาคาร จะเห็นตัวเลขและข้อความยาวๆ เป็นชุดเดียว เช่นตัวอย่าง "00020101021129370016A000000677010111011300660000000005802TH530376463048956" (ตัวอย่างนี้ใช้ข้อมูลหลอก ด้วยหมายเลขโทรศัพท์ 000-000-0000)
แนวทางการอ่านข้อมูลของมาตรฐาน EMVco คือ หมายเลขประจำฟิลด์ข้อมูล (เป็น 00-99), ความยาวของข้อมูลในฟิลด์นั้น (เป็น 01-99), และตัวข้อมูลจริงๆ การอ่านข้อมูลตัวอย่างจะทำเป็นขั้นได้ดังนี้
- หมายเลขเวอร์ชั่น ฟิลด์ 00 ความยาว 02 ข้อมูลตอนนี้คือ 01 เสมอ ดังนั้นข้อมูลชุดแรกคือ "000201"
- ประเภทของ QR ฟิลด์ 01 ความยาว 02 ข้อมูล "11" แปลว่า QR นี้สร้างขึ้นเพื่อใช้สำหรับการขายหลายครั้ง เช่นระบุผู้ขาย หรือระบุราคาสินค้า ถ้าเป็น 12 คือ QR สร้างขึ้นเพื่อใช้ครั้งเดียว เช่น เป็นการจ่ายสำหรับใบเสร็จใบเดียว
- ข้อมูลผู้ขาย (merchant account information) ฟิลด์ 29 ความยาว 37 ข้อมูล "0016A00000067701011101130066000000000" โดยข้อมูลนี้แบ่งออกเป็นสองฟิลด์ย่อย
- หมายเลขแอปพลิเคชั่น (application ID - AID) เป็นหมายเลขที่ปกติแล้วใช้อ้างอิงประเภทบัตรสมาร์ตการ์ดแบบต่างๆ ตั้งแต่บัตรประชาชนไปจนถึงบัตรเครดิตทั้งหลาย ในกรณีนี้มีการนำหมายเลขนี้มาใช้ใน QR เพื่อระบุว่า QR นี้เป็น PromptPay หมายเลขฟิลด์ย่อย 00 ความยาว 16 ข้อมูล "A000000677010111"
- หมายเลขบัญชี เป็นหมายเลข PromptPay โดยตรง ตอนนี้มีหมายเลขฟิลด์ เช่น
- 01 หมายเลขโทรศัพท์ ความยาว 13 นำหน้าด้วย 00 แล้วตามด้วยรหัสประเทศ 66 แล้วจึงเป็นหมายเลขโทรศัพท์ตัดศูนย์นำหน้าออก 00-000-0000
- 02 หมายเลขบัตรประชาชนไม่มีขีดคั่น
- ประเทศ ฟิลด์ 58 ความยาว 02 ข้อมูล "TH" หมายถึงประเทศไทย
- สกุลเงินที่ใช้งาน ฟิลด์ 53 ความยาว 03 ข้อมูล "764" โดยหมายเลข 764 เป็นหมายเลขประจำค่าเงินบาทตาม ISO 4217
- ค่า check sum ฟิลด์ 63 ความยาว 04 ข้อมูล "8956" ข้อมูลนี้ต้องอยู่ท้ายสุดเสมอ โดยค่า check sum เป็นการคำนวณจากข้อมูลทั้งหมด รวมถึงหมายเลขฟิลด์ของ check sum และความยาวของฟิลด์ check sum เอง กระบวนการหาค่า check sum ใช้ CRC-16 และ ค่าคงที่ polynomial 0x1021 (XMODEM) พร้อมกับค่าเริ่มต้น 0xFFFF (อันนี้ต้องระวังเพราะไลบรารีส่วนมากมักใส่ค่าเริ่มต้นเป็น 0x0000) ตัวไลบรารีสามารถใช้ pycrc16 ได้โดยตรง
ตัวอย่างการหาค่า check sum ด้วย crc16pure.py เช่น
In [7]: hex(crc16pure.crc16xmodem("00020101021129370016A000000677010111011300660000000005802TH53037646304",0xffff))
Out[7]: '0x8956'
สังเกตว่าหมายเลขฟิลด์กระโดดจาก 01 ซึ่งเป็นฟิลด์บังคับ ไปยัง 29 ทันที เพราะหมายเลข 02-25 นั้นสงวนไว้สำหรับผู้ให้บริการบัตรเครดิตโดยเฉพาะ เช่น 02-03 สำหรับ VISA, 04-05 สำหรับ Mastercard, 06-08, 11-12 สำหรับ Amex, 13-14 สำหรับ JCB, และ 15-16 สำหรับ UnionPay ที่เหลือทาง EMVco ก็ให้เว้นไว้สำหรับการใช้งานในอนาคต
เราได้ข้อมูลหลายอย่างจากการดูว่ามีข้อมูลอยู่ใน QR เช่น
- ตัว QR ยังคงแสดงข้อมูลหมายเลข PromptPay เช่นเดิม ซึ่งอาจจะหมายถึงหมายเลขโทรศัพท์หรือหมายเลขบัตรประชาชน หากใครมีความไม่สะดวกใจที่จะให้หมายเลขทั้งสองกับผู้ซื้อก็อาจจะต้องระวัง
- QR เหล่านี้ไม่มีกระบวนการยืนยันว่าสร้างโดยใคร ที่จริงแล้วตอนนี้ทาง Digio ก็เปิดเว็บสร้าง QR PromptPay แล้ว เท่าที่ทดสอบสามารถใช้ได้กับ PromptPay ทุกธนาคาร ความเสี่ยงมีอยู่บ้างคือธนาคารเองก็ไม่สามารถตรวจสอบได้ว่ามีการสร้าง QR ไปแปะทับเพื่อขโมยเงินกันหรือไม่ ดังนั้นการจ่ายเงินควรตรวจสอบชื่อบัญชีของผู้รับเสมอว่าตรงกับคนที่เราต้องการจ่ายไป
- มีความเป็นไปได้ที่จะสร้าง QR เหล่านี้โดยอัตโนมัติ ในเร็วๆ นี้เราคงได้เห็นไลบรารีโอเพนซอร์ส หรือบริการต่างๆ เพื่อสร้าง QR ทั้งระบุและไม่ระบุจำนวนเงิน ความเป็นไปได้อื่นๆ ของบริการนี้คงมีอีกมาก เช่นร้านค้าออนไลน์อาจจะเริ่มรับเงินผ่าน PromptPay กันมากขึ้นเพราะสามารถส่ง QR ระบุจำนวนเงินไปในแชตหรือเว็บอีคอมเมิร์ชได้โดยตรง
ข้อมูลเปิดเผย: Digio เป็นผู้ลงประกาศหางานบน Blognone แบบเด่นพิเศษ แต่บทความนี้เขียนโดยไม่ได้มีการติดต่อกันมาก่อน (ผมพบโพสประกาศหลังเริ่มเขียนบทความไปแล้ว) อย่างไรก็ดี QR ตัวอย่างสร้างโดยเว็บของ Digio เพื่อปิดบัง QR จริงที่ผมใช้แกะข้อมูล
Comments
อยากลองถกเหมือนกัน ว่าทำไมต้องสร้าง CRC ใน QR อีก
ในเมื่อ QR ก็มี CRC ในตัวมันเองอยู่แล้ว. ใครมีไอเดียมุมไหนบ้างครับ
ไว้กันกรณีคนแอบเปลี่ยน id บัตรคนรับเงินมั้งครับ
แต่คงกันไม่ได้เท่าไหร่
น่าจะเอาไว้เช็คกันผิดพลาดระดับแอพพิเคชั่นนะครับคงคิดว่าข้อมูลอาจจะผิดพลาดระหว่างกระบวนการไหนก็ได้เลยต้องใส่ไปจนระดับ end to end เลย
QR มี error correction อยู่แล้ว
และรายละเอียดผู้รับเงินปลายทาง คนจ่ายควรจะเช็คก่อนอยู่แล้ว ว่ากำลังโอนเงินไปไหน
หากมีการ fraud ก็ใส่ CRC มาเองได้อยู่ดี ไม่ได้ช่วยยืนยันอะไร
ผมคิดว่าไม่จำเป็นต้องมีนะครับ
ผมคิดว่า CRC มีไว้เพื่อยืนยันว่ามันเป็น QR ของ EMVco ครับ ไม่ใช่ QR อื่นๆ ที่บังเอิญ parse ผ่านพอดี
lewcpe.com, @wasonliw
ใน Paper
The CRC (ID "63") is the last object under the root and
allows the mobile application to check the integrity of the data scanned without having to parse all of the data objects.
หลักๆแล้วผมว่าเค้าอาจจะมองว่า
QR-CRC มันทำให้รู้ล่ะ ว่าสแกนมาถูกแน่ๆ แต่การแสกนถูก ไม่ได้บอกว่าเป็น EMV QR ที่ถูกต้อง เลยสร้าง EMV-CRC ซ้ำมาอีกที เพื่อให้เช็คได้เลยตั้งแต่เห็น Message ว่าข้อความที่สแกนมา เป็น EMVQR .. ถ้า Field นี้ผิดก็ผิด
ออกแนวเป็น Validation(Hash-Check) มากกว่า error detection(CRC) นะครับ ..
อาจจะเพราะว่ามันเป็นตัวเลขเกือบๆล้วนๆ(ALNUM) มีโอกาสที่การ Parse แล้วเช็คยาก
เช่นตัวอย่างในโพสต์นี่ ถ้าไม่มี CRC ให้เช็คก่อน เราก็จะไม่รู้เลยจนกว่าจะ Parse ครบหมด ว่า string ที่สแกนมาได้นั้นถูกหรือผิด
หรือไม่ก็จริงๆมันอาจจะมีโอกาสเจอตัวเลขที่คล้ายคลึงกับ [Type][Length][Data] ในเรื่องอื่นๆเยอะล่ะมั๊ง
ต่อไปคงไม่มีแล้วขอทงขอทาน อยากได้ตังก็ปริ๊นสติกเกอร์ QR ไปติดข้างเสาไฟฟ้าดื้อๆเลย บริจาคตามกำลังศรัทธา
ติดเสาไฟเฉยๆคงไม่มีใครให้ ขอทานจีนเขาเดินไปยื่น QR code ให้สแกนบริจาคเลยครับ จะได้มี impact แต่พวกขอทานต่างด้าว,ขอทานฝรั่งคงยังรับเศษเงินอยู่
วณิพก 4.0
วณิพก ไม่ได้ขอเฉยๆ แต่มีการแสดงแลกเงินครับ อาจจะเพิ่มคิวอาร์โค้ดสำหรับลิ้งก์ให้เข้าไปฟังเพลงออนไลน์
02 มีความยาวแค่ 13 หลัก และไม่มี 00 นำหน้า
สรุปข้อมูลข้างในก็คือ รหัสบัตรประชาชน/เบอร์โทร สินะ นึกว่าจะได้ตัวเลือกที่ 3 เพิ่มมาให้ใช้ซะอีก
หมายเลขประจำตัวผู้เสียภาษีใช้ 02 เหมือนกันกับเลขประจำตัวประชาชนครับ
ลองมาแล้ว
ตัวเลือกอื่นจะมี eWallet ID เพิ่มมาครับ ตอนนี้ยังไม่รู้ว่าจะเป็นเบอร์โทรผม (แต่ผมเชื่อว่าไม่ใช่นะ เพราะ LINE ก็ไม่ได้ผูกกับเบอร์โทรเดียว)
lewcpe.com, @wasonliw
พยายามเขียนอธิบายคนอื่น
ลิงค์สอน
อยากให้มีข้อมูลมากกว่านี้แฮะ เช่น callback หรือ product
/me กำลังเมาโค้ด
มันไม่ง่ายเลยที่จะทำ GIF ให้มีขนาดน้อยกว่า 20kB
จริงๆ มีข้อมูลสินค้าแบบเดียวกับบัตรเครดิตครับ พวก merchant type ทั้งหลาย แต่ผมยังไม่เห็นว่ามีใครเอาไปใช้อะไร
lewcpe.com, @wasonliw
Tag29 สามารถพ่วง Ref เข้าไปได้บ้างไหมครับ นอกจากใช้ระบบเศษสตางค์
เรื่องเบอร์โทร กับ เลขบัตรประชาชนก็เรื่องนึง
อีกเรื่องคือ คนขาย ก็เห็นชื่อ นามสกุลของเรา ตอนที่เราจ่ายด้วย อันนี้ผมไม่ค่อยชอบนะ