Toolora

Base64 คืออะไร

ข้อความยาว ๆ ที่ลงท้ายด้วย "==" คืออะไร ใช้ตอนไหน และทำไมมันไม่ใช่วิธีปกปิดข้อมูล

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

ถ้าคุณเคยเห็นข้อความแบบ 4Liq4Lin4Lix4Liq4LiU4Li1 แล้วสงสัยว่าคืออะไร นั่นคือ Base64 และมันแปลว่า สวัสดี

เรื่องที่คนเข้าใจผิดมากที่สุด

Base64 ไม่ใช่การเข้ารหัสลับ มันไม่ได้ปกปิดอะไรเลย

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

ดังนั้นอย่าใช้มันปกป้องรหัสผ่าน API key หรืออะไรก็ตามที่ควรเป็นความลับ การเอา token มาแปลงเป็น Base64 ก่อนส่งไม่ได้เพิ่มความปลอดภัยแม้แต่น้อย มันยังเป็น token ตัวเดิม เพียงแค่เปลี่ยนหน้าตา

ความเข้าใจผิดนี้พอเข้าใจได้ เพราะผลลัพธ์ของ Base64 ดูเหมือน ถูกสับเปลี่ยนจนอ่านไม่ออก แต่ “ดูอ่านไม่ออก” กับ “เป็นความลับ” เป็นคนละเรื่องกัน Base64 เป็นแค่ รูปแบบการเขียน เหมือนกับการเขียนตัวเลขในระบบฐานสิบหก

สังเกตยังไงว่าเป็น Base64

Base64 ใช้ตัวอักษร 64 ตัวพอดี คือ A–Z, a–z, 0–9 บวกกับ + และ / ความยาวของผลลัพธ์จะเป็นจำนวนที่หารด้วยสี่ลงตัวเสมอ และถ้าข้อมูลต้นทางสั้นไม่พอดี จะมีเครื่องหมาย = เติมท้าย

เครื่องหมาย = หรือ == ท้ายข้อความนี่แหละคือจุดสังเกตที่ชัดที่สุด ถ้าเห็นข้อความยาว ๆ ที่มีแต่ตัวอักษรกับตัวเลขแล้วลงท้ายด้วย = แทบจะฟันธงได้เลยว่าเป็น Base64

มีไว้ทำไม

ระบบบางอย่างรับส่งได้อย่างปลอดภัยเฉพาะข้อความธรรมดา ตัวอย่างคลาสสิกคืออีเมล ซึ่งโปรโตคอลถูกออกแบบไว้เมื่อหลายสิบปีก่อนสำหรับข้อความแบบ 7 บิต ถ้าส่งข้อมูลไบนารีดิบ ๆ ผ่านเข้าไปตรง ๆ ข้อมูลจะเสียหาย การแนบรูปในอีเมลจึงต้องแปลงเป็นข้อความก่อน ส่งไป แล้วค่อยแปลงกลับที่ปลายทาง

ปัญหาเดียวกันนี้เกิดขึ้นทุกที่ที่ข้อมูลไบนารีต้องเดินทางอยู่ข้างในสิ่งที่เป็นข้อความ:

ที่ที่คุณจะเจอ เกิดอะไรขึ้น
ไฟล์แนบในอีเมล ไฟล์ถูกแปลงเป็น Base64 ฝังในตัวอีเมล (MIME)
data:image/png;base64,… ใน CSS หรือ HTML รูปขนาดเล็กถูกฝังลงในไฟล์โดยตรง
ข้อมูลไบนารีใน JSON JSON ไม่มีชนิดข้อมูลไบนารี ไบต์จึงต้องกลายเป็นข้อความ
โทเคน JWT ทั้งสามส่วนที่คั่นด้วยจุดเป็น Base64 แบบ URL-safe

ข้อสุดท้ายต้องเตือนเป็นพิเศษ เนื้อหาข้างใน JWT เป็น Base64 ไม่ได้ถูกเข้ารหัสลับ ใครก็ตามที่ถือโทเคนนั้นอ่านข้อมูลข้างในได้ทั้งหมด ทั้งรหัสผู้ใช้ อีเมล และสิทธิ์ต่าง ๆ ลายเซ็นในโทเคนมีไว้กันการแก้ไข ไม่ได้กันการอ่าน จึงไม่ควรใส่ข้อมูลที่เป็นความลับลงไปในนั้น

กินพื้นที่เพิ่มประมาณหนึ่งในสาม

Base64 อัดข้อมูลทุก 3 ไบต์ให้กลายเป็นตัวอักษร 4 ตัว อัตราส่วนนี้ตายตัว ผลลัพธ์จึงใหญ่กว่าต้นฉบับราว 33% เสมอ

นั่นคือเหตุผลที่การฝังรูปขนาดใหญ่เป็น data URI ใน CSS มักไม่คุ้ม รูป 100 KB จะกลายเป็นข้อความราว 133 KB แถมยังแคชแยกจากไฟล์ CSS ไม่ได้ และเบราว์เซอร์ต้องถอดรหัสก่อนจึงจะวาดออกมาได้ ถ้าเป็นไอคอนเล็ก ๆ ไม่กี่ร้อยไบต์ การประหยัดการเชื่อมต่อหนึ่งครั้งก็ถือว่าคุ้ม แต่ถ้าเป็นรูปถ่าย ไม่คุ้มแน่นอน

ข้อความภาษาไทยได้ผลลัพธ์ยาวกว่ามาก

เรื่องนี้ทำให้หลายคนแปลกใจ และควรเข้าใจไว้เพราะมันไม่ใช่ข้อผิดพลาด

Base64 ทำงานกับ ไบต์ ไม่ใช่ตัวอักษร ในระบบ UTF-8 ตัวอักษรภาษาอังกฤษหนึ่งตัวใช้ 1 ไบต์ แต่ตัวอักษรไทยหนึ่งตัวใช้ 3 ไบต์ ข้อความที่ดูยาวเท่ากันจึงให้ผลลัพธ์ต่างกันมาก:

ข้อความ จำนวนตัวอักษร จำนวนไบต์ ความยาว Base64
hello 5 5 8
สวัสดี 6 18 24

ตัวอักษรไทยหกตัวกินพื้นที่เป็นสามเท่าของภาษาอังกฤษหกตัว ถ้าคุณกำลังแปลงข้อความไทยไปใส่ใน URL หรือ QR Code ให้เผื่อไว้เลยว่าจะยาวกว่าภาษาอังกฤษราวสามเท่า และสำหรับ QR Code หมายความว่าลวดลายจะถี่ขึ้นตามไปด้วย

Base64 แบบ URL-safe

Base64 มาตรฐานใช้เครื่องหมาย + และ / ซึ่งทั้งคู่สร้างปัญหาเมื่ออยู่ใน URL เพราะ / เป็นตัวคั่นเส้นทาง ส่วน + ใน query string หมายถึงช่องว่าง ข้อความ Base64 ที่วางลงใน URL จึงอาจไปถึงปลายทางในสภาพที่ผิดเพี้ยน

Base64 แบบ URL-safe แก้ปัญหานี้ด้วยการสลับตัวอักษรสองตัว:

  • + เปลี่ยนเป็น -
  • / เปลี่ยนเป็น _

นอกจากนั้นเหมือนเดิมทุกอย่าง และมักตัดเครื่องหมาย = ท้ายออกด้วย นี่คือรูปแบบที่ JWT ใช้ ถ้าคุณต้องเอา Base64 ไปใส่ในลิงก์ query parameter หรือชื่อไฟล์ ให้เลือกแบบ URL-safe ซึ่งเครื่องมือของเรามีช่องให้ติ๊กไว้แล้ว

สรุปว่าควรใช้ตอนไหน

ควรใช้: เมื่อข้อมูลไบนารีต้องเดินทางผ่านช่องทางที่รับได้แต่ข้อความ และไม่มีทางเลือกที่ดีกว่า

ไม่ควรใช้: เพื่อปกปิดข้อมูล เพื่อบีบอัดข้อมูล (มันทำตรงกันข้าม) หรือเพื่อฝังไฟล์ขนาดใหญ่ลงในไฟล์ CSS

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