การโฮสต์ข้อมูลผู้ใช้อย่างปลอดภัยในเว็บแอปพลิเคชันสมัยใหม่

David Dworken
David Dworken

เว็บแอปพลิเคชันจำนวนมากจำเป็นต้องแสดงเนื้อหาที่ผู้ใช้ควบคุม ซึ่งอาจเป็นการทำงานที่ไม่ซับซ้อน เช่น การแสดงรูปภาพที่ผู้ใช้อัปโหลด (เช่น รูปโปรไฟล์) หรืออาจเป็นการทำงานที่ซับซ้อน เช่น การแสดงผล HTML ที่ผู้ใช้ควบคุม (เช่น บทแนะนำการพัฒนาเว็บ) การดำเนินการนี้เป็นเรื่องยากที่จะทำอย่างปลอดภัยมาโดยตลอด เราจึงพยายามหาวิธีแก้ปัญหาที่ง่ายแต่ปลอดภัยซึ่งใช้ได้กับเว็บแอปพลิเคชันส่วนใหญ่

โซลูชันคลาสสิกสำหรับการแยกเนื้อหาที่ไม่น่าเชื่อถือ

โซลูชันแบบคลาสสิกสำหรับการแสดงเนื้อหาที่ผู้ใช้ควบคุมได้อย่างปลอดภัยคือการใช้สิ่งที่เรียกว่าโดเมนแซนด์บ็อกซ์ แนวคิดพื้นฐานคือหากโดเมนหลักของแอปพลิเคชันคือ example.com คุณจะแสดงเนื้อหาที่ไม่น่าเชื่อถือทั้งหมดใน exampleusercontent.com ได้ เนื่องจากทั้ง 2 โดเมนนี้เป็นข้ามเว็บไซต์ เนื้อหาที่เป็นอันตรายใน exampleusercontent.com จึงไม่ส่งผลต่อ example.com คุณสามารถใช้วิธีนี้เพื่อแสดงเนื้อหาที่ไม่น่าเชื่อถือทุกประเภทได้อย่างปลอดภัย ซึ่งรวมถึงรูปภาพ การดาวน์โหลด และ HTML แม้ว่าการใช้พารามิเตอร์นี้กับรูปภาพหรือการดาวน์โหลดอาจดูไม่จำเป็น แต่การทำเช่นนี้จะช่วยหลีกเลี่ยงความเสี่ยงจากการดมกลิ่นเนื้อหา โดยเฉพาะในเบราว์เซอร์รุ่นเดิม โดเมน Sandbox มีการใช้งานอย่างแพร่หลายในอุตสาหกรรมและใช้งานได้ดีมาเป็นเวลานาน แต่ก็มีข้อเสียที่สำคัญ 2 ประการ

  • แอปพลิเคชันมักต้องจำกัดการเข้าถึงเนื้อหาไว้สำหรับผู้ใช้เพียงคนเดียว ซึ่งต้องมีการตรวจสอบสิทธิ์และการให้สิทธิ์ เนื่องจากโดเมนแซนด์บ็อกซ์ไม่ได้แชร์คุกกี้กับโดเมนแอปพลิเคชันหลักโดยเจตนา จึงเป็นเรื่องยากมากที่จะดำเนินการอย่างปลอดภัย หากต้องการรองรับการตรวจสอบสิทธิ์ เว็บไซต์จะต้องใช้ URL ความสามารถ หรือต้องตั้งค่าคุกกี้การตรวจสอบสิทธิ์แยกต่างหากสำหรับโดเมน Sandbox วิธีที่ 2 นี้มีปัญหาอย่างยิ่งในเว็บสมัยใหม่ที่เบราว์เซอร์หลายตัวจํากัดคุกกี้ข้ามเว็บไซต์โดยค่าเริ่มต้น
  • แม้ว่าเนื้อหาของผู้ใช้จะแยกจากเว็บไซต์หลัก แต่ก็ไม่ได้แยกจากเนื้อหาของผู้ใช้รายอื่น ซึ่งจะทำให้เกิดความเสี่ยงที่เนื้อหาของผู้ใช้ที่เป็นอันตรายจะโจมตีข้อมูลอื่นๆ ในโดเมนแซนด์บ็อกซ์ (เช่น โดยการอ่านข้อมูลต้นทางเดียวกัน)

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

โซลูชันที่ทันสมัยสำหรับการแสดงเนื้อหาของผู้ใช้

เว็บมีการพัฒนามาเรื่อยๆ และปัจจุบันมีวิธีที่ง่ายและปลอดภัยกว่าในการแสดงเนื้อหาที่ไม่น่าเชื่อถือ ที่นี่มีแนวทางที่แตกต่างกันมากมาย ดังนั้นเราจะสรุป 2 โซลูชันที่เราใช้ที่ Google

วิธีที่ 1: แสดงเนื้อหาของผู้ใช้ที่ไม่มีการใช้งาน

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

  • ตั้งค่าส่วนหัว Content-Type เป็นประเภท MIME ที่รู้จักกันดีซึ่งเบราว์เซอร์ทั้งหมดรองรับและไม่มีเนื้อหาที่ใช้งานอยู่เสมอ หากไม่แน่ใจ application/octet-stream เป็นตัวเลือกที่ปลอดภัย
  • นอกจากนี้ ให้ตั้งค่าส่วนหัวการตอบกลับเสมอเพื่อให้มั่นใจว่าเบราว์เซอร์จะแยกการตอบกลับอย่างสมบูรณ์
ส่วนหัวการตอบกลับ Purpose

X-Content-Type-Options: nosniff

ป้องกันการดมกลิ่นเนื้อหา

Content-Disposition: attachment; filename="download"

ทริกเกอร์การดาวน์โหลดแทนการแสดงผล

Content-Security-Policy: sandbox

แซนด์บ็อกซ์เนื้อหาเสมือนว่ามีการแสดงในโดเมนอื่น

Content-Security-Policy: default-src ‘none'

ปิดใช้การดำเนินการ JavaScript (และการรวมทรัพยากรย่อย)

Cross-Origin-Resource-Policy: same-site

ป้องกันไม่ให้รวมหน้าเว็บไว้ในเว็บไซต์อื่น

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

การป้องกันเชิงลึก

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

  • ตั้งค่าส่วนหัว X-Content-Security-Policy: sandbox เพื่อให้เข้ากันได้กับ IE11
  • ตั้งค่าส่วนหัว Content-Security-Policy: frame-ancestors 'none' เพื่อบล็อกไม่ให้ฝังปลายทาง
  • เนื้อหาของผู้ใช้ใน Sandbox บนโดเมนย่อยที่แยกต่างหากโดยทำดังนี้
    • การแสดงเนื้อหาของผู้ใช้ในโดเมนย่อยที่แยกต่างหาก (เช่น Google ใช้โดเมนอย่าง product.usercontent.google.com)
    • ตั้งค่า Cross-Origin-Opener-Policy: same-origin และ Cross-Origin-Embedder-Policy: require-corp เพื่อเปิดใช้การแยกแบบข้ามต้นทาง

แนวทางที่ 2: แสดงเนื้อหาของผู้ใช้ที่ใช้งานอยู่

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

ตัวเลือกที่ง่ายที่สุดคือการใช้ประโยชน์จากส่วนหัว Content-Security-Policy: sandbox เพื่อบอกให้เบราว์เซอร์แยกการตอบกลับ แม้ว่าเว็บเบราว์เซอร์บางตัวจะไม่ได้ใช้การแยกกระบวนการสำหรับเอกสารแซนด์บ็อกซ์ แต่การปรับแต่งโมเดลกระบวนการของเบราว์เซอร์อย่างต่อเนื่องน่าจะช่วยปรับปรุงการแยกเนื้อหาแซนด์บ็อกซ์ออกจากแอปพลิเคชันที่ฝัง หากการโจมตี SpectreJS และการบุกรุกโปรแกรมแสดงผลอยู่นอกรูปแบบภัยคุกคามของคุณ การใช้แซนด์บ็อกซ์ CSP น่าจะเป็นโซลูชันที่เพียงพอ ที่ Google เราได้พัฒนาโซลูชันที่สามารถแยกเนื้อหาที่ใช้งานอยู่ซึ่งไม่น่าเชื่อถือได้อย่างสมบูรณ์ด้วยการปรับปรุงแนวคิดของโดเมนแซนด์บ็อกซ์ให้ทันสมัย แนวคิดหลักคือ

  • สร้างโดเมนแซนด์บ็อกซ์ใหม่ที่เพิ่มลงในรายการคำต่อท้ายสาธารณะ เช่น การเพิ่ม exampleusercontent.com ลงใน PSL จะช่วยให้มั่นใจได้ว่า foo.exampleusercontent.com และ bar.exampleusercontent.com เป็นแบบข้ามเว็บไซต์และแยกออกจากกันอย่างสมบูรณ์
  • ระบบจะกำหนดเส้นทาง URL ที่ตรงกับ *.exampleusercontent.com/shim ไปยังไฟล์ Shim แบบคงที่ทั้งหมด ไฟล์ Shim นี้มีข้อมูลโค้ด HTML และ JavaScript สั้นๆ ที่รอตัวแฮนเดิลเหตุการณ์ message และแสดงเนื้อหาที่ได้รับ
  • หากต้องการใช้ฟีเจอร์นี้ ผลิตภัณฑ์จะสร้าง iframe หรือกล่องโต้ตอบเพื่อ $RANDOM_VALUE.exampleusercontent.com/shim และใช้ postMessage เพื่อส่ง เนื้อหาที่ไม่น่าเชื่อถือไปยัง Shim เพื่อแสดงผล
  • ระบบจะเปลี่ยนเนื้อหาที่แสดงผลเป็น Blob และแสดงผลภายใน iframe ที่ทำแซนด์บ็อกซ์

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

บทสรุป

เมื่อใช้ร่วมกัน โซลูชันทั้ง 2 อย่างนี้จะช่วยให้คุณย้ายข้อมูลออกจากโดเมนแซนด์บ็อกซ์แบบคลาสสิก เช่น googleusercontent.com ไปยังโซลูชันที่ปลอดภัยกว่าซึ่งเข้ากันได้กับการบล็อกคุกกี้ของบุคคลที่สาม ที่ Google เราได้ย้ายข้อมูลผลิตภัณฑ์หลายอย่างให้ใช้โซลูชันเหล่านี้แล้ว และวางแผนที่จะย้ายข้อมูลเพิ่มเติมในปีหน้า