เครื่องหมายเท่ากับ (=) พวกนี้คืออะไรกันแน่?
(lars.ingebrigtsen.no)- ช่วงหลังมานี้มีการแชร์ ข้อความอ้างอิงจากอีเมลเก่า บน Twitter กันแพร่หลาย พร้อมตั้งคำถามว่าทำไมถึงมี เครื่องหมายเท่ากับ (=) โผล่อยู่ท้ายประโยค
- เครื่องหมายนี้เกิดจากกระบวนการเข้ารหัสแบบ
quoted-printableซึ่งใช้แสดงว่าบรรทัดยังต่อเนื่องกันเมื่อมีการบังคับตัดบรรทัดยาว - ตอนส่งอีเมลจะใช้ CRLF (carriage return + line feed) เป็นตัวขึ้นบรรทัดใหม่ แต่เมื่อแปลงเป็น NL ของ Unix ถ้าอัลกอริทึมถอดรหัสทำงานผิดพลาด ก็อาจมีเครื่องหมายเท่ากับค้างอยู่หรือทำให้ตัวอักษรหายไป
- นอกจากใช้กับการขึ้นบรรทัดใหม่แล้ว เครื่องหมายเท่ากับยังใช้แทน อักขระที่ไม่ใช่ ASCII (เช่น
=C2=A0) ได้ด้วย และตัวถอดรหัสที่ผิดพลาดอาจแทนที่มันแบบตรง ๆ จนทำให้เกิดข้อผิดพลาด - ต้นตอของปัญหาคือ ตรรกะการถอดรหัสที่มีบั๊กและการแปลงข้อมูลที่ไม่เหมาะสม ซึ่งสะท้อนว่าผู้ที่นำอีเมลไปประมวลผลนั้นขาดความชำนาญทางเทคนิค
ตัวตนที่แท้จริงของเครื่องหมายเท่ากับ (=) ในข้อความอ้างอิงจากอีเมล
-
ในช่วงไม่กี่วันที่ผ่านมา มีการแชร์ ข้อความอ้างอิงจากอีเมลเก่า จำนวนมากบน Twitter และสังเกตเห็นปรากฏการณ์ที่มีเครื่องหมายเท่ากับอยู่ท้ายประโยค
- ผู้เขียนโต้แย้งคำอธิบายที่เข้าใจผิดว่าเป็น โค้ดหรือข้อผิดพลาดจาก OCR (การรู้จำอักขระด้วยแสง)
- แท้จริงแล้วมันคือ ข้อผิดพลาดในการจัดการ encoding ที่เกิดขึ้นระหว่างกระบวนการแปลงอีเมลให้อ่านง่ายขึ้น
-
เดิมทีอีเมลเป็นเพียงข้อความธรรมดา แต่เพื่อรองรับบรรทัดยาวและอักขระพิเศษ จึงมีการนำ การเข้ารหัสแบบ
quoted-printableมาใช้- เมื่อต้องตัดบรรทัดยาว จะเติมเครื่องหมายเท่ากับ (=) ไว้ท้ายบรรทัดเพื่อบอกว่า “บรรทัดนี้ยังต่อเนื่อง”
- จากนั้นหลังเครื่องหมายเท่ากับจะตามด้วย CRLF (carriage return + line feed)
ข้อผิดพลาดในการเข้ารหัสและถอดรหัสการขึ้นบรรทัดใหม่
-
เซิร์ฟเวอร์อีเมลใช้การขึ้นบรรทัดใหม่แบบ CRLF เป็นมาตรฐาน แต่ระบบ Unix ใช้เพียง NL
- ระหว่างการแปลงจะมีข้อมูลหายไปหนึ่งไบต์ และหากตัวถอดรหัสจัดการผิด ก็อาจทำให้เครื่องหมายเท่ากับค้างอยู่หรือตัวอักษรบางตัวหายไป
- ตัวอย่างเช่น ถ้า
non- =CRLF clovenถูกประมวลผลผิด อาจกลายเป็นnon- lovenจนตัวcหายไป
-
บาง implementation จะจัดการโดยลบอักขระสองตัวเมื่อพบเครื่องหมายเท่ากับที่ท้ายบรรทัด
- อัลกอริทึมนี้จะทำงานผิดพลาดกับไฟล์รูปแบบ Unix และทำให้เกิดอาการที่เครื่องหมายเท่ากับยังคงหลงเหลืออยู่
อีกหน้าที่หนึ่งของเครื่องหมายเท่ากับ: การเข้ารหัสอักขระที่ไม่ใช่ ASCII
-
เครื่องหมายเท่ากับไม่ได้ใช้แค่กับการขึ้นบรรทัดใหม่ แต่ยังใช้ในการเข้ารหัส อักขระที่ไม่ใช่ ASCII ด้วย
- ตัวอย่าง:
=C2=A0หมายถึง non-breaking space (ช่องว่างที่ไม่ให้ตัดบรรทัด) - มักพบได้บ่อยเมื่อใช้อินเดนต์หรือแสดงอักขระพิเศษในเนื้อหาอีเมล
- ตัวอย่าง:
-
ผู้เขียนคาดว่าตัวแปลงบางตัวเพียงแค่แทนที่
=C2,=A0แบบ search-replace ตรง ๆ โดย ไม่ได้ใช้ตัวถอดรหัสที่ถูกต้องตามปกติ
พื้นหลังทางเทคนิคและมาตรฐาน
-
มาตรฐาน RFC 2045 กำหนดให้การเข้ารหัสแบบ quoted-printable เป็นรูปแบบสำหรับ การส่งข้อมูล (transport)
- หลังรับข้อมูลแล้วควรถูกถอดรหัสและเก็บเป็น ข้อความที่สะอาด ตามหลักการ
- แต่ใน implementation จริง ขั้นตอนนี้มักถูกละเลย ทำให้ข้อผิดพลาดเรื่องการจัดการบรรทัดใหม่เกิดขึ้นบ่อย
-
ในตัวอย่างโค้ด
(quoted-printable-decode-string "he=\nllo")จะถูกกู้คืนเป็น"hello"ได้อย่างถูกต้อง- สาเหตุเพราะมีการนำอัลกอริทึมที่ตั้งสมมติฐานว่าอยู่ในบริบทของเซิร์ฟเวอร์ SMTP และใช้ CRLF กลับมาใช้ซ้ำ
- บนไฟล์ที่มาจาก Windows มันทำงานได้ปกติ แต่บนระบบ Unix จะล้มเหลว
บทสรุป
- เครื่องหมายเท่ากับในข้อความอ้างอิงจากอีเมลคือ เศษตกค้างของการเข้ารหัสแบบ quoted-printable และเป็นผลลัพธ์จากการรวมกันของ
ข้อบกพร่องในการจัดการการขึ้นบรรทัดใหม่และการถอดรหัสอักขระที่ไม่ใช่ ASCII - รากของปัญหาที่แท้จริงคือ การ implement ตัวถอดรหัสอย่างไม่แม่นยำและความผิดพลาดในการแปลง encoding
- ผู้เขียนสรุปว่านี่คือ “ปัญหาทางเทคนิคและผลลัพธ์จากการประมวลผลที่ผิดพลาด” พร้อมเน้นย้ำว่าจำเป็นต้องปฏิบัติตามมาตรฐานอย่างละเอียดในกระบวนการแปลงอีเมล
1 ความคิดเห็น
ความคิดเห็นจาก Hacker News
ตัวเอกของบทความนี้คือ Lars Ingebrigtsen ผู้เขียนคู่มือของ Gnus ซึ่งเป็นแพ็กเกจอ่านอีเมล/Usenet ของ Emacs
คู่มือของเขาทั้งมีไหวพริบและให้ความรู้ พร้อมทั้งแสดงให้เห็นว่าเขาเข้าใจการพาร์สอีเมลลึกกว่าคนส่วนใหญ่มาก
ดูคู่มือได้ที่นี่ และอีกเวอร์ชันอยู่ที่ลิงก์นี้
ฉันจำช่วงที่เขาสร้าง Gnus ขึ้นมาเป็นครั้งแรกที่มหาวิทยาลัยออสโล (UiO) ได้
เขาเป็นเหมือน นักพัฒนาดาวเด่น ตัวเล็ก ๆ ในหมู่นักศึกษาภาควิชาวิทยาการคอมพิวเตอร์ของเรา และทุกคนก็ใช้ Emacs กับ Gnus กัน
เหตุการณ์นี้เป็นตัวอย่างคลาสสิกของคนที่ “รู้มากจนเป็นอันตราย”
รู้อยู่ว่าอีเมลไม่ได้เป็นแค่ข้อความธรรมดา แต่ไม่รู้ว่า quoted-printable decode ไม่ควรจัดการด้วยการแทนที่ข้อความแบบง่าย ๆ
มันเป็นบั๊กประเภทเดียวกับการพาร์ส HTML ด้วย regex โดยตรง ที่ช่วงแรกดูเหมือนจะใช้ได้ดี ก่อนจะลงเอยด้วยสถานการณ์ที่ มีเครื่องหมาย ‘=’ เต็มไปหมดในหลักฐานที่ยื่นต่อรัฐสภา
มีคำถามว่า “ทำไมเมลเซิร์ฟเวอร์ถึงเกลียดบรรทัดยาว ๆ”
เซิร์ฟเวอร์ต้องพาร์สเฮดเดอร์ จึงไม่สามารถมองมันเป็น binary blob ธรรมดาได้
IMAP ต้องให้เซิร์ฟเวอร์พาร์สอย่างสมบูรณ์ ส่วน POP3 ถูกออกแบบมาสำหรับอุปกรณ์เดี่ยวซึ่งไม่ค่อยเหมาะกับยุคนี้แล้ว
RFC 821 จำกัดความยาวบรรทัดไว้สูงสุด 1000 ไบต์ และเพื่อความเข้ากันได้ก็มักตัดไม่ให้เกิน 80 ตัวอักษร
เพราะแบบนี้ การเข้ารหัส Base64 จึงใส่การขึ้นบรรทัดใหม่ทุก ๆ 76 ตัวอักษร
เช่น PDP-11 มีราว 512KB และ VAX-11 มีราว 2MB ขณะที่โปรแกรมเมอร์ในยุคนั้น คำนวณหน่วยความจำกันในระดับไบต์
HELO,MAIL FROM,RCPT TO,DATAเป็นต้นดูเอกสารที่เกี่ยวข้องได้จากเอกสารทางการของ IBM และWikipedia
ตอนแรกนึกว่าบทความนี้จะพูดถึง ความหมายของโอเปอเรเตอร์ อย่าง
= == === .=. <== ==> <<== ==>> (==) => =~=ส่วนตัวฉันเคยทำซอฟต์แวร์เก็บถาวรอีเมลขึ้นมาเอง
การจัดการ edge case ของไฟล์ .eml ที่สะสมมากว่า 20 ปีคือส่วนที่ยากที่สุด
แนวคิดมันดูเรียบง่าย แต่อีเมลซับซ้อนอย่างน่าประหลาด
แม้แต่การตรวจสอบความถูกต้องของที่อยู่อีเมลก็แทบเป็นไปไม่ได้ในทางปฏิบัติ
มีผู้ใช้กลุ่มเล็ก ๆ อยู่หลายปี แต่ การจัดการ MIME คือความทรมานที่สุด
สิ่งที่ฉันสนใจไม่ใช่แค่เครื่องหมาย ‘=’ เอง แต่เป็นปรากฏการณ์ที่ ตัวอักษรรอบ ๆ มันหายไป
มันดูคล้าย off-by-one error ตรงที่แทนที่จะลบ ‘=’ กลับกลายเป็นว่าข้อความจริงบางส่วนหายไป
อาจเกี่ยวข้องกับการแปลง CRLF/LF ก็ได้
มีคนสงสัยว่าทำไมปัญหานี้ถึงเพิ่งมาเกิด ตอนนี้
ช่วงไม่กี่วันที่ผ่านมา ผู้คนกำลังโพสต์อีเมลเก่าลงบน Twitter และก็สงสัยว่ามันเกิดจากอะไร
บางคนตั้งข้อสังเกตว่าต้นตอของปัญหานี้อาจไม่ใช่ Gmail แต่เป็น การแปลงข้อมูลที่เซิร์ฟเวอร์กลางทาง
นอกจากการแปลง CRLF→LF แล้ว ถ้า quoted-printable ถูกประมวลผลซ้ำสองครั้งก็จะเกิดอาการมี ‘=’ ค้างอยู่ได้ ดังนั้นอาจมีเมลเซิร์ฟเวอร์สองตัวเข้ามาเกี่ยวข้อง
ในความเป็นจริงมักเป็น เด็กฝึกงานที่ไม่ใช่มืออาชีพ ใช้เครื่องมือพื้น ๆ รวบรวมข้อมูล แล้วข้อมูลก็ถูกแปลงหลายรอบจนฟอร์แมตพัง
ต้นฉบับถูกทำลายไปแล้ว เหลือเพียง เศษข้อมูลที่เหลือแต่รูปทรง เท่านั้น
บทความใน archive.today ก็มีอาการ quoted-printable พังแบบเดียวกัน
ลิงก์ที่เกี่ยวข้องคือ pastes.io/correspond และ เธรด HN
มีคนบอกว่าเวลาเปิดดูอีเมลที่ดาวน์โหลดจาก Outlook ถ้ามี ตัวดูไฟล์ .eml ที่ถอด quoted-printable ให้อัตโนมัติได้ก็คงจะดี