เมื่อวานนี้ธนาคารแห่งประเทศไทยเปิดตัว 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 จริงที่ผมใช้แกะข้อมูล
on
อยากลองถกเหมือนกัน
ShiRaTo Thu, 31/08/2017 - 05:41
อยากลองถกเหมือนกัน ว่าทำไมต้องสร้าง CRC ใน QR อีก
ในเมื่อ QR ก็มี CRC ในตัวมันเองอยู่แล้ว. ใครมีไอเดียมุมไหนบ้างครับ
ไว้กันกรณีคนแอบเปลี่ยน id
iamfalan Thu, 31/08/2017 - 07:35
In reply to อยากลองถกเหมือนกัน by ShiRaTo
ไว้กันกรณีคนแอบเปลี่ยน id บัตรคนรับเงินมั้งครับ
แต่คงกันไม่ได้เท่าไหร่
น่าจะเอาไว้เช็คกันผิดพลาดระดั
Hadakung Thu, 31/08/2017 - 07:46
In reply to อยากลองถกเหมือนกัน by ShiRaTo
น่าจะเอาไว้เช็คกันผิดพลาดระดับแอพพิเคชั่นนะครับคงคิดว่าข้อมูลอาจจะผิดพลาดระหว่างกระบวนการไหนก็ได้เลยต้องใส่ไปจนระดับ end to end เลย
QR มี error correction
bungbui Fri, 01/09/2017 - 23:43
In reply to อยากลองถกเหมือนกัน by ShiRaTo
QR มี error correction อยู่แล้ว
และรายละเอียดผู้รับเงินปลายทาง คนจ่ายควรจะเช็คก่อนอยู่แล้ว ว่ากำลังโอนเงินไปไหน
หากมีการ fraud ก็ใส่ CRC มาเองได้อยู่ดี ไม่ได้ช่วยยืนยันอะไร
ผมคิดว่าไม่จำเป็นต้องมีนะครับ
ผมคิดว่า CRC
lew Sat, 02/09/2017 - 00:06
In reply to QR มี error correction by bungbui
ผมคิดว่า CRC มีไว้เพื่อยืนยันว่ามันเป็น QR ของ EMVco ครับ ไม่ใช่ QR อื่นๆ ที่บังเอิญ parse ผ่านพอดี
ใน Paper
foizy Sat, 02/09/2017 - 03:24
In reply to QR มี error correction by bungbui
ใน 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] ในเรื่องอื่นๆเยอะล่ะมั๊ง
ต่อไปคงไม่มีแล้วขอทงขอทาน
MaylinZ Thu, 31/08/2017 - 07:15
ต่อไปคงไม่มีแล้วขอทงขอทาน อยากได้ตังก็ปริ๊นสติกเกอร์ QR ไปติดข้างเสาไฟฟ้าดื้อๆเลย บริจาคตามกำลังศรัทธา
ติดเสาไฟเฉยๆคงไม่มีใครให้
gosol Thu, 31/08/2017 - 09:20
In reply to ต่อไปคงไม่มีแล้วขอทงขอทาน by MaylinZ
ติดเสาไฟเฉยๆคงไม่มีใครให้ ขอทานจีนเขาเดินไปยื่น QR code ให้สแกนบริจาคเลยครับ จะได้มี impact แต่พวกขอทานต่างด้าว,ขอทานฝรั่งคงยังรับเศษเงินอยู่
วณิพก 4.0
impascetic Thu, 31/08/2017 - 09:54
In reply to ต่อไปคงไม่มีแล้วขอทงขอทาน by MaylinZ
วณิพก 4.0
วณิพก ไม่ได้ขอเฉยๆ
Floating Rotten Dog Fri, 01/09/2017 - 02:13
In reply to วณิพก 4.0 by impascetic
วณิพก ไม่ได้ขอเฉยๆ แต่มีการแสดงแลกเงินครับ อาจจะเพิ่มคิวอาร์โค้ดสำหรับลิ้งก์ให้เข้าไปฟังเพลงออนไลน์
02 หมายเลขบัตรประชาชน ความยาว
raykichi Thu, 31/08/2017 - 08:16
02 มีความยาวแค่ 13 หลัก และไม่มี 00 นำหน้า
สรุปข้อมูลข้างในก็คือ
azpirin Thu, 31/08/2017 - 16:06
สรุปข้อมูลข้างในก็คือ รหัสบัตรประชาชน/เบอร์โทร สินะ นึกว่าจะได้ตัวเลือกที่ 3 เพิ่มมาให้ใช้ซะอีก
หมายเลขประจำตัวผู้เสียภาษีใช้
gd_ab Fri, 01/09/2017 - 08:55
In reply to สรุปข้อมูลข้างในก็คือ by azpirin
หมายเลขประจำตัวผู้เสียภาษีใช้ 02 เหมือนกันกับเลขประจำตัวประชาชนครับ
ลองมาแล้ว
ตัวเลือกอื่นจะมี eWallet ID
lew Fri, 01/09/2017 - 15:40
In reply to สรุปข้อมูลข้างในก็คือ by azpirin
ตัวเลือกอื่นจะมี eWallet ID เพิ่มมาครับ ตอนนี้ยังไม่รู้ว่าจะเป็นเบอร์โทรผม (แต่ผมเชื่อว่าไม่ใช่นะ เพราะ LINE ก็ไม่ได้ผูกกับเบอร์โทรเดียว)
พยายามเขียนอธิบายคนอื่น
bioice Sat, 02/09/2017 - 03:01
พยายามเขียนอธิบายคนอื่น
ลิงค์สอน
อยากให้มีข้อมูลมากกว่านี้แฮะ
EThaiZone Sat, 02/09/2017 - 15:37
อยากให้มีข้อมูลมากกว่านี้แฮะ เช่น callback หรือ product
/me กำลังเมาโค้ด
จริงๆ
lew Mon, 04/09/2017 - 11:27
In reply to อยากให้มีข้อมูลมากกว่านี้แฮะ by EThaiZone
จริงๆ มีข้อมูลสินค้าแบบเดียวกับบัตรเครดิตครับ พวก merchant type ทั้งหลาย แต่ผมยังไม่เห็นว่ามีใครเอาไปใช้อะไร
เคยเห็นร้านอาหารที่ปริ้น QR
444poon Thu, 21/03/2019 - 00:27
Tag29 สามารถพ่วง Ref เข้าไปได้บ้างไหมครับ นอกจากใช้ระบบเศษสตางค์
เรื่องเบอร์โทร กับ
gift099 Mon, 11/02/2019 - 09:02
เรื่องเบอร์โทร กับ เลขบัตรประชาชนก็เรื่องนึง
อีกเรื่องคือ คนขาย ก็เห็นชื่อ นามสกุลของเรา ตอนที่เราจ่ายด้วย อันนี้ผมไม่ค่อยชอบนะ