เจาะให้ลึกแบบอ่านได้ยันดึกไปกับความสามารถของ Base64 กันดีกว่า
หลายคนเคยสงสัยเรื่อง Base64 กันบ้างไหมว่ามันมีที่มา และกลไกการทำงานอย่างไร ถ้าเคยละก็ ขอแนะนำว่า เนื้อหาต่อจากนี้จะเข้าสู่ MODE ที่ต้องใช้ สติ Concentrate ระดับนึง ขอแนะนำให้ พักสายตา แล้วรวบรวมสมาธิก่อนนะครับบบบ
คำเตือน : เนื้อหาที่นำมาเขียนนี้เป็นส่วนที่ผู้เขียนได้ทำการศึกษาและทำความเข้าใจด้วยตนเอง เพราะเช่นนั้น หากเจอจุดไหนที่ผิดพลาดต้องขออภัยไว้ ณ ที่นี้ และขอน้อมรับการแก้ไขให้ถูกต้องทุกกรณีครับ และก็ TL;DR (Too Long ; Didn’t Read)
หากจะขอให้ทุกคนช่วยนิยามเจ้า Base64 ว่ามันคืออะไร และสามารถนำไปทำอะไรได้ บ้างภายในเวลา 30 วิ เชื่อว่าหลายคนคิดใน “คุณคนเขียนจะบ้าหรอ เนี่ยตั้งใจมาอ่านไง” คนเขียน : พูดเป็นเล่นไป ขอบคุณนะครับ> < 555
Ok anyway, เรามาดูกันก่อนว่า Base64 มันคืออะไร และทำงานยังไงดีกว่า
Base64 คือ standard format ของข้อมูลรูปแบบหนึ่ง โดยรูปแบบข้อมูลจะประกอบไปด้วยตัวอักษรพิมพ์เล็ก พิมพ์ใหญ่ของภาษาอังกฤษ a-z, A-Z ตัวเลข 0–9และ อักขระอีก 2 ตัวคือ + กับ / ทั้งหมด 64 ตัวอักษร ซึ่งหากใครต้องการใช้ standard นี้ ต้องแปลงข้อมูลให้สอดคล้องกับ format ของ Base64 ซึ่งขั้นตอนนี้จะถูกเรียกว่า การ Encoding
ทีนี้มาดูในส่วนของการแปลงข้อมูลกันบ้างดีกว่า ซึ่งขั้นตอนนี้จะเรียกว่า ง่ายก็ไม่ง่ายเท่าไหร่ แต่ถ้าเข้าใจละก็ สบม.(สบายมากๆ) เริ่มจากนำข้อมูลต้นทางมาแปลงเป็นรูปแบบ Byte ก่อน จากนั้นก็นำข้อมูลมาเรียง Bit ( 1 Byte = 8 Bits) ตามปกติแล้วนำมา Map กับตารางอักขระของ Base64 โดยใช้จำนวน 6 Bits เพื่อเป็นรหัสอ้างอิงแทนแต่ละอักษรครับ ตามตารางดังนี้
หาก Map แล้วเหลือ เศษ bits ที่หาร 6 ไม่ลงตัว เราจะเติมสิ่งที่เรียกว่า padding ลงไป ซึ่งเราจะเติม bit 0 ต่อท้ายของข้อมูลจนกว่าจะได้ จำนวน bit ที่หาร 6 ลงตัว และ character ที่ต่อท้ายจะใช้ตัวอักษร = เสมอ เพื่อไม่ให้สับสนกับ A (ข้อมูลนั้นเป็น data หรือ padding) เรามาดูตัวอย่างกัน
หากเราจะ Encode คำว่า BASE64 เราจะได้ผลลัพธ์ดังนี้ QkFTRTY0 โดยเริ่มจากการนำ BASE64 มาแปลงเป็นข้อมูล byte ก่อน ซึ่งเราจะพิจารณาทีละตัวอักษร โดย Map แต่ละตัวอักษรกับ ตาราง ASCII ก่อนเลย (1 ตัวอักษรใน computer จะแทนด้วยรหัส 0,1 ซึ่งโดยทั่วไปจะใช้จำนวน 8 ตัว แทนแต่ละตัวอักษร โดยรหัส 0,1 จำนวน 1 ตัว เรียกว่า 1 bit และ 8 bits จะเรียกว่า 1 Byte ฉะนั้น 1 ตัวอักษร เท่ากับ 8 bits หรือ 1 Byte)
B A S E 6 4 0100 0010 0100 0001 0101 0011 0100 0101 0011 0110 0011 0100
ทีนี้มาแบ่งกลุ่ม bit เป็นทีละ 6 bits กัน
B A S E 6 4 0100 0010 0100 0001 0101 0011 0100 0101 0011 0110 0011 0100 เมื่อเรียงต่อกันจะได้เป็นแบบนี้ 010000100100000101010011010001010011011000110100 แบ่งกลุ่ม Bit ใหม่ กลุ่มละ 6 bits เพ่ือให้สามารถ Map กับ ตาราง Base64 ได้ 010000 100100 000101 010011 010001 010011 011000 110100 เมื่อเทียบกลุ่ม Bit กับ ตาราง Base64 จะได้ว่า Q k F T R T Y 0 010000 100100 000101 010011 010001 010011 011000 110100
และเมื่อนำมา Map กับ Table Base64 จะได้ Result = 'QkFTRTY0'
ขอเสริมอีกซักตัวอย่างนึง หากเราจะ Encode คำว่า Hello เราจะได้ผลลัพธ์ดังนี้
SGVsbG8= โดยหากเรามาพิจารณาจะได้ว่า
H e l l o 0100 1000 0110 0101 0110 1100 0110 1100 0110 1111 แบ่งกลุ่ม Bit ใหม่ กลุ่มละ 6 bits 010010 000110 010101 101100 011011 000110 1111
จะเห็นว่า Bit กลุ่มสุดท้ายมี ไม่ครบ 6 ฉะนั้นเราต้องเติมสิ่งที่เรียกว่า Padding ลงไปเพื่อให้เราสามารถทำการ Decode ได้ง่ายขึ้น หลักการเติม Padding นั้นจะเป็นไปตามสัดส่วนดังนี้ 3 Bytes : 4 Base64 characters แปลว่า
ผลลัพธ์จากการ Encoding จะมี Length เป็น จำนวนที่หาร 4 ลงตัว หากได้ไม่ลงตัวจะต้องเติมสิ่งที่เรียกว่า Padding ลงไป
H e l l o 0100 1000 0110 0101 0110 1100 0110 1100 0110 1111 แบ่งกลุ่ม Bit ใหม่ กลุ่มละ 6 bits 010010 000110 010101 101100 011011 000110 1111 สำหรับกรณีที่ผลลัพธ์ Encode จำนวนต้องเป็นจำนวนที่หาร 4 ลงตัว เมื่อนับแล้วพบว่าตัวสุดท้ายหาร 4 ไม่ลงตัว 1 2 3 4 1 2 3 ฉะนั้นจำเป็นต้องเติม Padding ลงไปเพื่อให้หาร 4 ลงตัว โดยจะเป็นการเติม bit 0 ต่อไปเรื่อยๆ จนกว่าจะได้จำนวนที่หาร 4 ลงตัว 010010 000110 010101 101100 011011 000110 111100 000000 เมื่อเทียบกับตาราง Base64 จะมีค่าเท่ากับ S G V s b G 8 = 010010 000110 010101 101100 011011 000110 111100 000000
จำนวนตัวอักษรที่ได้จากการ Encode จะมีขนาดไม่เกิน
4*(n/3)
ปล. n คือ จำนวน Bytes และมีเศษให้ปัดขึ้นนะครับ
วิธี Proof
Encode Aมีค่าเท่ากับ QQ==
Encode ABมีค่าเท่ากับ QUI=
Encode ABC มีค่าเท่ากับ QUJD
Encode ABCDมีค่าเท่ากับ QUJDRA==
Encode ABCDEมีค่าเท่ากับ QUJDREU=
Encode ABCDEFมีค่าเท่ากับ QUJDREVG
………
Encode ABCDEFGHIJKLMNOPQRSTUVWXYZมีค่าเท่ากับ QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVo=
เมื่อพิจารณาดู
พบว่า 1 ตัวอักษร encode ได้ 4 Base64
พบว่า 2 ตัวอักษร encode ได้ 4 Base64
พบว่า 3 ตัวอักษร encode ได้ 4 Base64
พบว่า 4 ตัวอักษร encode ได้ 8 Base64
พบว่า 5 ตัวอักษร encode ได้ 8 Base64
พบว่า 6 ตัวอักษร encode ได้ 8 Base64
ให้ n แทนตัวอักษร
n=1, 4*(n/3) = 4
n=2, 4*(n/3) = 4
n=3, 4*(n/3) = 4
n=4, 4*(n/3) = 8
n=5, 4*(n/3) = 8
n=6, 4*(n/3) = 8
…
n=26, 4*(n/3) = 36
∴ หลักการ Encode ข้อมูลของ Base64 จะได้ขนาดข้อมูลเท่ากับ 4*(n/3) โดยที่ n เป็นขนาดของ Byte เสมอ
เมื่อเรา Encode แล้ว เราก็มาทำความเข้าใจหลักการ decoding กัน สำหรับวิธีการแปลงข้อมูลกลับ เราจะทำคล้ายๆ Encoding แต่เป็นการทำย้อนกระบวนตั้งแต่ขั้นตอนสุดท้าย ย้อนไปถึงขั้นตอนแรก หรือง่ายๆคือ ย้อนแย้ง 😁 มาดูวิธีการกันเลย
ก่อนอื่นเอาค่าที่ encoding นั้น ขอใช้เป็น QkFTRTY0 ซึ่งจะตรงกับข้อมูลตัวอย่าง มา
1. Map กับ ตาราง Base64 Character แปลงค่าจาก เลขฐาน 64 เป็น เลขฐาน 2
2. แล้วทำการแปลงเป็นตัว character อีกที ด้วยการนับ เลขฐาน 2 จำนวน 8 bits
เพียงเท่านี้เราก็จะได้ข้อมูลที่ถอดรหัสจากการ encode เรียบร้อย แล้ว
ในทำนองเดียวกัน หากมี Padding ให้ตัด Padding ออกก่อน ก็จะได้ Bit ที่หาร 8 ลงตัวแล้ว Map ค่าย้อนกลับได้ตามปกติ
Highlight
แต่ในบางครั้งการ encode ข้อมูลทำให้ไม่สามารถนำข้อมูลที่ Encode แล้วไปใช้งานได้ เพราะ break rule หรือ violate convention ของ context ที่ใช้อยู่หรือพูดง่ายคือ อักขระ encoding บางตัว ไม่สามารถใช้งานกับสภาพแวดล้อมของสิ่งนั้นได้ เช่น การแปลงเป็น Base64 เพื่อนำไปเป็น parameter ใน url หากสังเกตดีๆ จะเห็นว่าตัวอักขระ / ใน Base64 จะเป็นปัญหาในทันที หากเอามาใช้งาน เพราะ จะถูกมองว่าเป็น Path delimiter ของ URL ดังนั้นเพื่อให้เหมาะสมกับการใช้งาน จะมี Encoder Decoder บางตัวที่มีการปรับ format ของข้อมูลไปเพื่อให้เหมาะสม เช่น Base64URLEncoder, Base64 encoding for IMAP, Nmtoken เป็นต้น
ประโยชน์ จากการทำ Base64 Encoding ที่เห็นได้ชัด
คือการ Encode ข้อมูลตรงๆ เพื่อป้องกันไม่ให้เห็นข้อมูล Plain ๆ แต่การทำแค่ Encode Base64 ไม่ปลอดภัยเพราะ หากใครรู้หลักการ Decode ก็จะสามารถอ่านข้อมูลได้ทันที ฉะนั้นก็อาจจะมีคนประสงค์ร้ายที่จะใช้รูโหว่ ของ Base64 เพื่อทำการ Hack ข้อมูล จึง อยากจะขอเตือนให้ทุกคนระมัดระวังการใช้งานด้วย หากจะใช้งานควรนำ Security Approach มา Apply ร่วมด้วย เพื่อลดความเสี่ยงความเสียหาย เรื่องการโจรกรรมข้อมูลได้
การประยุกต์ที่เคยเห็น
เคยได้ยินเรื่องการใช้ Image บน Web ที่เป็นแบบ Base64 กันไหมครับ ซึ่ง Base64 Image คือ sixty-fournary image โดยเป็นการนำมาแทนการ Download source รูป จากสมัยก่อนจะมีการ request ขอไฟล์รูปมาที่ web และมีการ Download resource อื่นๆเช่น css, javascript, รูปภาพ, เสียง, วิดีโอ, ฟอนต์ ฯลฯ ต่างๆนานา มากมายด้วยเช่นกัน หาก Webpage ของเราต้องโหลดรูป 10 ไฟล์ในหน้า Client ก็ต้องทำการเปิด Request มาขอรูปภาพ 10 รอบ ซึ่งจะเห็นว่า มันมี overhead ตอนเปิด Request มาขอรูป ตอนแจ้ง client ว่ารูปโหลดและเรนเดอร์เสร็จแล้ว และอื่นๆ...... แต่หากเราเปลี่ยนรูปเป็น Base64 ละก็ Client ก็ไม่จำเป็นต้องโหลด มากมายขนาดนั้น ซึ่งจะช่วยให้ประหยัดทรัพยากรอย่างมากมาย เพราะตัดพวก Holding Request ออกไปได้ แต่ก็ต้องคำนึกถึงขนาดของรูปภาพก่อนด้วย หากมีขนาดใหญ่เกินไป ก็จะไม่เหมาะสม เพราะ client จะต้องดาวน์โหลด Content ที่ใหญ่กว่าปกติ ซึ่งมีความไม่เหมาะสมกับการใช้งาน
แต่แล้ว ความสงสัยที่มี ก็ยังไม่หมดไปเคยสงสัยมะว่า Base64 Image เนี่ยเอาไปทำงานยังไงต่อ 555 เกริ่นมาตั้งนาน มาเข้าประเด็นคอลัมน์ นี้กันดีกว่า อันนี้จุดเริ่มต้นของความสงสัยที่แท้จริง บอกเลยว่า มันเป็นสิ่งที่อยากรู้โดย ความรู้สึกมันถูกซ่อนอยู่มานาน ถึงวันที่ต้องดับระเบิดความสงสัยกันซักที Base64 ที่ใช้แทนไฟล์รูป บน HTML นั้นมีที่มาอย่างไร
สรุป Base64 คือ เป็น Format การแทนค่าข้อมูลคล้ายกับ Binary, Hexadecimal Number เพียงแต่ขยาย จากตัวแทนรหัส 2 ตัว, 16 ตัว มาเป็น 64 ตัว เพื่อให้เพิ่มขนาดในการแทนค่า และประหยัดปริมาณข้อมูลในการแปลงความหมาย
ขอบคุณทุกๆคน ที่อ่านมาจนถึงบรรทัดนี้ครับ ปรบมือให้กับตัวเองกันหน่อย พวกคุณ เก่งมาก มาถึงตรงนี้ Blog จบละครับ บายยยยยย