การสร้างประสบการณ์การใช้งานที่สมบูรณ์บนเว็บในปัจจุบันแทบจะหลีกเลี่ยงไม่ได้ที่จะต้องฝังคอมโพเนนต์และเนื้อหาที่คุณไม่มีสิทธิ์ควบคุม วิดเจ็ตของบุคคลที่สามสามารถกระตุ้นการมีส่วนร่วมและมีส่วนสําคัญอย่างยิ่งในประสบการณ์โดยรวมของผู้ใช้ และบางครั้งเนื้อหาที่ผู้ใช้สร้างขึ้นก็สำคัญกว่าเนื้อหาในเว็บไซต์ การไม่ใช้ทั้ง 2 รายการไม่ใช่ตัวเลือกที่ดีนัก แต่ทั้ง 2 รายการก็เพิ่มความเสี่ยงที่ Something Bad™ อาจเกิดขึ้นในเว็บไซต์ วิดเจ็ตแต่ละรายการที่คุณฝัง ไม่ว่าจะเป็นโฆษณา วิดเจ็ตโซเชียลมีเดียทุกรายการ อาจเป็นเวกเตอร์การโจมตีสำหรับผู้ที่มีเจตนาร้าย
นโยบายรักษาความปลอดภัยเนื้อหา (CSP) สามารถลดความเสี่ยงที่เกี่ยวข้องกับเนื้อหาทั้ง 2 ประเภทนี้ได้ด้วยการให้คุณเพิ่มแหล่งที่มาของสคริปต์และเนื้อหาอื่นๆ ที่เชื่อถือได้โดยเฉพาะลงในรายการที่อนุญาต นี่เป็นก้าวสำคัญในทิศทางที่ถูกต้อง แต่ควรทราบว่าการป้องกันที่คำสั่ง CSP ส่วนใหญ่มอบให้เป็นแบบ 2 ค่า คืออนุญาตหรือไม่อนุญาต บางครั้งการพูดว่า "ฉันไม่แน่ใจว่าเชื่อถือแหล่งที่มาของเนื้อหานี้จริงๆ แต่มันสวยมาก ฝังมันเลย โปรด เบราว์เซอร์ แต่อย่าทำให้เว็บไซต์ของฉันพัง"
สิทธิ์ขั้นต่ำที่สุด
สรุปแล้ว เรากําลังมองหากลไกที่จะช่วยให้เราให้สิทธิ์เนื้อหาที่ฝังไว้ในระดับความสามารถขั้นต่ำที่จําเป็นต่อการใช้งานเท่านั้น หากวิดเจ็ตไม่จําเป็นต้องเปิดหน้าต่างใหม่ การยกเลิกสิทธิ์เข้าถึง window.open ก็ไม่ส่งผลเสียใดๆ หากแอปไม่จำเป็นต้องใช้ Flash การปิดใช้การรองรับปลั๊กอินจะไม่ทำให้เกิดปัญหา เราจะรักษาความปลอดภัยได้มากที่สุดหากปฏิบัติตามหลักการของสิทธิ์ขั้นต่ำ และบล็อกฟีเจอร์ทั้งหมดที่ไม่เกี่ยวข้องกับฟังก์ชันการทำงานที่เราต้องการใช้โดยตรง ผลลัพธ์ที่ได้คือเราไม่จำเป็นต้องเชื่ออย่างสุ่มสี่สุ่มห้าอีกต่อไปว่าเนื้อหาที่ฝังบางส่วนจะไม่ใช้ประโยชน์จากสิทธิ์ที่ไม่ควรใช้ แต่จะเข้าถึงฟังก์ชันการทำงานดังกล่าวไม่ได้ตั้งแต่แรก
องค์ประกอบ iframe
เป็นก้าวแรกสู่เฟรมเวิร์กที่ดีสําหรับโซลูชันดังกล่าว
การโหลดคอมโพเนนต์ที่ไม่น่าเชื่อถือบางอย่างใน iframe
จะช่วยแยกแอปพลิเคชันของคุณออกจากเนื้อหาที่ต้องการโหลด เนื้อหาในกรอบจะไม่มีสิทธิ์เข้าถึง DOM ของหน้าเว็บหรือข้อมูลที่จัดเก็บไว้ในเครื่อง แต่จะวาดในตำแหน่งใดก็ได้ในหน้าเว็บ โดยขอบเขตจะจำกัดอยู่ที่ขอบของกรอบ อย่างไรก็ตาม การแยกดังกล่าวไม่ได้มีประสิทธิภาพมากนัก หน้าเว็บที่มีไฟล์ดังกล่าวยังคงมีตัวเลือกต่างๆ สำหรับลักษณะการทำงานที่รบกวนหรือเป็นอันตราย เช่น วิดีโอที่เล่นอัตโนมัติ ปลั๊กอิน และป๊อปอัป
แอตทริบิวต์ sandbox
ขององค์ประกอบ iframe
ช่วยให้เรามีข้อมูลที่จำเป็นในการจำกัดเนื้อหาที่มีกรอบให้รัดกุมยิ่งขึ้น เราสั่งให้เบราว์เซอร์โหลดเนื้อหาของเฟรมที่เฉพาะเจาะจงในสภาพแวดล้อมที่มีสิทธิ์ต่ำได้ โดยอนุญาตให้ใช้ความสามารถเพียงชุดย่อยที่จำเป็นต่อการทำงาน
เชื่อ แต่ต้องตรวจสอบ
ปุ่ม "ทวีต" ของ Twitter เป็นตัวอย่างที่ยอดเยี่ยมของฟังก์ชันการทำงานที่ฝังลงในเว็บไซต์ได้อย่างปลอดภัยมากขึ้นผ่านแซนด์บ็อกซ์ Twitter ให้คุณฝังปุ่มผ่าน iframe ได้โดยใช้โค้ดต่อไปนี้
<iframe src="https://platform.twitter.com/widgets/tweet_button.html"
style="border: 0; width:130px; height:20px;"></iframe>
มาดูกันว่าเราจะล็อกอะไรได้บ้าง โดยเราจะตรวจสอบความสามารถที่จําเป็นสำหรับปุ่ม HTML ที่โหลดลงในเฟรมจะเรียกใช้ JavaScript เล็กน้อยจากเซิร์ฟเวอร์ของ Twitter และสร้างป๊อปอัปที่มีอินเทอร์เฟซการทวีตเมื่อมีการคลิก อินเทอร์เฟซดังกล่าวต้องมีสิทธิ์เข้าถึงคุกกี้ของ Twitter เพื่อเชื่อมโยงทวีตกับบัญชีที่ถูกต้อง และต้องมีความสามารถในการส่งแบบฟอร์มการทวีต เท่านี้ก็เสร็จแล้ว เฟรมไม่จําเป็นต้องโหลดปลั๊กอินใดๆ และไม่จําเป็นต้องไปยังส่วนต่างๆ ของหน้าต่างระดับบนสุดหรือฟังก์ชันอื่นๆ อีกมากมาย เนื่องจากไม่จำเป็นต้องมีสิทธิ์เหล่านั้น เราจึงจะนําสิทธิ์เหล่านั้นออกโดยการใช้แซนด์บ็อกซ์กับเนื้อหาของเฟรม
Sandboxing ทำงานตามรายการที่อนุญาต เราจะเริ่มต้นด้วยการนําสิทธิ์ทั้งหมดออก จากนั้นเปิดความสามารถแต่ละรายการอีกครั้งด้วยการเพิ่ม Flag ที่เฉพาะเจาะจงในการกําหนดค่าของ Sandbox สำหรับวิดเจ็ต Twitter เราตัดสินใจที่จะเปิดใช้ JavaScript, ป๊อปอัป, การส่งแบบฟอร์ม และคุกกี้ของ twitter.com ซึ่งทําได้โดยการเพิ่มแอตทริบิวต์ sandbox
ลงใน iframe
ด้วยค่าต่อไปนี้
<iframe sandbox="allow-same-origin allow-scripts allow-popups allow-forms"
src="https://platform.twitter.com/widgets/tweet_button.html"
style="border: 0; width:130px; height:20px;"></iframe>
เท่านี้เอง เราได้ให้ความสามารถทั้งหมดที่จำเป็นแก่เฟรมแล้ว และเบราว์เซอร์จะปฏิเสธไม่ให้สิทธิ์เข้าถึงแก่เฟรมที่เราไม่ได้ให้สิทธิ์อย่างชัดเจนผ่านค่าของแอตทริบิวต์ sandbox
การควบคุมความสามารถแบบละเอียด
เราได้เห็น Flag ที่ใช้กับแซนด์บ็อกซ์ที่เป็นไปได้ 2-3 รายการในตัวอย่างด้านบน ตอนนี้มาเจาะลึกการทำงานภายในของแอตทริบิวต์กัน
เมื่อใช้ iframe ที่มีแอตทริบิวต์แซนด์บ็อกซ์ว่าง เอกสารที่ฝังไว้จะอยู่ในแซนด์บ็อกซ์โดยสมบูรณ์ ซึ่งจะขึ้นอยู่กับข้อจำกัดต่อไปนี้
- JavaScript จะไม่ทำงานในเอกสารที่มีกรอบ ซึ่งไม่เพียงรวมถึง JavaScript ที่โหลดผ่านแท็กสคริปต์อย่างชัดเจนเท่านั้น แต่ยังรวมถึงตัวแฮนเดิลเหตุการณ์ในบรรทัด และ URL รูปแบบ javascript: ด้วย ซึ่งหมายความว่าเนื้อหาที่อยู่ในแท็ก noscript จะแสดงราวกับว่าผู้ใช้ปิดใช้สคริปต์ด้วยตนเอง
- ระบบจะโหลดเอกสารที่มีกรอบลงในต้นทางที่ไม่ซ้ำกัน ซึ่งหมายความว่าการตรวจสอบต้นทางเดียวกันทั้งหมดจะดำเนินการไม่สำเร็จ ต้นทางที่ไม่ซ้ำกันจะไม่ตรงกับต้นทางอื่นๆ เลย แม้แต่ต้นทางเดียวกันเอง ผลกระทบอื่นๆ ของการดำเนินการนี้ ได้แก่ เอกสารจะไม่มีสิทธิ์เข้าถึงข้อมูลที่จัดเก็บไว้ในคุกกี้ของต้นทางหรือกลไกการจัดเก็บอื่นๆ (ที่จัดเก็บ DOM, Indexed DB ฯลฯ)
- เอกสารที่มีกรอบจะสร้างหน้าต่างหรือกล่องโต้ตอบใหม่ไม่ได้ (เช่น ผ่าน
window.open
หรือtarget="_blank"
) - ส่งแบบฟอร์มไม่ได้
- ปลั๊กอินจะไม่โหลด
- เอกสารที่มีกรอบจะไปยังส่วนต่างๆ ของเอกสารได้เท่านั้น แต่จะไปยังส่วนต่างๆ ของเอกสารหลักระดับบนสุดไม่ได้
การตั้งค่า
window.top.location
จะแสดงข้อยกเว้น และการคลิกลิงก์ที่มีtarget="_top"
จะไม่มีผล - ระบบจะบล็อกฟีเจอร์ที่ทริกเกอร์โดยอัตโนมัติ (องค์ประกอบแบบโฟกัสอัตโนมัติของแบบฟอร์ม วิดีโอที่เล่นอัตโนมัติ ฯลฯ)
- ไม่สามารถรับการล็อกเคอร์เซอร์
- ระบบจะละเว้นแอตทริบิวต์
seamless
ในiframes
ที่เอกสารที่มีกรอบมี
การดำเนินการนี้เข้มงวดมาก และเอกสารที่โหลดลงใน iframe
ที่ทำงานในระบบแซนด์บ็อกซ์อย่างเต็มรูปแบบมีความเสี่ยงน้อยมาก แต่แน่นอนว่าวิธีนี้ก็ไม่ได้มีประโยชน์มากนัก คุณอาจใช้แซนด์บ็อกซ์แบบเต็มกับเนื้อหาแบบคงที่บางรายการได้ แต่ส่วนใหญ่แล้วคุณจะต้องผ่อนคลายกฎระเบียบลงบ้าง
ยกเว้นปลั๊กอิน คุณสามารถยกเลิกข้อจำกัดเหล่านี้ได้โดยการใส่ Flag ลงในค่าของแอตทริบิวต์แซนด์บ็อกซ์ เอกสารที่อยู่ในแซนด์บ็อกซ์จะไม่สามารถเรียกใช้ปลั๊กอินได้ เนื่องจากปลั๊กอินเป็นโค้ดเนทีฟที่ไม่ได้อยู่ในแซนด์บ็อกซ์ แต่ส่วนอื่นๆ นั้นใช้ได้
allow-forms
อนุญาตให้ส่งแบบฟอร์มallow-popups
อนุญาตป๊อปอัป (น่าตกใจ)allow-pointer-lock
อนุญาตให้ล็อกเคอร์เซอร์ (แปลกใจไหม)allow-same-origin
ช่วยให้เอกสารคงต้นทางไว้ หน้าเว็บที่โหลดจากhttps://example.com/
จะยังคงเข้าถึงข้อมูลของต้นทางนั้นได้allow-scripts
อนุญาตให้เรียกใช้ JavaScript และอนุญาตให้ฟีเจอร์ทริกเกอร์โดยอัตโนมัติ (เนื่องจากติดตั้งใช้งานผ่าน JavaScript ได้ง่ายๆ)allow-top-navigation
ช่วยให้เอกสารออกจากเฟรมได้โดยการนำทางหน้าต่างระดับบนสุด
เมื่อพิจารณาข้อมูลเหล่านี้แล้ว เราประเมินสาเหตุที่ทำให้เกิด Flag Sandboxing ชุดหนึ่งในตัวอย่าง Twitter ด้านบนได้ดังนี้
- ต้องมี
allow-scripts
เนื่องจากหน้าเว็บที่โหลดลงในเฟรมจะเรียกใช้ JavaScript บางอย่างเพื่อจัดการกับการโต้ตอบของผู้ใช้ - ต้องมี
allow-popups
เนื่องจากปุ่มนี้จะแสดงแบบฟอร์มการทวีตในหน้าต่างใหม่ - ต้องระบุ
allow-forms
เนื่องจากควรส่งแบบฟอร์มการทวีตได้ allow-same-origin
เป็นสิ่งจําเป็น เนื่องจากคุกกี้ของ twitter.com จะเข้าถึงไม่ได้ และผู้ใช้จะเข้าสู่ระบบเพื่อโพสต์แบบฟอร์มไม่ได้
สิ่งที่ควรทราบอย่างหนึ่งคือ Flag ที่ใช้กับแซนด์บ็อกซ์ในเฟรมจะมีผลกับหน้าต่างหรือเฟรมที่สร้างในแซนด์บ็อกซ์ด้วย ซึ่งหมายความว่าเราต้องเพิ่ม allow-forms
ลงในแซนด์บ็อกซ์ของเฟรม แม้ว่าแบบฟอร์มจะอยู่ในหน้าต่างที่เฟรมปรากฏขึ้นเท่านั้น
เมื่อใช้แอตทริบิวต์ sandbox
วิดเจ็ตจะได้รับเฉพาะสิทธิ์ที่จําเป็น และความสามารถต่างๆ เช่น ปลั๊กอิน การนำทางระดับบนสุด และการล็อกเคอร์เซอร์จะยังคงถูกบล็อก เราได้ลดความเสี่ยงในการฝังวิดเจ็ตโดยไม่มีผลกระทบที่ไม่ดี
ซึ่งถือเป็นการชนะสำหรับทุกฝ่ายที่เกี่ยวข้อง
การแยกสิทธิ์
การใช้แซนด์บ็อกซ์กับเนื้อหาของบุคคลที่สามเพื่อเรียกใช้โค้ดที่ไม่น่าเชื่อถือในสภาพแวดล้อมที่มีสิทธิ์ในระดับต่ำนั้นมีประโยชน์อย่างเห็นได้ชัด แล้วโค้ดของคุณล่ะ คุณเชื่อมั่นในตัวเองใช่ไหม แล้วทำไมจึงต้องกังวลเกี่ยวกับการใช้แซนด์บ็อกซ์
เราขอถามกลับว่าหากโค้ดไม่จําเป็นต้องใช้ปลั๊กอิน เหตุใดจึงให้สิทธิ์เข้าถึงปลั๊กอิน ในกรณีที่ดีที่สุด สิทธิ์นี้จะเป็นสิทธิ์ที่คุณไม่เคยใช้เลย แต่ในกรณีที่เลวร้ายที่สุด สิทธิ์นี้อาจเป็นเวกเตอร์ที่อาจทำให้ผู้โจมตีเข้ามาได้ โค้ดของทุกคนล้วนมีข้อบกพร่อง และแอปพลิเคชันแทบทุกแอปพลิเคชันมีความเสี่ยงที่จะถูกละเมิดไม่ว่าในทางใดทางหนึ่ง การใช้แซนด์บ็อกซ์กับโค้ดของคุณเองหมายความว่าแม้ว่าผู้โจมตีจะแทรกแซงแอปพลิเคชันของคุณได้สำเร็จ แต่ผู้โจมตีก็จะไม่ได้รับสิทธิ์เข้าถึงเต็มรูปแบบในต้นทางของแอปพลิเคชัน แต่จะทําได้เพียงสิ่งที่แอปพลิเคชันทำได้เท่านั้น แม้จะยังคงเป็นปัญหาอยู่ แต่ก็ไม่ใช่ปัญหาร้ายแรงที่สุด
คุณลดความเสี่ยงได้มากขึ้นด้วยการแบ่งแอปพลิเคชันออกเป็นส่วนๆ ตามความเหมาะสม และทำให้แต่ละส่วนอยู่ในแซนด์บ็อกซ์ที่มีสิทธิ์น้อยที่สุดเท่าที่จะเป็นไปได้ เทคนิคนี้พบได้ทั่วไปในโค้ดเนทีฟ เช่น Chrome จะแบ่งตัวเองออกเป็นกระบวนการเบราว์เซอร์ที่มีสิทธิ์สูงซึ่งเข้าถึงฮาร์ดไดรฟ์ในเครื่องได้และสร้างการเชื่อมต่อเครือข่ายได้ รวมถึงกระบวนการแสดงผลที่มีสิทธิ์ต่ำจำนวนมากซึ่งทํางานหนักในการแยกวิเคราะห์เนื้อหาที่ไม่น่าเชื่อถือ โปรแกรมแสดงผลไม่จำเป็นต้องเข้าถึงดิสก์ เนื่องจากเบราว์เซอร์จะเป็นผู้ให้ข้อมูลทั้งหมดที่จำเป็นในการแสดงผลหน้าเว็บ แม้ว่าแฮ็กเกอร์ที่ฉลาดจะพบวิธีทำให้โปรแกรมแสดงผลเสียหาย แต่ก็ยังทำอันตรายได้ไม่มากนัก เนื่องจากโปรแกรมแสดงผลไม่สามารถดำเนินการใดๆ ที่น่าสนใจได้ด้วยตัวเอง สิทธิ์เข้าถึงที่มีสิทธิ์ระดับสูงทั้งหมดต้องส่งผ่านกระบวนการของเบราว์เซอร์ ผู้โจมตีจะต้องหาช่องโหว่หลายจุดในระบบส่วนต่างๆ เพื่อที่จะสร้างความเสียหาย ซึ่งจะช่วยลดความเสี่ยงในการลักลอบใช้บัญชีได้อย่างมาก
การใช้แซนด์บ็อกซ์กับ eval()
อย่างปลอดภัย
การใช้แซนด์บ็อกซ์และ postMessage
API ช่วยให้การนำโมเดลนี้ไปใช้กับเว็บนั้นง่ายดาย ชิ้นส่วนต่างๆ ของแอปพลิเคชันสามารถอยู่ใน iframe
ที่ใช้แซนด์บ็อกซ์ และเอกสารหลักสามารถเป็นสื่อกลางการสื่อสารระหว่างชิ้นส่วนต่างๆ ดังกล่าวได้โดยโพสต์ข้อความและรอรับการตอบกลับ โครงสร้างประเภทนี้ช่วยให้มั่นใจได้ว่าช่องโหว่ในส่วนใดส่วนหนึ่งของแอปจะสร้างความเสียหายน้อยที่สุด นอกจากนี้ ยังมีข้อดีในการบังคับให้คุณสร้างจุดผสานรวมที่ชัดเจน เพื่อให้คุณทราบว่าต้องตรวจสอบอินพุตและเอาต์พุตที่ใด เรามาดูตัวอย่างสมมติกันเพื่อดูว่าวิธีนี้อาจทำงานอย่างไร
Evalbox เป็นแอปพลิเคชันที่น่าสนใจซึ่งจะรับสตริงและประเมินเป็น JavaScript ว้าว จริงไหม ทุกอย่างที่คุณต้อง แน่นอนว่าแอปพลิเคชันนี้ค่อนข้างอันตราย เนื่องจากการอนุญาตให้ JavaScript ทำงานโดยพลการหมายความว่าข้อมูลทั้งหมดที่ต้นทางมีให้สามารถเข้าถึงได้ เราจะลดความเสี่ยงที่จะเกิด "เหตุการณ์ร้ายแรง" ขึ้นโดยการตรวจสอบว่าโค้ดทำงานภายในแซนด์บ็อกซ์ ซึ่งทำให้ปลอดภัยขึ้นมาก เราจะอธิบายโค้ดจากภายในสู่ภายนอก โดยเริ่มจากเนื้อหาของเฟรม
<!-- frame.html -->
<!DOCTYPE html>
<html>
<head>
<title>Evalbox's Frame</title>
<script>
window.addEventListener('message', function (e) {
var mainWindow = e.source;
var result = '';
try {
result = eval(e.data);
} catch (e) {
result = 'eval() threw an exception.';
}
mainWindow.postMessage(result, event.origin);
});
</script>
</head>
</html>
ภายในเฟรม เรามีเอกสารขั้นต่ำที่คอยฟังข้อความจากรายการหลักโดยเชื่อมต่อกับเหตุการณ์ message
ของออบเจ็กต์ window
เมื่อใดก็ตามที่รายการหลักเรียกใช้ postMessage ในเนื้อหาของ iframe เหตุการณ์นี้จะทริกเกอร์ขึ้น ซึ่งทำให้เราเข้าถึงสตริงที่รายการหลักต้องการให้เราเรียกใช้ได้
ในตัวแฮนเดิล เราจะดึงแอตทริบิวต์ source
ของเหตุการณ์ ซึ่งเป็นหน้าต่างหลัก เราจะใช้อีเมลนี้เพื่อส่งผลลัพธ์ของการทำงานหนักของเรากลับคืนมาเมื่อดำเนินการเสร็จสิ้น จากนั้นเราจะดำเนินการในส่วนที่ยาก โดยส่งข้อมูลที่ได้จากคุณไปยัง eval()
การเรียกนี้ได้รับการรวมไว้ในบล็อก try เนื่องจากการดำเนินการที่ถูกห้ามภายใน iframe
ที่อยู่ในแซนด์บ็อกซ์จะสร้างข้อยกเว้น DOM บ่อยครั้ง เราจะจับข้อยกเว้นเหล่านั้นและรายงานข้อความแสดงข้อผิดพลาดที่เข้าใจง่ายแทน สุดท้าย เราจะโพสต์ผลลัพธ์กลับไปยังหน้าต่างหลัก ขั้นตอนนี้ค่อนข้างตรงไปตรงมา
การดำเนินการกับรายการหลักก็ซับซ้อนไม่แพ้กัน เราจะสร้าง UI ขนาดเล็กที่มี textarea
สําหรับโค้ด และ button
สําหรับการดําเนินการ และเราจะดึง frame.html
ผ่าน iframe
ที่ใช้แซนด์บ็อกซ์ ซึ่งอนุญาตเฉพาะการเรียกใช้สคริปต์
<textarea id='code'></textarea>
<button id='safe'>eval() in a sandboxed frame.</button>
<iframe sandbox='allow-scripts'
id='sandboxed'
src='frame.html'></iframe>
ตอนนี้เราจะเดินสายไฟเพื่อใช้งาน ก่อนอื่น เราจะฟังความคิดเห็นจาก iframe
และ alert()
ให้กับผู้ใช้ เราคาดว่าแอปพลิเคชันจริงจะทําสิ่งต่อไปนี้ซึ่งน่ารำคาญน้อยกว่า
window.addEventListener('message',
function (e) {
// Sandboxed iframes which lack the 'allow-same-origin'
// header have "null" rather than a valid origin. This means you still
// have to be careful about accepting data via the messaging API you
// create. Check that source, and validate those inputs!
var frame = document.getElementById('sandboxed');
if (e.origin === "null" && e.source === frame.contentWindow)
alert('Result: ' + e.data);
});
ต่อไป เราจะเชื่อมต่อตัวแฮนเดิลเหตุการณ์กับการคลิก button
เมื่อผู้ใช้คลิก เราจะดึงเนื้อหาปัจจุบันของ textarea
และส่งไปยังเฟรมเพื่อดำเนินการ
function evaluate() {
var frame = document.getElementById('sandboxed');
var code = document.getElementById('code').value;
// Note that we're sending the message to "*", rather than some specific
// origin. Sandboxed iframes which lack the 'allow-same-origin' header
// don't have an origin which you can target: you'll have to send to any
// origin, which might alow some esoteric attacks. Validate your output!
frame.contentWindow.postMessage(code, '*');
}
document.getElementById('safe').addEventListener('click', evaluate);
ง่ายใช่ไหม เราได้สร้าง API การประเมินที่เรียบง่ายมาก และมั่นใจได้ว่าโค้ดที่ประเมินจะไม่มีสิทธิ์เข้าถึงข้อมูลที่ละเอียดอ่อน เช่น คุกกี้หรือพื้นที่เก็บข้อมูล DOM ในทํานองเดียวกัน โค้ดที่ประเมินแล้วจะโหลดปลั๊กอิน ป๊อปอัปหน้าต่างใหม่ หรือดําเนินการอื่นๆ ที่น่ารําคาญหรือเป็นอันตรายไม่ได้
คุณทําแบบเดียวกันกับโค้ดของคุณเองได้โดยแยกแอปพลิเคชันแบบโมโนลิธิกออกเป็นคอมโพเนนต์ที่มีวัตถุประสงค์เดียว แต่ละรายการสามารถรวมไว้ใน API การรับส่งข้อความแบบง่ายได้ เช่นเดียวกับที่เราเขียนไว้ข้างต้น หน้าต่างหลักที่มีสิทธิ์สูงสามารถทำหน้าที่เป็นตัวควบคุมและตัวจัดเตรียม โดยส่งข้อความไปยังโมดูลที่เฉพาะเจาะจงซึ่งแต่ละโมดูลมีสิทธิ์น้อยที่สุดในการทำงาน คอยฟังผลลัพธ์ และตรวจสอบว่าแต่ละโมดูลได้รับข้อมูลที่จำเป็นเท่านั้น
อย่างไรก็ตาม โปรดทราบว่าคุณต้องระมัดระวังอย่างยิ่งเมื่อจัดการกับเนื้อหาที่มีกรอบซึ่งมาจากแหล่งที่มาเดียวกันกับเนื้อหาหลัก หากหน้าในhttps://example.com/
แสดงเฟรมหน้าอื่นในต้นทางเดียวกันที่มีแซนด์บ็อกซ์ซึ่งมีทั้ง Flag allow-same-origin และ allow-scripts หน้าที่มีเฟรมจะเข้าถึงหน้าหลักและนำแอตทริบิวต์แซนด์บ็อกซ์ออกได้ทั้งหมด
เล่นในแซนด์บ็อกซ์
ขณะนี้แซนด์บ็อกซ์พร้อมให้ใช้งานในเบราว์เซอร์ต่างๆ เช่น Firefox 17 ขึ้นไป, IE10 ขึ้นไป และ Chrome ณ เวลาที่เขียนบทความนี้ (แน่นอนว่า caniuse มีตารางการรองรับที่อัปเดตอยู่เสมอ) การใช้แอตทริบิวต์ sandbox
กับ iframes
ที่รวมไว้ช่วยให้คุณให้สิทธิ์บางอย่างแก่เนื้อหาที่แสดงได้ แต่ให้สิทธิ์เฉพาะที่จำเป็นต่อการทำงานอย่างถูกต้องของเนื้อหา ซึ่งจะช่วยให้คุณลดความเสี่ยงที่เกี่ยวข้องกับการรวมเนื้อหาของบุคคลที่สามได้มากขึ้นนอกเหนือจากที่ทำได้ด้วยนโยบายรักษาความปลอดภัยเนื้อหา
นอกจากนี้ Sandboxing ยังถือเป็นเทคนิคที่มีประสิทธิภาพในการลดความเสี่ยงที่ผู้โจมตีที่ฉลาดจะใช้ประโยชน์จากช่องโหว่ในโค้ดของคุณได้ การแยกแอปพลิเคชันแบบโมโนลิธิกออกเป็นชุดบริการที่ใช้แซนด์บ็อกซ์ ซึ่งแต่ละบริการมีหน้าที่รับผิดชอบฟังก์ชันการทำงานแบบสแตนด์อโลนเพียงส่วนเล็กๆ จะทำให้ผู้โจมตีต้องเจาะทั้งเนื้อหาของเฟรมที่เฉพาะเจาะจงและตัวควบคุมเฟรมด้วย ซึ่งเป็นเรื่องที่ยากกว่ามาก โดยเฉพาะอย่างยิ่งเมื่อตัวควบคุมสามารถลดขอบเขตได้อย่างมาก คุณสามารถใช้ความพยายามที่เกี่ยวข้องกับความปลอดภัยในการตรวจสอบโค้ดนั้นได้หากขอความช่วยเหลือจากเบราว์เซอร์เกี่ยวกับส่วนที่เหลือ
แต่ไม่ได้หมายความว่าแซนด์บ็อกซ์เป็นโซลูชันที่สมบูรณ์แบบสำหรับปัญหาด้านความปลอดภัยบนอินเทอร์เน็ต ซึ่งจะมอบการป้องกันแบบหลายชั้น และคุณจะยังใช้การรองรับเบราว์เซอร์สำหรับผู้ใช้ทุกคนไม่ได้ เว้นแต่คุณจะควบคุมไคลเอ็นต์ของผู้ใช้ได้ (เช่น สภาพแวดล้อมขององค์กร) สักวันหนึ่ง… แต่ตอนนี้ Sandboxing เป็นการป้องกันอีกชั้นหนึ่งเพื่อเสริมการป้องกันของคุณ แต่ไม่ใช่การป้องกันที่สมบูรณ์ซึ่งคุณพึ่งพาได้เพียงอย่างเดียว แต่เลเยอร์ก็ยังคงยอดเยี่ยม เราขอแนะนำให้ใช้ตัวเลือกนี้
อ่านเพิ่มเติม
"การแยกสิทธิ์ในแอปพลิเคชัน HTML5" เป็นบทความที่น่าสนใจซึ่งอธิบายการออกแบบเฟรมเวิร์กขนาดเล็กและการใช้งานกับแอป HTML5 ที่มีอยู่ 3 แอป
แซนด์บ็อกซ์จะมีความยืดหยุ่นมากขึ้นเมื่อใช้ร่วมกับแอตทริบิวต์ iframe ใหม่อีก 2 รายการ ได้แก่
srcdoc
และseamless
รายการแรกช่วยให้คุณป้อนข้อมูลเฟรมด้วยเนื้อหาได้โดยไม่ต้องมีค่าใช้จ่ายเพิ่มเติมสำหรับคำขอ HTTP ส่วนรายการที่ 2 ช่วยให้สไตล์ไหลเข้าสู่เนื้อหาในเฟรมได้ ขณะนี้ทั้ง 2 รายการรองรับเบราว์เซอร์ได้ไม่ดีนัก (Chrome และ WebKit แบบ Nightly) แต่จะเป็นชุดค่าผสมที่น่าสนใจในอนาคต เช่น คุณอาจทดสอบความคิดเห็นในบทความผ่านโค้ดต่อไปนี้<iframe sandbox seamless srcdoc="<p>This is a user's comment! It can't execute script! Hooray for safety!</p>"></iframe>