Body Signature 101 — เข้าใจกุญแจคู่แบบมือใหม่
อธิบายแบบง่ายที่สุด: กุญแจคู่คืออะไร เซ็นยังไง ตรวจยังไง ทำไมหลังบ้านตรวจได้ทั้งที่ไม่มี private key และทำไมคน copy curl ถึงปลอมไม่ได้ — พร้อม sequence diagram ทุกขั้น
อัปเดต: 2026-08-03
Body Signature 101 — เข้าใจกุญแจคู่แบบมือใหม่
อ่านเล่มนี้ก่อน ถ้ายังใหม่กับเรื่องกุญแจคู่ — เล่มนี้ตอบ 4 คำถามที่ทุกคนสงสัย ด้วยภาษาบ้านๆ ไม่มีศัพท์ crypto เกินจำเป็น
พออ่านจบแล้วค่อยไปต่อ: ภาพระบบ 3 ชั้น (ระบบเต็มเป็นยังไง) → แผน Implement (จะสร้างยังไง)
คำถามที่ 1: กุญแจคู่คืออะไร ต่างจากรหัสผ่านยังไง
ของที่เราคุ้นเคย (รหัสผ่าน, API key, secret) เป็น “ความลับก้อนเดียว” — ใครรู้ก้อนนี้ = ทำได้ทุกอย่าง ทั้งตรวจและปลอม ดังนั้นมันอยู่ใน browser ไม่ได้เด็ดขาด เพราะทุกอย่างใน browser เปิด DevTools ก็เห็น
กุญแจคู่ต่างออกไป — มันคือกุญแจ 2 ดอกที่เกิดมาคู่กันทางคณิตศาสตร์ และแบ่งหน้าที่กันเด็ดขาด:
| อยู่ที่ไหน | ทำอะไรได้ | ถ้าคนอื่นได้ไป | |
|---|---|---|---|
| private key (ตราประทับ) | ในตู้เซฟที่ฝังอยู่ในเครื่องผู้ใช้ — สั่งให้ประทับได้ แต่หยิบตราออกมาดูไม่ได้ แม้แต่เจ้าของเอง | สร้างลายเซ็น | เป็นไปไม่ได้ — browser ไม่มีปุ่มให้ดูดค่าออกมา (extractable: false) |
| public key (ตัวอย่างลายประทับ) | ฝากไว้ที่ server | ตรวจลายเซ็น — อย่างเดียวเท่านั้น | ไม่เป็นไรเลย มันไม่ใช่ความลับ เห็นแล้วก็ปลอมตราไม่ได้ |
นึกภาพ: ตราประทับอยู่ในตู้เซฟที่มีช่องสอดกระดาษ — ยื่นเอกสารเข้าไป เอกสารออกมาพร้อมตราประทับ แต่ไม่มีทางล้วงเอาตัวตราออกมา · ส่วนตัวอย่างลายประทับที่ฝากธนาคารไว้ ใช้เทียบได้อย่างเดียว จะเอาไปแกะสลักตราปลอมไม่ได้
ขั้นแรก: สร้างกุญแจแล้วฝาก public key (ทำครั้งเดียวต่อเครื่อง)
sequenceDiagram
participant B as เครื่องผู้ใช้ (browser)
participant S as Server
Note over B: หลัง login สำเร็จครั้งแรก
B->>B: สร้างกุญแจคู่ — private ถูกล็อกในตู้เซฟทันที<br/>หยิบออกมาไม่ได้ตลอดชีวิตของมัน
B->>S: ส่งขึ้นไปฝากเฉพาะ public key (ไม่ใช่ความลับ หลุดก็ไม่เป็นไร)
S->>S: ผูก public key เข้ากับบัญชีผู้ใช้นี้<br/>กติกา: คนแรกเท่านั้น — ใครมาขอทับทีหลังโดนปฏิเสธ + แจ้งเตือน
S-->>B: เรียบร้อย
Note over B,S: จากนี้ server มี "ตัวอย่างลายประทับ" ของเครื่องนี้แล้ว<br/>และความลับไม่เคยเดินทางออกจากเครื่องเลย
คำถามที่ 2: หนึ่ง request เซ็นยังไง ตรวจยังไง
ก่อนส่งทุก request, browser จะรวมข้อมูลสำคัญทั้งหมดเป็น “ข้อความ” ก้อนเดียว — เวลา + วิธีเรียก (GET/POST) + ที่อยู่ปลายทาง + เนื้อหา — แล้วยื่นให้ตู้เซฟประทับตรา ได้ลายเซ็นแนบไปกับ request
ฝั่ง server ไม่ได้ “เชื่อ” อะไรที่ client ส่งมาเลย — มันประกอบข้อความเดียวกันขึ้นมาเองจากของที่ได้รับจริง แล้วเช็คว่าลายเซ็นลงตัวกับข้อความนั้นไหม
sequenceDiagram
participant B as Browser
participant S as Server
Note over B: ก่อนส่งทุก request
B->>B: ① รวมข้อมูลเป็นข้อความเดียว<br/>เวลา + GET/POST + ที่อยู่ + เนื้อหา
B->>B: ② ยื่นให้ตู้เซฟประทับตรา → ได้ลายเซ็น
B->>S: ③ ส่ง request + ลายเซ็น + เวลา
Note over S: ฝั่งตรวจ — ไม่เชื่ออะไรที่ส่งมา ประกอบเองหมด
S->>S: ④ ประกอบข้อความเดียวกันจากของที่ได้รับจริง
S->>S: ⑤ หยิบ public key ของผู้ใช้คนนี้ที่ฝากไว้
S->>S: ⑥ เช็ค: ลายเซ็น + ข้อความ + public key ลงตัวไหม?<br/>(คำตอบมีแค่ จริง/เท็จ)
alt ลงตัว
S-->>B: ✅ ทำงานต่อตามปกติ
else ไม่ลงตัว
S-->>B: ❌ 401 — มีอะไรถูกแก้ หรือไม่ใช่เครื่องที่ลงทะเบียน
end
จุดสำคัญที่ทำให้ระบบนี้แน่น: ทุกอย่างถูกมัดรวมในข้อความที่เซ็น — แก้เนื้อหา 1 ตัวอักษร, เปลี่ยนที่อยู่ปลายทาง, หรือเปลี่ยนเวลา = ข้อความเปลี่ยน = ลายเซ็นเดิมไม่ลงตัวทันที
คำถามที่ 3: server ไม่มี private key แล้ว “ตรวจ” ได้ยังไง? 🔑
นี่คือจุดที่มือใหม่งงที่สุด เพราะเราเคยชินกับการตรวจแบบรหัสผ่าน: “เอาความลับมาคำนวณซ้ำ แล้วเทียบว่าตรงกัน” — แบบนั้นคนตรวจต้องมีความลับด้วย
กุญแจคู่ไม่ได้ตรวจแบบนั้น — การตรวจคือ “เช็คคำตอบ” ไม่ใช่ “ทำโจทย์ซ้ำ”:
| แบบรหัสผ่าน/HMAC (กุญแจร่วม) | แบบกุญแจคู่ (ECDSA) | |
|---|---|---|
| วิธีตรวจ | ทำโจทย์ซ้ำด้วยความลับเดิม แล้วเทียบ | แทนค่าลงสมการ ด้วยของเปิดเผยล้วนๆ |
| คนตรวจต้องมี | ความลับตัวเดียวกับคนเซ็น | แค่ public key |
| ผลข้างเคียง | ตรวจได้ = ปลอมได้ด้วย | ตรวจได้ แต่ปลอมไม่ได้ |
ดูตัวอย่างเลขจริงให้เห็นภาพ (แบบ RSA ซึ่งหลักเดียวกันแต่เลขดูง่ายกว่า):
กุญแจคู่ถูกสร้างมาให้: ยกกำลัง d แล้วตามด้วยยกกำลัง e = กลับมาที่เดิมเสมอ
เซ็น (เครื่องผู้ใช้): ลายเซ็น = ข้อความ ^ d ← ใช้เลขลับ d
ตรวจ (server): ลายเซ็น ^ e == ข้อความ ? ← ใช้เลขเปิดเผย e เท่านั้น
สังเกตว่าบรรทัดตรวจไม่มี d โผล่มาเลย — server แค่เอาลายเซ็นยกกำลัง e (ที่ใครก็รู้) แล้วดูว่าได้ข้อความเดิมกลับมาไหม ถ้าได้ = ลายเซ็นนี้ต้องเกิดจาก d ตัวจริงเท่านั้น เพราะไม่มีทางอื่นที่จะทำให้สมการลงตัว
แล้วทำไม attacker ไม่คำนวณหา d จาก e ล่ะ? — เพราะมันคือโจทย์คณิตศาสตร์ที่โลกยังแก้ไม่ได้ ต้องลองประมาณ 2¹²⁸ ครั้ง (เอาคอมทั้งโลกช่วยกันก็ไม่เสร็จก่อนดวงอาทิตย์ดับ) · กำแพงจริงของระบบนี้คือคณิตศาสตร์ ไม่ใช่การซ่อนไฟล์
ECDSA ที่เราใช้จริงเปลี่ยนจาก “ยกกำลัง” เป็น “คูณจุดบนเส้นโค้ง” แต่หลักเหมือนกันทุกประการ: สมการตรวจถูกออกแบบให้ public key ทำหน้าที่แทน private key ได้ โดยไม่ต้องเห็นมันเลย
คำถามที่ 4: คน copy curl (มี cookie + ลายเซ็นครบ) ปลอมได้ไหม
ไล่ดูว่าเขาได้อะไรไปบ้าง: cookie ✓ ลายเซ็น ✓ เนื้อหา ✓ เวลา ✓ — และไม่ได้อะไร: ตราประทับ (private key) ✗ เพราะมันถ่ายเอกสารไม่ติด อยู่ในตู้เซฟของเครื่องเหยื่อ
sequenceDiagram
participant A as Attacker (copy curl มาครบมือ)
participant S as Server
Note over A: มี: cookie, ลายเซ็น, เนื้อหา, เวลา<br/>ไม่มี: private key (สิ่งเดียวที่ copy ไม่ได้)
A->>S: ทางที่ 1 — ยิงซ้ำก้อนเดิมเป๊ะทุก byte ภายใน 5 นาที
S-->>A: ⚠️ ผ่าน — ลายเซ็นเดิมยังลงตัวกับข้อความเดิม<br/>(ช่องเดียวที่เหลือ — มีแผนปิดด้วย replay-guard)
A->>A: ทางที่ 2 — แก้เนื้อหา เช่น เปลี่ยนเลขบัญชีปลายทาง
A->>S: ส่งด้วยลายเซ็นเดิม
S->>S: ประกอบข้อความจากเนื้อหาใหม่ → เช็คสมการ → ไม่ลงตัว
S-->>A: ❌ 401
A->>A: ทางที่ 3 — รอเกิน 5 นาทีค่อยยิง
S-->>A: ❌ 401 เวลาเก่าเกิน · จะแก้เวลา = ข้อความเปลี่ยน = ต้องเซ็นใหม่อีก
A->>A: ทางที่ 4 — สร้างกุญแจคู่ของตัวเองมาเซ็นแทน
A->>S: ส่งลายเซ็นจาก key ตัวเอง
S->>S: หยิบ public key ของ "เหยื่อ" มาตรวจ (ไม่ใช่ของ attacker)<br/>จะเอา key ตัวเองไปทับของเหยื่อก็โดนปฏิเสธ (คนแรกชนะ)
S-->>A: ❌ 401
Note over A: ทางตันทุกทาง ยกเว้นยิงซ้ำก้อนเดิมช่วงสั้นๆ
สรุปหนึ่งประโยค: copy curl = ได้ “เอกสารใบที่ประทับตราแล้ว 1 ใบ” — เอาไปยื่นซ้ำได้ช่วงสั้นๆ (ช่องที่รู้และมีแผนปิด) แต่เขียนใบใหม่หรือแก้ข้อความแล้วประทับใหม่ไม่ได้เด็ดขาด เพราะตราจริงออกจากเครื่องเหยื่อไม่ได้
ศัพท์ที่เจอบ่อย (แปลไทยทีละคำ)
| ศัพท์ | แปลว่า |
|---|---|
| keypair / กุญแจคู่ | private + public key ที่เกิดมาคู่กันทางคณิตศาสตร์ |
extractable: false / non-extractable | ตู้เซฟล็อกตาย — สั่งเซ็นได้ แต่อ่านค่ากุญแจออกมาไม่ได้ตลอดกาล |
| ECDSA P-256 | ชื่อสูตรคณิตศาสตร์ของกุญแจคู่ที่เราใช้ (ตระกูลเส้นโค้ง) |
| sign / เซ็น | เอา private key ประทับตราลงบนข้อความ ได้ลายเซ็นออกมา |
| verify / ตรวจ | แทนค่า (ข้อความ + ลายเซ็น + public key) ลงสมการ ดูว่าลงตัวไหม |
| raw bytes | เนื้อหาดิบเป๊ะๆ ทุก byte ตามที่ส่งจริง — server ใช้ตัวนี้ประกอบข้อความเอง ไม่เชื่อของแปรรูป |
| TOFU (first-key-wins) | ลงทะเบียน key ได้เฉพาะคนแรก — คนมาทีหลังโดนปฏิเสธ + แจ้งเตือน |
| replay | ยิง request เดิมซ้ำทั้งก้อน — ช่องเดียวที่เหลือ ปิดด้วย replay-guard |
| oid | รหัสประจำตัวผู้ใช้ใน token — server ใช้หา public key ว่าต้องหยิบของใคร |
| HMAC | ระบบลายเซ็นแบบ “กุญแจร่วม” ที่ server คุยกันเองใช้ — ใช้กับ browser ไม่ได้ |
อ่านต่อ
- ภาพระบบ 3 ชั้น (Target Architecture) — กุญแจคู่นี้อยู่ตรงไหนของระบบใหญ่ ทำงานร่วมกับ cookie และ encryption ยังไง เส้นทางเต็มขาเข้า-ขาออก
- แผน Implement รอบ POC — wire contract จริงที่ freeze แล้ว, ไฟล์ที่จะเขียน, ลำดับงาน, เกณฑ์ตรวจรับ