การวิเคราะห์ความปลอดภัยล่าสุดที่เน้นช่องโหว่ใน parser ของ standard library ของ Go ได้จุดประกายการถกเถียงอย่างรุนแรงในหมู่นักพัฒนาเกี่ยวกับแนวทางปฏิบัติในการจัดการข้อมูลและการเลือกใช้ภาษาโปรแกรม รายงานดังกล่าวแสดงให้เห็นว่าการดำเนินการ parsing ที่ดูเหมือนไม่มีอันตรายสามารถนำไปสู่ข้อบกพร่องด้านความปลอดภัยที่ร้ายแรงได้ แต่การตอบสนองของชุมชนเผยให้เห็นความไม่เห็นด้วยที่ลึกซึ้งยิ่งขึ้นเกี่ยวกับความรับผิดชอบ
สถาปัตยกรรม vs การตำหนิ Parser
การอภิปรายที่ร้อนแรงที่สุดมุ่งเน้นไปที่ว่าปัญหาเหล่านี้เป็นปัญหาของ parser จริง ๆ หรือเป็นการออกแบบแอปพลิเคชันที่ไม่ดี นักพัฒนาที่มีประสบการณ์หลายคนโต้แย้งว่าสาเหตุหลักไม่ใช่ parsing library ของ Go แต่เป็นข้อผิดพลาดทางสถาปัตยกรรมพื้นฐาน ความกังวลหลักเกี่ยวข้องกับนักพัฒนาที่ใช้โครงสร้างข้อมูลเดียวกันสำหรับทั้งการดำเนินการฐานข้อมูลและ API endpoint ซึ่งสร้างโอกาสให้เกิดการเปิดเผยข้อมูลที่ไม่ตั้งใจ
IsAdmin ไปทำอะไรใน create user request DTO ตั้งแต่แรก? ตัวอย่างดูเหมือนจะบ่งชี้ถึงการใช้ data model ซ้ำอย่างไม่เหมาะสม
การวิจารณ์ทางสถาปัตยกรรมนี้เน้นย้ำถึง anti-pattern ที่พบบ่อย ซึ่งนักพัฒนาสร้างโครงสร้างข้อมูลเดียวที่ใช้งานหลายวัตถุประสงค์ ตั้งแต่ระเบียนฐานข้อมูลไปจนถึงการตอบสนอง API เมื่อโครงสร้างเหล่านี้ถูก serialize อัตโนมัติโดยไม่มีการควบคุม field อย่างระมัดระวัง ข้อมูลที่ละเอียดอ่อนอาจรั่วไหลหรือข้อมูลที่เป็นอันตรายอาจถูกแทรกเข้ามา
แนวทางปฏิบัติด้านความปลอดภัยที่แนะนำ:
• แยกโครงสร้างข้อมูล - ใช้ประเภทข้อมูลที่แตกต่างกันสำหรับคำขอ API โมเดลฐานข้อมูล และตรรกะทางธุรกิจ • การตรวจสอบ Content-Type - ตรวจสอบ header ของคำขออย่างชัดเจนเพื่อป้องกันการโจมตีแบบสับสนรูปแบบ • การตรวจสอบข้อมูลนำเข้า - ใช้ชั้นการตรวจสอบที่ไม่พึ่งพาพฤติกรรมของ parser เพื่อความปลอดภัย • การแมปฟิลด์อย่างชัดเจน - หลีกเลี่ยงการ serialization อัตโนมัติของฟิลด์ struct ทั้งหมด • การจำกัดความลึกในการแยกวิเคราะห์ - กำหนดข้อจำกัดเพื่อป้องกันการโจมตีแบบปฏิเสธการให้บริการ
![]() |
---|
แผนภาพแสดงให้เห็นการปฏิสัมพันธ์ระหว่างการป้อนข้อมูลของผู้ใช้และการประมวลผลแบ็กเอนด์ โดยเน้นปัญหาที่อาจเกิดขึ้นจากการนำโครงสร้างข้อมูลกลับมาใช้ใหม่อย่างไม่เหมาะสม |
การเลือกใช้การออกแบบของ Go ถูกวิจารณ์
การตัดสินใจในการออกแบบหลายประการของ Go กำลังถูกวิจารณ์จากชุมชนนักพัฒนา การจับคู่ JSON key แบบไม่คำนึงถึงตัวพิมพ์เล็กใหญ่ของภาษานี้โดดเด่นว่าเป็นเรื่องที่ถกเถียงกันเป็นพิเศษ โดยนักพัฒนาสังเกตว่าพฤติกรรมนี้แตกต่างจากการใช้งาน JSON ของภาษาโปรแกรมอื่น ๆ เกือบทั้งหมด ความไม่สอดคล้องกันนี้สามารถสร้างช่องโหว่ด้านความปลอดภัยเมื่อระบบที่ใช้ภาษาต่าง ๆ ประมวลผลข้อมูลเดียวกันแต่ได้ผลลัพธ์ที่แตกต่างกัน
การใช้ struct tag ที่ใช้ string สำหรับ field metadata ยังเผชิญกับการตรวจสอบอย่างละเอียด ซึ่งแตกต่างจากระบบ annotation ที่มีโครงสร้างมากกว่าในภาษาอย่าง Java หรือ Rust วิธีการของ Go ต้องการการแยกวิเคราะห์ string เพื่อดึงตัวเลือกการกำหนดค่า ซึ่งนำไปสู่ข้อผิดพลาดที่ละเอียดอ่อนเมื่อนักพัฒนาพิมพ์ผิดใน tag syntax
ปัญหาความปลอดภัยทั่วไปของ Go Parser:
• JSON keys ที่ไม่คำนึงถึงตัวพิมพ์เล็กใหญ่ - JSON parser ของ Go จับคู่ struct fields โดยไม่คำนึงถึงตัวพิมพ์เล็กใหญ่ ซึ่งแตกต่างจากภาษาอื่นๆ ส่วนใหญ่ • การยอมรับข้อมูลขยะต่อท้าย - XML parser ประมวลผลเอกสารที่มีเนื้อหาพิเศษโดยไม่แสดงข้อผิดพลาด • การ serialize field อัตโนมัติ - struct fields สาธารณะทั้งหมดจะถูก serialize โดยค่าเริ่มต้น เว้นแต่จะถูกยกเว้นอย่างชัดเจน • metadata แบบ string - struct tags ใช้การแยกวิเคราะห์ string ซึ่งอาจนำไปสู่ข้อผิดพลาดในการกำหนดค่า • polyglot payloads - string ข้อมูลเดียวสามารถใช้ได้กับรูปแบบ JSON, XML และ YAML
![]() |
---|
ภาพนี้แสดงให้เห็นว่าการแยกวิเคราะห์ JSON ในภาษา Go อาจนำไปสู่ความไม่สอดคล้องกัน โดยเน้นย้ำถึงตัวเลือกการออกแบบเฉพาะที่ถูกวิพากษ์วิจารณ์ในชุมชน |
ปัญหา Polyglot Payload
หนึ่งในการค้นพบที่น่าประหลาดใจที่สุดเกี่ยวข้องกับข้อมูลที่สามารถแยกวิเคราะห์พร้อมกันเป็น JSON, XML และ YAML ที่ถูกต้องได้ สิ่งนี้สร้างโอกาสให้ผู้โจมตีสร้าง payload ที่ทำงานแตกต่างกันขึ้นอยู่กับว่า parser ใดประมวลผลพวกมัน ปัญหานี้กลายเป็นอันตรายเป็นพิเศษเมื่อบริการต่าง ๆ ในระบบใช้ parsing library ที่แตกต่างกัน ซึ่งอาจทำให้ข้อมูลที่เป็นอันตรายสามารถหลีกเลี่ยงการตรวจสอบความปลอดภัยได้
โซลูชันของชุมชนและแนวทางปฏิบัติที่ดี
แม้จะมีการถกเถียงอย่างรุนแรงเกี่ยวกับการตำหนิ แต่ชุมชนได้รวมตัวกันรอบโซลูชันที่ปฏิบัติได้หลายประการ วิธีการที่ได้รับการสนับสนุนอย่างกว้างขวางที่สุดเกี่ยวข้องกับการสร้างโครงสร้างข้อมูลแยกต่างหากสำหรับ application layer ที่แตกต่างกัน - ประเภทที่แตกต่างกันสำหรับ API request, การดำเนินการฐานข้อมูล และ logic ทางธุรกิจภายใน แม้ว่าสิ่งนี้จะต้องการโค้ดมากขึ้น แต่ก็ให้ขอบเขตที่ชัดเจนและป้องกันการเปิดเผยข้อมูลโดยไม่ตั้งใจ
นักพัฒนาหลายคนยังสนับสนุนขั้นตอนการตรวจสอบความถูกต้องอย่างชัดเจนแทนที่จะพึ่งพา parser เพื่อความปลอดภัย ปรัชญา parse, don't validate นี้แนะนำว่าแอปพลิเคชันควรแปลงข้อมูลที่แยกวิเคราะห์แล้วเป็นการแสดงภายในแบบ strongly-typed ทันที โดยทิ้ง field ใด ๆ ที่ไม่ได้คาดหวังไว้อย่างชัดเจน
การอภิปรายเผยให้เห็นความตึงเครียดพื้นฐานในการพัฒนาซอฟต์แวร์สมัยใหม่ระหว่างความสะดวกสบายและความปลอดภัย ปรัชญาการออกแบบของ Go เน้นความเรียบง่ายและความง่ายในการใช้งาน แต่บางครั้งสิ่งนี้อาจขัดแย้งกับแนวทางปฏิบัติที่ดีด้านความปลอดภัย ดังที่นักพัฒนาคนหนึ่งกล่าวไว้ ความสะดวกสบายของการ serialize อัตโนมัติขัดแย้งกับความปลอดภัยโดยพื้นฐาน เพราะมันส่งเสริมให้นักพัฒนาใช้ทางลัดที่อาจมีผลที่ตามมาอย่างร้ายแรง
ในขณะที่รายงานความปลอดภัยเดิมมุ่งเน้นไปที่พฤติกรรม parser เฉพาะ การตอบสนองของชุมชนแนะนำว่าโซลูชันที่แท้จริงอยู่ที่สถาปัตยกรรมซอฟต์แวร์ที่ดีกว่าและแนวทางปฏิบัติการพัฒนาที่มีระเบียบวินัยมากขึ้น โดยไม่คำนึงถึงภาษาโปรแกรมหรือ parsing library ใดที่ใช้
อ้างอิง: Unexpected security footguns in Go's parsers
![]() |
---|
การเปรียบเทียบวิธีที่รูปแบบการทำให้ข้อมูลเป็นอนุกรมที่แตกต่างกันจัดการกับคีย์ที่ไม่รู้จัก เน้นย้ำถึงความสำคัญของการออกแบบเพื่อความปลอดภัยในการแยกวิเคราะห์ข้อมูล |