fintech#1 - QR
Show QR nhận tiền, quét QR chuyển tiền: làm mỗi ngày, nhưng có bao giờ bạn tò mò bên trong nó là gì?
Background
Gần đây bạn có dùng một trong hai tính năng này không: Show QR để nhận tiền, hoặc quét QR để chuyển tiền? Còn mình thì hầu như ngày nào / tuần nào cũng dùng để đi cafe. Nhưng bạn có từng tò mò cơ chế phía sau cái hình QR quen thuộc đó hông.
Back to basic của use case thanh toán trong Fintech. Nếu như xưa, muốn chuyển tiền phải nhập số tài khoản, chọn đúng ngân hàng thụ hưởng, double check tên người nhận…cũng kha khá step. Giờ chỉ cần giơ máy lên, quét, check, bấm xác thực thanh toán. Xong, nhanh, gọn.
Cái mã QR mình quét mỗi ngày, thật ra phía sau nó chỉ là một chuỗi ký tự. Chúng ta thử ngồi soi từng chuỗi ký tự QR (tạm gọi QR payload) của vài ví điện tử lớn.
Bạn thử mở Camera điện thoại, đưa vào một mã QR chuyển tiền bất kỳ (đừng bấm vào link nhé), nó sẽ hiện ra một chuỗi dài ngoằng. Đa số QR chuyển khoản ở Việt Nam hiện nay đều sử dụng chuẩn VietQR. Để dễ hình dung, có thể tách thành ba lớp:
EMVCo là chuẩn quốc tế quy định cách tổ chức dữ liệu của QR thanh toán; VietQR là chuẩn triển khai và thương hiệu nhận diện tại Việt Nam được xây dựng dựa trên EMVCo.
Còn Napas247 là hạ tầng chuyển tiền nhanh liên ngân hàng xử lý giao dịch sau khi người dùng quét QR và xác nhận thanh toán.
Vì vậy, khi thấy logo VietQR, bạn có thể kỳ vọng rằng hầu hết ứng dụng ngân hàng và các đơn vị tham gia hệ sinh thái VietQR đều có thể đọc và xử lý mã QR đó, thay vì bị giới hạn bởi ứng dụng đã tạo ra mã.
Note rõ phạm vi bài này luôn cho khỏi lộn: Mình đang nói về QR nhận tiền, tức bạn show QR ra, người khác quét, tiền chảy vào ví bạn (inflow). Còn QR thanh toán (bạn show QR, merchant quét, tiền chảy ra khỏi ví bạn, outflow) hay QR xuyên biên giới (loại dùng khi đi nước ngoài) là câu chuyện khác, payload khác hẳn, để dành nói ở bài sau.
Go Detail
Mình có 3 cái QR nhận tiền đang dùng thật, đều mang badge VietQR, tạm gọi là ví tím, ví xanh, ví cam. Quét cả ba bằng Camera thường, mỗi cái cho ra một payload khác nhau:
Ví tím (đang để chế độ mặc định, không dùng số đth là stk)
00020101021138630010A000000727013300069710250119PSP26084199000001440208QRIBFTTA53037045802VN62190515MOMOW2W5012160563044525Ví xanh:
00020101021126400010vn.zalopay0115goNSNSsQjnXTpKD020300238620010A00000072701320006970454011899ZP25189M123845830208QRIBFTTA5204739953037045802VN630431BBVí cam:
00020101021138630010A000000727013300069704360119SPAY1262440238206180208QRIBFTTA53037045802VN630432A0Nếu như người bình thường chưa hiểu thì nó là một chuỗi ký tự dài lộn xộn. Nhưng thật ra nó cấu trúc rất rõ ràng, theo chuẩn VietQR (dựa trên EMVCo), được Napas áp dụng cho thị trường Việt Nam.
(Đoạn này hơi kỹ thuật 1 tí) Mỗi cụm là một “id” gồm mã id, độ dài dữ liệu, rồi tới. giá trị. Cứ vậy lặp lại. Bạn cứ đọc từ tuần tự id - độ dài dữ liệu - giá trị (Thông tin bên dưới lấy từ tài liệu kỹ thuật của NAPAS)
Thử khui secret payload của ví tím ra:
00020101021138630010A000000727013300069710250119PSP26084199000001440208QRIBFTTA53037045802VN62190515MOMOW2W501216056304452500 02 01
id
00: Payload Format Indicator, xác định chuẩn QR được sử dụng02: độ dài dữ liệu phía sau là 2 ký tự01: QR tuân thủ chuẩn EMVCo
01 02 11
id
01: Point of Initiation Method, xác định loại QR02: độ dài dữ liệu là 2 ký tự11: QR tĩnh (Static QR). Nếu là12thì QR động (Dynamic QR)
38 63 00 10 A000000727 01 33 00069710250119PSP2608419900000144 02 08 QRIBFTTA
id
38: Merchant Account Information, thông tin định danh và định tuyến giao dịch Napas, phần quan trọng nhất63: tổng chiều dài dữ liệu bên trong là 63 ký tựsub id
00, độ dài10:A000000727là GUID của NapasGUID (Globally Unique Identifier) là mã định danh duy nhất trên phạm vi toàn cầu, dùng để xác định tổ chức hoặc hệ thống chịu trách nhiệm xử lý Merchant Account Information, ở đây là Napas. Trong chuẩn EMVCo: Mỗi Payment Network được cấp một GUID riêng. Khi ứng dụng ngân hàng đọc QR, nó sẽ nhìn GUID để biết phải giải mã dữ liệu theo quy tắc của tổ chức nào.
sub id
01, độ dài33:00 06 971025 01 19 PSP2608419900000144,bên trong còn một lớp con nữasub id
00, độ dài06:971025là PSP ID của ví tímPSP ID (Payment Service Provider ID) là mã định danh của đơn vị cung cấp dịch vụ thanh toán, được Napas cấp hoặc quản lý để nhận diện một ngân hàng, ví điện tử hoặc tổ chức thanh toán trong hệ thống VietQR
Nói đơn giản có thể xem nó là bankcode. Có thể tham khảo thêm tại đây
sub id
01, độ dài19:PSP2608419900000144là mã định danh người nhận do ví tím quản lý (receiver identifier)
sub id
02, độ dài08:QRIBFTTAlà dịch vụ chuyển tiền liên ngân hàng tới tài khoản
53 03 704
id
53: Currency Code, mã tiền tệ giao dịch03: độ dài dữ liệu là 3 ký tự704: Việt Nam Đồng (VND)
58 02 VN
id
58: Country Code, quốc gia phát hành QR02: độ dài dữ liệu là 2 ký tựVN: Việt Nam
62 19 ...
id
62: Additional Data Field Template, thông tin tham chiếu bổ sung19: tổng chiều dài dữ liệu bên trong là 19 ký tựgiá trị bên trong là
MOMOW2W50121605, mã tham chiếu nội bộ của ví tím.
63 04 4525
id
63: CRC, kiểm tra tính toàn vẹn QRCRC (Cyclic Redundancy Check) là một mã kiểm tra lỗi (error detection code) được tính toán từ toàn bộ nội dung QR, nói đơn giản nó giống như “checksum” / Mục đích: Xác mình QR có nguyên vẹn hay đã bị sửa đổi hoặc bị cắt mất dữ liệu, lỗi khi truyền hoặc quét QR trước khi xử lý thanh toán
Có thể tham khảo thêm tại: CRC Calculation online
04: độ dài CRC là 4 ký tự4525: CRC16 của toàn bộ payload
Nếu làm tương tự như trên cho ví cam và ví xanh thì mình sẽ thấy được:
Ví tím và ví cam cấu trúc gần như y hệt, chỉ đổi PSP ID (
970436thay vì971025) và mã định danh người nhận (SPAY126244023820618).Ví xanh thì khác một chút. Trước khi vào tới phần chuẩn Napas (
38), họ chèn thêm một id riêng của họ (26), chứa domain nội bộvn.zalopaycùng mã định danh ví dùng cho hệ sinh thái của họ.
Static QR vs Dynamic QR
Quay lại id 01 lúc nãy bóc tách ở section trước:
01 02 11
id
01: Point of Initiation Method, xác định loại QR02: độ dài dữ liệu là 2 ký tự11: QR tĩnh (Static QR). Nếu là12thì QR động (Dynamic QR)
Giá trị 11 là QR tĩnh, 12 là QR động. Đây chính là chỗ quyết định bạn đang cầm loại QR nào, đáng dừng lại giải thích kỹ hơn một chút.
QR tĩnh thì không có số tiền, ai quét cũng tự nhập tiền, dùng lại được nhiều lần (kiểu QR dán ở quầy, in trên name tag, hay đúng 3 cái QR nhận tiền mình show ở trên). Nói rõ hơn một chút cho dễ hình dung: với QR tĩnh, payload chỉ chứa đúng mã định danh người nhận và ngân hàng thụ hưởng (như đã phân tích ở phần trên), nên khi quét xong, tới trang chuyển tiền, người dùng hoặc hệ thống sẽ phải chủ động điền thêm nội dung chuyển khoản và số tiền
QR động thì có thêm id
54(Transaction Amount), số tiền được khoá sẵn. Payload đã có sẵn cả nội dung chuyển khoản lẫn số tiền, nên tới trang chuyển tiền là thấy điền sẵn hết, chỉ việc xác nhận.
Logic A → B
Khi A quét QR của B để chuyển tiền, hệ thống dựa vào id nào để biết nên xử lý nội bộ hay đẩy qua luồng chuyển tiền liên ngân hàng? Câu trả lời nằm sẵn trong cách EMVCo thiết kế: Một QR có thể chứa nhiều template, mỗi cái đại diện một mạng lưới thanh toán riêng. Id 38 là template của Napas, ai cũng đọc được và dùng cho luồng liên ngân hàng.
Với ví tím, thử tách ra 2 trường hợp cho dễ hình dung:
Nếu người nào đó cũng dùng ví tím, quét QR ví tím của mình: hệ thống ví tím (mình đoán) nhận diện qua id
62, biết ngay đây là chuyển khoản nội bộ, xử lý thẳng trong hệ thống của họ, không cần qua hệ thống chuyển tiền liên ngân hàngNếu người khác dùng ví khác hoặc ngân hàng khác, quét QR ví tím của mình: họ chỉ nhìn vào id
38để biết mã định danh người nhận và ngân hàng thụ hưởng của ví tím. Sau khi ngân hàng thụ hưởng đó nhận tiền thành công qua Napas247, sẽ bắn tín hiệu về hệ thống của ví tím để thông báo và ghi nhận số tiền vào ví.
Với ví xanh thì mình assume logic gần như y hệt, chỉ đổi id dùng để nhận diện nội bộ:
Nếu người khác cũng dùng ví xanh, quét QR ví xanh của mình: hệ thống ví xanh nhận diện qua id
26, cái template riêng họ tự khai báo, biết ngay đây là chuyển khoản nội bộ, xử lý thẳng trong hệ thống của họ.Nếu người khác dùng ví khác hoặc ngân hàng khác, quét QR ví xanh của mình: họ bỏ qua id
26, chỉ đọc id38để biết mã định danh người nhận và ngân hàng thụ hưởng. Sau khi ngân hàng thụ hưởng đó nhận tiền thành công qua Napas247, sẽ bắn tín hiệu về hệ thống của ví xanh để thông báo và ghi nhận số tiền vào ví bạn.
Giờ đảo chiều lại thử xem. Từ nãy tới giờ mình đứng ở vai người tạo QR, tức show QR ra để nhận tiền. Còn nếu đổi vai, mình là người quét, để chuyển tiền cho ai đó, app hiện ra tên người nhận, mã định danh người nhận, ngân hàng...
Không có số điện thoại, hay bất cứ thông tin định danh cá nhân nào trong payload cả. Cái duy nhất có là một mã định danh nội bộ, do mỗi ví tự quản lý (cái này gọi là receiver identifier). Khi app của bạn quét xong, nó gửi mã đó cùng PSP ID lên backend, backend mới đi tra cứu ngược lại xem mã đó ứng với ai, rồi mới trả tên và logo ngân hàng thụ hưởng để hiển thị.
Tức là cái màn hình “đang chuyển tới [Tên người nhận]” mà bạn thấy, hoàn toàn không nằm trong QR. Nó được dựng lên sau, bởi một cuộc gọi API phía sau hậu trường, ngay trong vài trăm mili giây bạn không kịp nhận ra.
Hi vọng sau bài viết này: nếu lần tới giơ điện thoại lên quét QR, chậm lại một vài giây xem, chắc có thể bạn sẽ nhìn nó khác đi một chút.
Hết.





