CBOR Encoder & Decoder: แปลง JSON เป็น Binary และกลับ (RFC 8949)
เรียนรู้วิธี encode และ decode CBOR ฟอร์แมต binary JSON ที่อยู่เบื้องหลัง WebAuthn, COSE และ IoT พร้อมเครื่องมือ CBOR encoder/decoder ออนไลน์ฟรี
Table of Contents
ถ้าเคยเปิดดู WebAuthn registration response, แกะ COSE key หรือทำงานกับอุปกรณ์ IoT ที่คุยผ่าน CoAP คุณคงเจอ CBOR มาแล้ว CBOR (Concise Binary Object Representation) ตามมาตรฐาน RFC 8949 คือคำตอบของโลก internet ต่อคำถามง่ายๆ ว่า "ถ้าเอา JSON มาออกแบบใหม่ให้เป็น format สำหรับ machine ล้วนๆ จะหน้าตาเป็นอย่างไร" ผลลัพธ์คือ binary format ที่เก็บ data model เดียวกับ JSON — object, array, string, number, boolean, null — แต่กินพื้นที่น้อยกว่าหลายเท่า
ปัญหาคือ binary data อ่านยาก CBOR payload ที่วิ่งมาถึงมือเรามักเป็น hex string ตาบอดๆ อย่าง a36568656c6c6f65776f726c64 การจะแกะดูข้างในต้องพึ่ง library ในโปรเจกต์ หรือไม่ก็ต้องมี decoder ที่เชื่อถือได้ นี่คือเหตุผลที่เราสร้าง CBOR Encoder / Decoder ฟรีไว้ให้ — วาง JSON แล้วได้ CBOR bytes ทั้งแบบ hex และ Base64 หรือวาง CBOR bytes แล้วได้ JSON ที่อ่านรู้เรื่อง จบในหน้าเดียว
ทุกอย่างทำงาน client-side ใน browser ของคุณ encoder และ decoder เขียนด้วย pure JavaScript ตาม RFC 8949 โดยตรง payload ไม่เคยออกจากเครื่องคุณเลย ซึ่งสำคัญมากเมื่อคุณกำลัง debug ข้อมูล authentication จริงหรือ protocol ของอุปกรณ์ที่เป็นความลับทางการค้า
ทำไมต้องใช้ CBOR?
- Payload เล็กลงมาก CBOR ประหยัดพื้นที่ 40–60% เทียบกับ JSON ข้อมูลชุดเดียวกัน ไม่มี quote ครอบ key ไม่มี colon หรือ comma คั่น element และ integer ขนาดเล็กบีบเหลือ byte เดียว บนอุปกรณ์ IoT ที่ใช้แบตเตอรี่หรือเน็ตแบบ metered ส่วนต่างนี้สะสมเป็นเงินเป็นเวลาจริงๆ
- WebAuthn และ FIDO2 ใช้เป็นหลัก passkey และ security key คุยกันด้วย CBOR โดยตรง field attestationObject และ authenticatorData ในพิธี registration ของ WebAuthn ทุกครั้งเป็น CBOR map ใครทำระบบ login แบบไร้รหัสผ่านต้องอ่าน CBOR เป็นประจำ
- COSE และ CWT สร้างทับบนนี้ COSE (RFC 9052) นิยาม object ที่ sign/encrypt ได้บน CBOR ส่วน CBOR Web Token (CWT, RFC 8392) คือน้อง binary ของ JWT — นิยมใน environment จำกัดทรัพยากรที่ overhead ของ JWT แพงเกินไป
- เป็น codec มาตรฐานของ CoAP และ IoT Constrained Application Protocol (RFC 7252) จับคู่กับ CBOR อย่างเป็นธรรมชาติ ทีม sensor network, smart meter และ embedded firmware ใช้เป็น serialization เริ่มต้น (default)
- มี binary-native types ที่ JSON ไม่มี CBOR มี byte string แท้ๆ, half-precision float, integer 64-bit เกินขอบเขต safe ของ JavaScript และ tag สำหรับค่าเชิง semantic อย่าง timestamp — อย่างที่ JSON ต้องเจอ workarounds แบบ Base64-in-string ที่สูญเสียความหมาย
- Deterministic encoding สำหรับการ sign CBOR รองรับรูปแบบ canonical (deterministic) อย่าง dCBOR ที่ค่าเดียวกันได้ bytes เดียวกันเสมอ — จำเป็นสำหรับ digital signature เพราะ encoder สองตัวไม่ตรงกันแม้แต่ byte เดียวก็พังการ verify ทั้งหมด
ฟีเจอร์เด่น
| ฟีเจอร์ | ทำอะไร |
|---|---|
| Encode JSON → CBOR | แปลง JSON document ใดๆ เป็น CBOR bytes |
| Decode CBOR → JSON | แกะ hex หรือ Base64 CBOR กลับเป็น JSON ที่อ่านได้ |
| Output สองมุมมอง | โหมด encode แสดง Base64 และ hex คู่กัน โหมด decode แสดง JSON และ hex bytes ต้นทาง |
| รองรับ major type ครบ | integer (รวมค่าลบและช่วง BigInt), byte string, text string, array, map, tag และ simple value |
| Float ทุกขนาด | half-precision (f16), single-precision (f32) และ double-precision (f64) |
| 100% client-side | implement RFC 8949 ด้วย pure JavaScript ไม่มีการ upload ไม่มี server round-trip |
สองจุดนี้อธิบายเพิ่ม หนึ่ง byte string รอดผ่านการ decode ได้ครบถ้วน — ถูก render เป็น object ที่มี field __cbor_bstr__ (Base64) และ __cbor_hex__ (hex) แทนที่จะถูกบีบผ่าน UTF-8 จนเพี้ยน สอง ถ้า map ใช้ byte string เป็น key เครื่องมือจะแสดงแบบ diagnostic notation (h'...') ซึ่งเป็นรูปแบบเดียวกับที่ตัวอย่างใน RFC 8949 ใช้ — สิ่งที่คุณเห็นคือสิ่งที่ spec เขียน
error handling ก็แม่นยำ แทนที่จะบอกแค่ "parse failed" decoder จะรายงานว่า unexpected end of CBOR input หรือ byte string length out of range ซึ่งชี้ไปที่ payload ถูกตัด หนึ่งในสาเหตุที่พบบ่อยที่สุดเวลา copy hex ด้วยมือ
วิธีใช้งาน
- เลือกโหมด สลับระหว่าง Encode และ Decode ด้วยปุ่มสองปุ่มด้านบนของเครื่องมือ
- วาง input โหมด Encode วาง JSON document เช่น {"hello": "world"} โหมด Decode วาง CBOR bytes แบบ hex string หรือ Base64
- รัน conversion เครื่องมือ parse input ทันที และแจ้งเตือนเมื่อ JSON ผิด format หรือ byte sequence ไม่ valid ด้วยข้อความ error เฉพาะเจาะจง
- อ่าน output ทั้งสอง โหมด Encode ได้ CBOR bytes เป็น Base64 และ hex โหมด Decode ได้ JSON พร้อม hex view ของ bytes ที่ป้อนเข้าไป
- Copy ผลลัพธ์ คัดลอก representation ที่ต้องการไปใช้ใน code, test fixture หรือ bug report ได้ทันที
เข้าใจ CBOR: Major Types และการ Encode
โครงสร้างทั้งหมดของ CBOR ตั้งอยู่บน eight major types แต่ละอันระบุด้วยบิตสามตัวบนสุดของ byte แรก (initial byte):
| Major type | ค่า | แทนสิ่งใด |
|---|---|---|
| 0 | 0–7 | Unsigned integer |
| 1 | 8–15 | Negative integer |
| 2 | 16–23 | Byte string |
| 3 | 24–31 | UTF-8 text string |
| 4 | 32–39 | Array |
| 5 | 40–47 | Map (คู่ key-value) |
| 6 | 48–55 | Tag (หมายเหตุเชิง semantic) |
| 7 | 56–63 | Simple value และ float |
บิตที่เหลืออีกห้าตัวของ initial byte เก็บ "additional information" — จะเป็นค่า argument ตรงๆ (สำหรับเลขเล็ก) หรือความยาวของมัน ค่า 0–23 เก็บ inline ในตัว 24 แปลว่า "ตามด้วย byte เพิ่มอีกหนึ่ง" 25 แปลว่าสอง byte (ใช้กับ half-precision float ด้วย) 26 แปลว่าสี่ byte (single-precision float) และ 27 แปลว่าแปด byte (double-precision float และ integer 64-bit)
ตัวอย่างจริงทำให้เห็นภาพ เอา {"hello": "world"}:
a1 map ที่มี 1 คู่ 65 text string ยาว 5 bytes 68656c6c6f "hello" 65 text string ยาว 5 bytes 776f726c64 "world"
byte แรก 0xa1 คือ major type 5 (map) ที่มีความยาว 1 จากนั้น 0x65 คือ major type 3 (text) ที่มี payload 5 bytes — คือ hex ของ "hello" และ value ก็เป็น pattern เดียวกันสำหรับ "world" รวมแล้ว 13 bytes เทียบกับ 17 bytes ของ JSON text และช่องว่างจะถ่างขึ้นเรื่อยๆ เมื่อ document ใหญ่ขึ้น เพราะ JSON ต้องจ่ายค่า quote, colon และ comma ให้ทุก element
integer แสดงการบีบอัดได้ชัดกว่านั้น เลข 42 ใส่ได้ในบิต additional-information ล้วนๆ: การ encode ทั้งหมดคือ byte เดียว 0x2a (major type 0, ค่า 42 inline) — ไม่มีเครื่องหมายลบ ไม่มีเลขฐานสิบ ไม่มีตัวคั่น
float ทำตามกฎ preferred-encoding ของ RFC 8949: ใช้ความกว้าง float ที่สั้นที่สุดที่ยังคงค่าได้ decoder รองรับครบทั้งสามขนาด (f16, f32, f64) และ integer ใหญ่ที่เกิน Number.MAX_SAFE_INTEGER ของ JavaScript จะผ่านทาง BigInt ทำให้ ID หรือ timestamp แบบ 64-bit ไม่หาย precision แบบเงียบๆ
Use Cases ในทางปฏิบัติ
Debug การ register และ authenticate ของ WebAuthn
เวลา passkey registration พัง วิธีวินิจฉัยเร็วสุดคือ decode attestationObject ทำ base64-url-decode ก่อน (Base64 Encoder จัดการขั้นนี้ได้) แล้ววาง bytes ลง CBOR decoder ในรูป hex คุณจะเห็น map key สามตัวตามคาด — fmt, attStmt และ authData — พร้อม authenticator data ซ้อนข้างใน ที่ซึ่งคุณตรวจ flags, signature counter และความยาว credential ID ได้ แทนที่จะเดาว่า layer ไหนพัง
ตรวจ COSE key และ CWT token
COSE public key (labeled map ที่มี key type, algorithm และ curve parameter) และ CWT claims set เป็น CBOR ทั้งคู่ ถ้าคุณกำลัง integrate security library หรือ validate token จากอุปกรณ์ constrained การ decode payload จะเผย algorithm identifier และ claim label ที่เป็นตัวเลข ให้คุณเทียบกับ IANA registry ได้ทันที แทนที่จะเชื่อ error message ของ framework ตาบอดๆ
ลดขนาด payload ของ IoT และ CoAP
ทีม firmware ย้าย sensor telemetry จาก JSON ไป CBOR เป็นกิจวัตร เพื่อยัด message ให้พอใน network frame เดียว ค่าอ่านทั่วไปอย่าง {"temp": 22.5, "hum": 61, "batt_mv": 3310} หดจากราว 40 bytes เหลือไม่ถึง 20 ใช้ encoder แปลง JSON schema เป็น CBOR วัดจำนวน byte จริงจาก hex output และยืนยันส่วนต่างก่อนแก้ firmware
ตรวจ binary API response และ test fixture
ถ้า backend คุณตอบ CBOR (พบบ่อยใน stack ใกล้ gRPC, device gateway หรือ HTTP + CBOR API) วาง response ที่ capture ไว้ลง decoder เพื่อเช็คชื่อ field และค่าระหว่างพัฒนา แล้วใช้ encoder ในทิศตรงข้ามสร้าง fixture bytes สำหรับ unit test — โดย hex view ทำหน้าที่เป็น source of truth ของ expected bytes
Best Practices
- ตรวจ hex input ให้ดีทุกครั้ง hex string ที่ copy ด้วยมือหายไป byte เดียวก็ตัด payload และเลื่อนการ parse ทั้งหมด ถ้า decoder แจ้ง unexpected end of CBOR input ให้นับ bytes ก่อนสรุปว่าข้อมูลเสียหาย
- เลือก deterministic encoding ตอน sign ถ้า bytes จะเข้า digital signature ให้ encode ตามกฎ Core Deterministic Encoding (หรือ dCBOR) เพื่อให้ encoder ทุกตัวได้ bytes ตรงกันเป๊ะ ความสะดวกแบบ round-trip เหมาะกับการ debug แต่ signature ต้องการความ deterministic
- เคารพ preferred float encoding RFC 8949 แนะนำ float ที่สั้นที่สุดที่ round-trip ได้ encoder ที่ยิง f64 เสมอทำ payload ใหญ่โดยไม่จำเป็น และอาจพัง interop กับ validator เข้มงวดบนอุปกรณ์ constrained
- เก็บ byte string เป็น bytes อย่าแปลงข้อมูล binary เป็น UTF-8 string ก่อน encode — วิธีนั้นทำลาย byte ที่ไม่ใช่ ASCII ให้ใช้ CBOR byte string (major type 2) ตรงๆ ซึ่งเป็นสิ่งที่ output __cbor_bstr__/__cbor_hex__ ของเครื่องมือนี้รักษาไว้ให้
- ระวังขอบเขต integer ค่าเกิน 2^53 เสีย precision ใน JavaScript number ธรรมดา ใช้เครื่องมือที่รองรับ BigInt (decoder ตัวนี้รองรับ) เมื่อต้องจัดการ ID หรือ timestamp แบบ 64-bit
- Round-trip test payload ของคุณ encode JSON แล้ว decode ผลลัพธ์กลับ แล้วเทียบกัน ถ้าไม่ตรงแปลว่ามีปัญหา type assumption — มักเป็น byte string ถูกบังคับเป็น text หรือปัญหา float precision — เจอที่โต๊ะดีกว่าเจอใน production
เริ่ม Encode และ Decode CBOR วันนี้
binary format ไม่น่ากลัวอีกต่อไปเมื่อคุณมองเห็นข้างในได้ ไม่ว่าจะไล่ WebAuthn attestation ตรวจ COSE structure ลดขนาด firmware payload หรือแค่สงสัยว่า hex bytes ชุดนั้นมีอะไร CBOR Encoder / Decoder เปิดหน้าต่างเข้าไปดู RFC 8949 ได้ทันที แบบ private และตรงมาตรฐาน — ไม่ต้องติดตั้ง ไม่ต้องสมัคร ไม่มีข้อมูลออกจาก browser คุณ
เครื่องมือที่เกี่ยวข้อง
- JSON Formatter — จัดรูปแบบและตรวจ JSON ที่ได้หลัง decode
- JWT Decoder — ตรวจ header และ claims ของ JWT แบบข้อความ
- Base64 Encoder — แปลงระหว่าง Base64 กับ text หรือ bytes ดิบ
ขอให้มีความสุขกับการ encode!