Private Docs

Encryption Field 101 + ทำหน้าบ้านให้ปลอดภัยขึ้น

อธิบายแบบง่ายที่สุด: มี HTTPS แล้วทำไมต้องเข้ารหัสอีก, browser ไม่มี secret แล้วล็อกข้อมูลยังไง, ทำงานคู่กับลายเซ็นยังไง และวิธีอุดจุดอ่อนร่วมของทั้งระบบ (XSS) — พร้อม sequence diagram

อัปเดต: 2026-08-04

Encryption Field 101 + ทำหน้าบ้านให้ปลอดภัยขึ้น

เล่มคู่ของ Body Signature 101 — เล่มนั้นตอบเรื่อง “ลายเซ็น” (กันปลอม) เล่มนี้ตอบเรื่อง “การเข้ารหัส” (กันอ่าน) และปิดท้ายด้วยวิธีทำให้หน้าบ้านแข็งแรงขึ้นทั้งระบบ

⚠️ สถานะ: encryption field (ชั้น 3) ยังเป็นร่าง design ยังไม่ freeze — หลักการในเล่มนี้คือทิศทางที่ตกลงกันแล้ว แต่รายละเอียด (สูตร, รูปแบบ envelope) ยังเปิดอยู่ 6 ประเด็น ดูภาพระบบข้อ 5.4

คำถามที่ 1: เว็บเราเป็น HTTPS อยู่แล้ว ทำไมต้องเข้ารหัสซ้ำอีก

HTTPS (TLS) เข้ารหัสแบบ “ท่อต่อท่อ” ไม่ใช่ “ต้นทางถึงปลายทาง” — ระหว่างทางข้อมูลของเราวิ่งผ่านตัวกลางหลายตัว และทุกข้อต่อ ข้อมูลถูกแกะออกมาเป็นตัวหนังสือโล้นๆ ชั่วคราว:

sequenceDiagram
    participant B as Browser
    participant CF as Cloudflare (WAF)
    participant GW as App GW (L7)
    participant BE as Backend

    Note over B,BE: HTTPS จริงๆ คือท่อเข้ารหัส "หลายท่อนต่อกัน" ไม่ใช่ท่อเดียวยาวถึงปลายทาง
    B->>CF: 🔒 ท่อนที่ 1 (เข้ารหัส)
    Note over CF: แกะออกอ่านได้เต็มๆ ตรงนี้<br/>(WAF ต้องอ่านเพื่อตรวจ traffic)
    CF->>GW: 🔒 ท่อนที่ 2 (เข้ารหัสใหม่)
    Note over GW: แกะออกอ่านได้อีกที่
    GW->>BE: 🔒 ท่อนที่ 3
    Note over BE: ปลายทางตัวจริง

แปลว่า เลขบัญชี เลขบัตร ข้อมูลส่วนตัว — ตัวกลางทุกตัวที่ยืนอยู่ตรงข้อต่อเห็นหมด ไม่ใช่เพราะใครทำผิด แต่เพราะหน้าที่ของมัน (WAF ต้องอ่าน traffic ถึงจะกรองได้)

Encryption field แก้ตรงนี้: ล็อกเฉพาะ field ที่อ่อนไหวตั้งแต่ในเครื่องผู้ใช้ แล้วไปเปิดได้ที่ backend ปลายทางเท่านั้น — ตัวกลางยังทำงานของมันได้ตามปกติ (เห็น request, เห็น header, กรอง traffic ได้) แต่ field ที่ล็อกไว้กลายเป็นก้อนขยะอ่านไม่ออกสำหรับมัน

คำถามที่ 2: browser ห้ามถือ secret แล้วจะเข้ารหัสได้ยังไง

ใช้กุญแจคู่อีกชุดหนึ่ง — แต่คราวนี้กลับด้านกับลายเซ็น: เจ้าของกุญแจคือ backend ไม่ใช่ browser

นึกภาพแม่กุญแจกับลูกกุญแจ:

อยู่ที่ไหนทำอะไรได้ถ้าคนอื่นได้ไป
public key (แม่กุญแจ)แจกให้ browser ทุกเครื่อง — แจกฟรี ใครเห็นก็ได้ล็อกได้อย่างเดียวไม่เป็นไรเลย — ได้แม่กุญแจไปก็ทำได้แค่ล็อก เปิดไม่ได้
private key (ลูกกุญแจ)ใน Key Vault ของ backend ไม่เคยออกไปไหนเปิดล็อกเป็นไปไม่ได้ — ไม่เคยเดินทางออกจาก server

browser จึงไม่ต้องถือความลับอะไรเลย — มันถือแค่ “แม่กุญแจ” ซึ่งเป็นของสาธารณะ · เหมือนกับที่ฝั่งลายเซ็น browser ถือแค่ตราประทับที่ล้วงออกมาไม่ได้ — ทั้งสองชั้นยึดหลักเดียวกัน: ไม่มีของลับในหน้าบ้าน

มีรายละเอียดทางเทคนิคอีกชั้น: ของจริงไม่ได้เอาแม่กุญแจล็อกข้อมูลตรงๆ (มันช้ากับข้อมูลก้อนใหญ่) — browser จะสุ่มกุญแจชั่วคราวขึ้นมาใหม่ทุก request ใช้ล็อกข้อมูลจริง แล้วเอาแม่กุญแจล็อก “ตัวกุญแจชั่วคราว” นั้นอีกที ส่งไปด้วยกัน (เรียกว่า hybrid encryption):

sequenceDiagram
    participant B as Browser
    participant BE as Backend

    Note over B: ครั้งแรก (หรือตาม cache)
    B->>BE: ขอ public key (แม่กุญแจ) — เป็นของแจกฟรี
    BE-->>B: ส่งให้ ไม่มีอะไรต้องปกปิด

    Note over B: ทุก request ที่มี field อ่อนไหว
    B->>B: ① สุ่มกุญแจชั่วคราว (ใช้ครั้งเดียวทิ้ง)
    B->>B: ② ล็อก field อ่อนไหวด้วยกุญแจชั่วคราว
    B->>B: ③ เอาแม่กุญแจล็อก "ตัวกุญแจชั่วคราว" อีกชั้น
    B->>BE: ④ ส่ง: { กุญแจชั่วคราวที่ถูกล็อก + ข้อมูลที่ถูกล็อก }
    Note over B,BE: ตัวกลางทุกตัวระหว่างทางเห็นแค่ก้อนขยะ 2 ก้อน

    BE->>BE: ⑤ ใช้ลูกกุญแจ (จาก Key Vault) เปิดเอากุญแจชั่วคราวออกมา
    BE->>BE: ⑥ ใช้กุญแจชั่วคราวเปิดข้อมูล → ได้ field ตัวจริง

ทำไมต้องสุ่มใหม่ทุกครั้ง? — เพราะกุญแจชั่วคราวใช้แล้วทิ้ง ต่อให้ใครเจาะได้สัก request (ซึ่งยากมากอยู่แล้ว) ก็เปิดได้แค่ request เดียว ไม่มี “กุญแจสะสม” ให้ขโมย

คำถามที่ 3: แล้วทำงานร่วมกับลายเซ็น (body signature) ยังไง

กติกาตายตัว: ล็อกก่อน แล้วค่อยประทับตรา (encrypt → sign) และฝั่งรับก็กลับลำดับ: ตรวจตราก่อน แล้วค่อยเปิดล็อก (verify → decrypt)

ฝั่ง browser:   payload → เข้ารหัส field → ได้ body สุดท้าย → เซ็นทับ body สุดท้ายนั้น
ฝั่ง backend:   ตรวจลายเซ็นจาก body ตามที่ได้รับ (ยังล็อกอยู่) → ผ่านแล้วค่อยเปิดล็อก

เหตุผล 2 ข้อ:

  1. ตรวจของถูกก่อนเสียแรงเปิด — request ปลอม/ถูกแก้ ตายตั้งแต่ด่านลายเซ็น (401) โดย backend ไม่ต้องเสียแรงถอดรหัสเลย
  2. ตราครอบทั้งกล่อง — ลายเซ็นทับก้อนที่ล็อกแล้วทั้งก้อน ใครสลับ/ตัดต่อชิ้นส่วนของกล่องระหว่างทาง ลายเซ็นพังทันที

จุดที่คนมักงง (มาจากคำถามจริงตอนคุยเรื่องลายเซ็น): “server ตรวจลายเซ็นได้ยังไงในเมื่อ body ถูกเข้ารหัส?” — ได้สบายมาก เพราะลายเซ็นถูกประทับทับก้อนที่ล็อกแล้ว server แค่เอาก้อนที่อยู่ในมือ (ยังล็อกอยู่) ไปเช็คสมการตามปกติ ไม่ต้องเปิดล็อกก่อนตรวจ — รายละเอียดเรื่องเช็คสมการอ่านที่ Body Signature 101 คำถามที่ 3

คำถามที่ 4: ขากลับ (backend ตอบมา) เข้ารหัสไหม

มติ Owner 04/08/2026: ต้องทำด้วย — ขากลับไม่ใช่ของแถม เหตุผลตรงไปตรงมา: response มักถือข้อมูลอ่อนไหวหนักกว่าขาไปด้วยซ้ำ — เรียกดูโปรไฟล์ครั้งเดียว เลขบัตรประจำตัวประชาชน เลขบัญชี ที่อยู่ ไหลกลับมาทั้งชุด และจุดเปิดเผยคือจุดเดียวกับขาไปเป๊ะ: ข้อต่อที่แกะ TLS อ่านได้หมด

(เกร็ดความแม่นยำ: response ไม่ได้ “โล้นๆ บน network” — ในสายมันอยู่ใต้ TLS เสมอ คนดักสายมองไม่เห็น · จุดที่เห็นคือข้อต่อที่แกะท่อ ซึ่งเพียงพอแล้วที่จะต้องปิดด้วยหลัก end-to-end เดียวกับขาไป)

วิธีทำ — สมมาตรกับขาไป แค่สลับบทบาท: คราวนี้ browser ต้องมี “แม่กุญแจ” ของตัวเองบ้าง — สร้างกุญแจคู่ชุดที่ 2 ในตู้เซฟเดียวกัน (คนละชุดกับลายเซ็น เพราะกุญแจลายเซ็นเซ็นได้อย่างเดียว ล็อก/เปิดไม่ได้) แล้วฝาก public key ขึ้นไปพร้อม flow ลงทะเบียนเดิม

sequenceDiagram
    participant B as Browser
    participant BE as Backend

    Note over B: ตอนลงทะเบียน (ครั้งเดียวต่อเครื่อง)
    B->>B: สร้างกุญแจคู่ชุดที่ 2 — สำหรับ "รับของ"
    B->>BE: ฝากแม่กุญแจของ browser (public key ชุดที่ 2)

    Note over BE: ทุก response ที่มี field อ่อนไหว
    BE->>BE: ① สุ่มกุญแจชั่วคราว → ล็อก field
    BE->>BE: ② เอาแม่กุญแจของ browser ล็อกตัวกุญแจชั่วคราว
    BE-->>B: ③ ส่ง envelope กลับ — ข้อต่อกลางทางเห็นแต่ก้อนขยะ
    B->>B: ④ เปิดด้วยลูกกุญแจในตู้เซฟ (ชุดที่ 2) → ได้ข้อมูลจริง

ลำดับการสร้าง: ขาไปก่อน → ขากลับตามทันที — เหตุผลเชิง engineering ล้วนๆ (ขาไปพิสูจน์กลไก envelope + การแจก key ให้จบก่อน ขากลับ reuse ของเดิมเกือบทั้งหมด) — ไม่ใช่ optional และไม่ใช่ “ค่อยว่ากัน”

กติการะหว่างที่ยังไม่มา (บังคับ — ไม่งั้นช่องเปิดค้าง): field อ่อนไหวใน response ให้ backend mask เสมอ เมื่อหน้าจอไม่จำเป็นต้องใช้ค่าเต็ม — เช่น เลขบัตรประชาชนส่ง x-xxxx-xxx45-67-8 แทนเลขเต็ม · หน้าจอส่วนใหญ่ต้องการแค่ให้ผู้ใช้ยืนยันว่า “ใช่เลขนี้” ไม่ได้ต้องการเลขเต็ม — ลดของอ่อนไหวบน wire ได้ทันทีโดยไม่ต้องรอ crypto

ข่าวดี: วิธีเข้ารหัสที่ใช้ (AES-GCM) ตรวจจับการแก้ไขได้ในตัวมันเอง — response ถูกแก้ = เปิดล็อกไม่ออก — จึงไม่ต้องเพิ่มลายเซ็นขากลับอีกชั้นให้ซ้ำซ้อน

คำถามที่ 5: จุดอ่อนร่วมของทุกชั้นคืออะไร — และทำหน้าบ้านให้ปลอดภัยขึ้นยังไง

หัวข้อนี้มีเล่มเต็มแยกแล้ว: Frontend Hardening 101 — เจาะลึกว่า XSS เข้าทางไหน, CSP/Trusted Types/WebAuthn ทำงานยังไงทีละ diagram, และถ้าเกิดจริงอะไรเสียหาย-อะไรรอด · ข้างล่างนี้คือฉบับย่อ

ทั้งลายเซ็นและการเข้ารหัส มีศัตรูร่วมตัวเดียวกัน: XSS — สคริปต์แปลกปลอมที่หลุดเข้ามารันในหน้าเว็บเรา

ทำไมสองชั้นนี้ช่วยไม่ได้: สคริปต์ที่รันในหน้าเดียวกัน มีสิทธิ์เท่ากับโค้ดของเราเป๊ะ — มันขโมยตราประทับไม่ได้ (non-extractable) แต่สั่งประทับได้ · มันขโมยกุญแจไม่ได้ แต่อ่านข้อมูลบนหน้าจอก่อนถูกล็อกได้ · browser แยกไม่ออกว่าใครเป็นคนเรียก

วิธีทำให้หน้าบ้านแข็งแรงขึ้น เรียงตามลำดับความสำคัญ:

#มาตรการกันอะไรสถานะของเรา
1CSP แบบเข้มงวด (nonce-based) — browser จะรันเฉพาะสคริปต์ที่มี “รหัสผ่านประจำรอบ” ที่ server แจกเท่านั้นตัดทางสคริปต์แปลกปลอมตั้งแต่ก่อนมันได้รัน — แก้ที่ต้นเหตุของ XSStrack แยกใน security uplift (IMPL_PLAN_10) — ยังไม่เริ่ม
2Trusted Types — ห้ามยัด string ดิบเข้า DOM ตรงๆ (จุดเกิด DOM-XSS)XSS สายที่เกิดจากโค้ดเราเองเผลอประกอบ HTML จาก inputไปด้วยกันกับข้อ 1
3Supply-chain scan — ตรวจ dependency ที่ใช้ว่ามีตัวไหนโดนฝังของXSS ที่มากับ library ที่เรา import เอง✅ มีแล้ว — SBOM + Dependency-Track ใน CI ของ FE
4WebAuthn step-up สำหรับ operation มูลค่าสูง — ลายเซ็นที่ต้องมีการกดของมนุษย์จริง (แตะ fingerprint / security key)เป็น primitive เดียวที่ XSS สั่งเงียบๆ ไม่ได้ — ต่อให้สคริปต์ร้ายรันอยู่ ก็บังคับนิ้วผู้ใช้ไม่ได้อนาคต — สำหรับ operation ระดับโอนเงิน/เปลี่ยนข้อมูลสำคัญ
5หลักการที่ถืออยู่แล้ว: ไม่มี secret ใดๆ ใน bundle/config ของ FE · cookie เป็นแค่ตัวชี้ session (token จริงอยู่ server)จำกัดความเสียหาย — ต่อให้ XSS เกิด ก็ไม่มีของลับให้ขโมยออกไปใช้ที่เครื่องอื่น✅ เป็นหลักของ architecture ทั้งระบบอยู่แล้ว

มองรวมกันเป็นภาพเดียว: ชั้น 1-3 กันภัยจากนอกเครื่อง (ขโมย cookie, แก้ข้อมูลกลางทาง, ดักอ่าน) ส่วนมาตรการในตารางนี้กันภัยจากในหน้าเว็บเอง (สคริปต์แปลกปลอม) — ต้องมีทั้งสองด้านถึงเรียกว่าหน้าบ้านปลอดภัยจริง

ศัพท์ที่เจอบ่อย

ศัพท์แปลว่า
TLS / HTTPSท่อเข้ารหัสระหว่างจุดต่อจุด — ปลอดภัยในท่อ แต่ถูกแกะที่ข้อต่อ
terminate TLSจุดที่ท่อเข้ารหัสสิ้นสุดและข้อมูลถูกแกะออกอ่าน (Cloudflare, App GW, APIM)
end-to-end (E2E)ล็อกจากต้นทางจริง เปิดที่ปลายทางจริง — ตัวกลางอ่านไม่ได้เลย
hybrid encryptionสุ่มกุญแจชั่วคราวล็อกข้อมูล แล้วเอาแม่กุญแจ (public key) ล็อกตัวกุญแจชั่วคราวอีกชั้น
ephemeral keyกุญแจชั่วคราวที่สุ่มใหม่ทุก request ใช้แล้วทิ้ง
AES-GCMสูตรล็อกข้อมูลที่ตรวจจับการแก้ไขได้ในตัว (เปิดไม่ออกถ้าถูกแก้)
envelopeก้อนที่ส่งจริง = กุญแจชั่วคราวที่ถูกล็อก + ข้อมูลที่ถูกล็อก
encrypt-then-signกติกาลำดับ: ล็อกก่อน → เซ็นทับก้อนที่ล็อกแล้ว
XSSสคริปต์แปลกปลอมที่หลุดมารันในหน้าเว็บเรา — จุดอ่อนร่วมที่ crypto ช่วยไม่ได้
CSP (nonce-based)กฎบอก browser ว่ารันได้เฉพาะสคริปต์ที่มีรหัสประจำรอบจาก server
Trusted Typesกฎห้ามยัด string ดิบเข้า DOM — กัน DOM-XSS
WebAuthnลายเซ็นที่ต้องมีการกดของมนุษย์จริง — XSS สั่งแทนไม่ได้

อ่านต่อ

  • Frontend Hardening 101 — เล่มเต็มของคำถามที่ 5: ปิดจุดอ่อนร่วม (XSS) ทีละมาตรการ
  • Body Signature 101 — เล่มคู่กัน: ลายเซ็นทำงานยังไง ทำไมปลอมไม่ได้
  • ภาพระบบ 3 ชั้น (Target Architecture) — encryption field อยู่ตรงไหนของระบบใหญ่ + 6 ประเด็นที่ยังต้องตัดสินก่อน implement (ข้อ 5.4)
  • แผน Implement รอบ POC — งานรอบปัจจุบัน (ลายเซ็นฝั่ง backend)