fixmint
TH

ข้างในโทเคน JWT มีอะไร และทำไมการถอดรหัสไม่เท่ากับการตรวจสอบ

โดย · · อ่าน 4 นาที

โทเคน JSON Web Token (JWT) คือข้อความสามส่วนที่คั่นด้วยจุด ได้แก่ header, payload และ signature สองส่วนแรกเป็นเพียงการเข้ารหัสแบบแปลงรูป ไม่ได้เข้ารหัสลับ ใครก็ตามที่ถือโทเคนจึงอ่านได้ ส่วน signature ช่วยให้เซิร์ฟเวอร์ตรวจได้ว่าโทเคนออกโดยฝ่ายที่เชื่อถือได้และไม่มีใครแก้ไข การถอดรหัสบอกให้รู้ว่าโทเคนพูดอะไร มีแต่การตรวจสอบเท่านั้นที่บอกได้ว่าควรเชื่อหรือไม่

ตัวถอดรหัส JWTโทเคนหมดอายุแล้ว หรือยังใช้ได้?ใช้ฟรี

ส่วนทั้งสามของ JWT

โทเคนมีรูปแบบ header.payload.signature ส่วนแรกของโทเคนตัวอย่างที่รู้จักกันดีจาก jwt.io คือ

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

สองส่วนแรกแต่ละส่วนเป็น JSON ที่แปลงเป็น base64url ซึ่งเป็นรูปแบบข้อความที่ปลอดภัยใน URL ส่วนแรกถอดรหัสได้เป็น

{"alg":"HS256","typ":"JWT"}

payload ของตัวอย่างเดียวกันถอดรหัสได้เป็น

{"sub":"1234567890","name":"John Doe","iat":1516239022}

payload เก็บ claim ซึ่งเป็นข้อความที่บอกเกี่ยวกับผู้ใช้หรือเซสชัน signature คำนวณจากสองส่วนแรกและคีย์ ดังนั้นการเปลี่ยนตัวอักษรเพียงตัวเดียวจะทำให้ signature ไม่ตรงกันอีก base64url ย้อนกลับได้โดยไม่ต้องใช้คีย์ จึงอย่าใส่รหัสผ่าน private key หรือข้อมูลส่วนบุคคลลงใน payload เด็ดขาด

claim ที่มาตรฐานกำหนดไว้

RFC 7519 มาตรฐานของ JWT สงวนชื่อ claim สั้นๆ ไว้จำนวนหนึ่ง

  • iss (issuer): ผู้สร้างโทเคน
  • sub (subject): โทเคนนี้เกี่ยวกับใคร มักเป็นรหัสผู้ใช้
  • aud (audience): บริการที่โทเคนตั้งใจให้ใช้
  • exp (expiration time): เวลาที่หลังจากนั้นโทเคนจะไม่ถูกต้อง
  • nbf (not before): เวลาที่เร็วที่สุดที่โทเคนจะใช้ได้
  • iat (issued at): เวลาที่สร้างโทเคน

เวลาเป็นจำนวนวินาทีนับจาก 1 มกราคม 1970 UTC เรียกว่า Unix time ตัวอย่างนี้ไม่มี exp ตามมาตรฐานจึงไม่มีวันหมดอายุ โทเคนจริงควรมี ส่วน claim อื่นๆ เช่น role หรือ email เป็นของแอปพลิเคชันเอง

การถอดรหัสไม่ใช่การตรวจสอบ

การถอดรหัสคือการแยกโทเคนที่จุด แปลง base64url กลับ แล้วอ่าน JSON ซึ่งบอกให้รู้ว่าโทเคนอ้างอะไร และทำแบบเดียวกันกับโทเคนปลอม เพราะใครก็เขียน claim อะไรก็ได้พร้อม signature อะไรก็ได้

การตรวจสอบคือคำนวณ signature ใหม่ด้วยคีย์ที่ถูกต้องแล้วเช็กว่าตรงกัน และยังเช็กว่า exp กับ nbf ครอบคลุมเวลาปัจจุบัน และ iss กับ aud เป็นค่าที่บริการคาดหวัง แอปที่อ่าน claim role โดยไม่ตรวจสอบ กำลังไว้ใจผู้ที่เขียนโทเคนนั้น ซึ่งเป็นความผิดพลาดที่พบบ่อย

HS256, RS256 และ ES256

ค่า alg ระบุวิธีการ วิธีที่พบบ่อยมีสามแบบ

  • HS256 คือ HMAC กับ SHA-256 secret เดียวใช้ทั้งลงนามและตรวจสอบ ดังนั้น secret ต้องอยู่บนเซิร์ฟเวอร์ที่ออกโทเคนเท่านั้น
  • RS256 คือ RSA signature กับ SHA-256 ผู้ออกลงนามด้วย private key และใครก็ตามที่มี public key ก็ตรวจสอบได้ บริการอื่นจึงตรวจโทเคนได้โดยไม่สามารถสร้างโทเคนได้
  • ES256 คือ ECDSA signature บนเส้นโค้ง P-256 กับ SHA-256 ทำงานคล้าย RS256 แต่คีย์และ signature มีขนาดเล็กกว่า

ใช้ HS256 เมื่อบริการเดียวทั้งออกและตรวจโทเคนของตัวเอง ใช้ RS256 หรือ ES256 เมื่อบริการอื่นต้องตรวจโทเคนที่ตัวเองไม่ได้ออก

ปัญหาที่มาจากการเชื่อ header

header ถูกเขียนโดยผู้ที่ส่งโทเคน ฝ่ายตรวจสอบจึงต้องไม่ปล่อยให้ header เป็นผู้กำหนดกฎ

  1. alg: none โทเคนที่ไม่มี signature สามารถประกาศ "alg":"none" ได้ ไลบรารีบางตัวเคยยอมรับโทเคนแบบนี้และข้ามการตรวจสอบ ให้กำหนดอัลกอริทึมที่อนุญาตในโค้ดของคุณเอง อย่ารับค่านี้จากโทเคน
  2. การสับสนอัลกอริทึม เซิร์ฟเวอร์คาดหวัง RS256 และมี public key ผู้โจมตีส่ง HS256 token ที่ลงนามโดยใช้ public key นั้นเป็น HMAC secret ผู้ตรวจที่ยอมรับอัลกอริทึมใดก็ได้ที่ header ระบุจะยอมรับโทเคนนี้ ให้ผูกคีย์แต่ละตัวกับอัลกอริทึมเพียงหนึ่งเดียว
  3. secret ที่อ่อนแอ ผู้โจมตีมี header, payload และ signature จึงทดสอบ secret ที่เป็นไปได้แบบออฟไลน์ได้ secret ที่สั้นหรือคำที่ใช้บ่อยจะถูกเดาได้อย่างรวดเร็วจากรายการคำ RFC 7518 กำหนดว่าคีย์ HS256 ควรมีอย่างน้อย 256 บิต และต้องเป็นค่าสุ่ม

การวางโทเคนจริงลงในเว็บไซต์

โทเคนที่ใช้ได้และยังไม่หมดอายุจะใช้ได้กับผู้ที่ถืออยู่ จนกว่าจะหมดอายุ ให้ถือเหมือนรหัสผ่าน ก่อนวางลงในเว็บไซต์ ให้ตรวจสอบว่าเว็บไซต์ส่งโทเคนไปยังเซิร์ฟเวอร์หรือไม่ เครื่องมือที่ทำงานทั้งหมดในแท็บเบราว์เซอร์ไม่จำเป็นต้องส่ง คุณตรวจสอบหน้าใดก็ได้โดยดูคำขอเครือข่ายใน developer tools ของเบราว์เซอร์

โทเคนมักเพิกถอนก่อนหมดอายุไม่ได้ เว้นแต่เซิร์ฟเวอร์จะเก็บรายการไว้ ถ้าโทเคนที่ใช้งานอยู่รั่วไหล ให้ขอให้บริการเพิกถอนเซสชันหรือเปลี่ยนคีย์ เมื่อทำได้ ให้ใช้โทเคนจากสภาพแวดล้อมทดสอบสำหรับการดีบัก ตัวถอดรหัส JWT อ่านสามส่วนในแท็บเบราว์เซอร์ของคุณ และไม่มีสิ่งที่คุณวางถูกส่งไปที่ใดเลย

Webhook: หลักการเดียวกันกับ secret ที่ใช้ร่วมกัน

ผู้ให้บริการ webhook ส่วนใหญ่ส่ง HMAC ของ request body ซึ่งคำนวณด้วย secret ที่คุณใช้ร่วมกับพวกเขา และใส่ไว้ใน header ฝั่งผู้รับจะคำนวณ HMAC เดียวกันแล้วเทียบสองค่า ความผิดพลาดที่พบบ่อยมักเป็นเรื่องเล็กน้อย เช่น JSON ถูกจัดรูปแบบใหม่ก่อนแฮช ทำให้ไบต์เปลี่ยนไป ใช้ secret ทดสอบกับทราฟฟิกจริง หรือเทียบ signature ด้วยการเปรียบเทียบสตริงธรรมดา ซึ่งอาจรั่วข้อมูลเรื่องเวลาได้ ให้ใช้การเปรียบเทียบแบบ constant-time

ตรวจลายเซ็น webhook คำนวณ signature จาก secret และ body ที่คุณวาง สำหรับ GitHub, Stripe, Slack, Shopify หรือรูปแบบ HMAC อื่นๆ เพื่อให้คุณเห็นว่าสองค่าตรงกันหรือไม่

คำตอบสั้นๆ

JWT ถูกเข้ารหัสหรือไม่?

ไม่ได้ JWT มาตรฐานถูกลงนาม และใครก็อ่าน header กับ payload ได้ มีเพียง signature เท่านั้นที่ป้องกันการแก้ไข

ถ้าแก้ไข payload จะเกิดอะไรขึ้น?

signature จะไม่ตรงกัน เซิร์ฟเวอร์ที่ตรวจสอบจะปฏิเสธโทเคนนั้น การอ่าน claim ไม่ได้ตรวจ signature ดังนั้นตัวถอดรหัสยังแสดงเวอร์ชันที่คุณแก้ไขอยู่

แปลจาก ฉบับภาษาอังกฤษ ด้วยความช่วยเหลือของ AI

ความคิดเห็น

    ยังไม่มีความคิดเห็น มาเป็นคนแรกกันเลย

    คะแนนของคุณ (ไม่บังคับ)

    อีเมลของคุณจะไม่ถูกแสดงหรือเก็บไว้

    ปกของ Agentic AI in the BrowserAgentic AI in the Browser

    ตัวอย่างการใช้งานเวิร์กโฟลว์ AI ที่ทำงานบนเบราว์เซอร์และให้ความสำคัญกับความเป็นส่วนตัวเป็นอันดับแรก ยึดแนวคิดเดียวกับ fixmint คือประมวลผลบนอุปกรณ์ของคุณเอง

    $4.99ซื้อบน Gumroadฉบับภาษาอังกฤษ