เล่นอย่างปลอดภัยใน IFrame ที่แซนด์บ็อกซ์

การสร้างประสบการณ์ที่สมบูรณ์บนเว็บทุกวันนี้แทบจะหลีกเลี่ยงไม่ได้เลยด้วยการฝังคอมโพเนนต์และเนื้อหาที่คุณไม่สามารถควบคุมได้อย่างแท้จริง วิดเจ็ตของบุคคลที่สามจะช่วยกระตุ้นการมีส่วนร่วมและมีบทบาทสำคัญต่อประสบการณ์ของผู้ใช้โดยรวมได้ และบางครั้งเนื้อหาที่ผู้ใช้สร้างขึ้นก็มีความสำคัญมากกว่าเนื้อหาเนทีฟของเว็บไซต์ด้วย การยับยั้งการใช้ทั้ง 2 อย่างนี้ไม่ใช่ทางเลือกที่ดีนัก แต่ทั้ง 2 อย่างนี้ก็เพิ่มความเสี่ยงที่Some BadTM จะเกิดขึ้นบนเว็บไซต์ของคุณได้ วิดเจ็ตแต่ละรายการที่คุณฝัง โฆษณาทุกรายการ วิดเจ็ตโซเชียลมีเดียทั้งหมด คือเวกเตอร์การโจมตีที่เป็นไปได้สำหรับผู้ที่มีเจตนาร้าย

นโยบายรักษาความปลอดภัยเนื้อหา (CSP) ช่วยลดความเสี่ยงที่เกี่ยวข้องกับเนื้อหาทั้ง 2 ประเภทนี้ได้ด้วยการมอบความสามารถในการอนุญาตแหล่งที่มาของสคริปต์และเนื้อหาอื่นๆ ที่เชื่อถือได้เป็นการเฉพาะ นี่เป็นขั้นตอนสำคัญในทิศทางที่ถูกต้อง แต่ควรทราบว่าการปกป้องที่คำสั่งของ CSP ส่วนใหญ่นำเสนอจะเป็นแบบไบนารี กล่าวคือ อนุญาตหรือไม่อนุญาตทรัพยากร ในบางครั้ง การพูดว่า "ฉันไม่มั่นใจว่าวางใจแหล่งข้อมูลนี้จริงๆ นะ แต่มันสวยมากเลย ให้ฝังลงในเบราว์เซอร์ แต่อย่าให้มันเสียหายกับเว็บไซต์ของฉัน"

สิทธิ์น้อยที่สุด

โดยพื้นฐานแล้ว เรากำลังมองหากลไกที่จะช่วยให้เราสามารถมอบเนื้อหาที่เราฝังเฉพาะความสามารถขั้นต่ำที่จำเป็นต่อการทำงานของเนื้อหาเท่านั้น หากวิดเจ็ตไม่จำเป็นต้องแสดงหน้าต่างใหม่ขึ้นมา การนำสิทธิ์เข้าถึง 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 เพื่อเชื่อมโยงทวีตกับบัญชีที่ถูกต้อง และต้องสามารถส่งแบบฟอร์มการทวีตได้ ง่ายๆ ก็คือ เฟรมไม่จำเป็นต้องโหลดปลั๊กอินใดๆ ไม่จำเป็นต้องไปที่หน้าต่างระดับบนสุดหรือ ฟังก์ชันเสริมอื่นๆ เนื่องจากไม่ต้องใช้สิทธิ์นั้น ให้นำ ออกโดยแซนด์บ็อกซ์เนื้อหาของเฟรม

แซนด์บ็อกซ์ทำงานบนพื้นฐานของรายการที่อนุญาตพิเศษ เราจะเริ่มต้นด้วยการนำสิทธิ์ทั้งหมดออก แล้วเปิดความสามารถแต่ละรายการอีกครั้งด้วยการเพิ่ม Flag ที่เฉพาะเจาะจงในการกำหนดค่าของแซนด์บ็อกซ์ สำหรับวิดเจ็ต 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 แซนด์บ็อกซ์บางส่วนที่เป็นไปได้ในตัวอย่างด้านบน คราวนี้มาเจาะลึกรายละเอียดการทำงานภายในของแอตทริบิวต์กัน

เนื่องจาก iframe ที่มีแอตทริบิวต์แซนด์บ็อกซ์ที่ว่างเปล่า เอกสารที่อยู่ในเฟรมจะได้รับแซนด์บ็อกซ์โดยสมบูรณ์ ซึ่งเป็นไปตามข้อจำกัดต่อไปนี้

  • JavaScript จะไม่ทำงานในเอกสารที่อยู่ในเฟรม ซึ่งไม่เพียงมี JavaScript ที่โหลดอย่างชัดเจนผ่านแท็กสคริปต์เท่านั้น แต่ยังรวมถึงเครื่องจัดการเหตุการณ์แบบอินไลน์และ javascript: URL ด้วย ซึ่งหมายความว่าเนื้อหาที่อยู่ในแท็ก noscript จะแสดงเหมือนกับที่ผู้ใช้ได้ปิดใช้สคริปต์ด้วยตนเอง
  • ระบบจะโหลดเอกสารที่ใส่เฟรมลงในต้นทางที่ไม่ซ้ำกัน ซึ่งหมายความว่าการตรวจสอบจากต้นทางเดียวกันทั้งหมดจะล้มเหลว เพราะต้นทางที่ไม่ซ้ำกันจะไม่จับคู่กับต้นทางอื่นๆ เลย ยกเว้นต้นทางเอง นอกจากผลกระทบอื่นๆ แล้ว หมายความว่าเอกสารจะไม่มีสิทธิ์เข้าถึงข้อมูลที่เก็บไว้ในคุกกี้ของต้นทางหรือกลไกการจัดเก็บอื่นๆ (พื้นที่เก็บข้อมูล DOM, DB ที่จัดทำดัชนีแล้ว ฯลฯ)
  • เอกสารที่ใส่กรอบจะไม่สามารถสร้างหน้าต่างหรือกล่องโต้ตอบใหม่ (เช่น ผ่าน window.open หรือ target="_blank")
  • ส่งแบบฟอร์มไม่ได้
  • ปลั๊กอินจะไม่โหลด
  • เอกสารที่อยู่ในเฟรมจะไปยังส่วนต่างๆ ได้ด้วยตัวเองเท่านั้น ไม่ใช่เอกสารระดับบนสุด การตั้งค่า window.top.location จะทำให้มีข้อยกเว้น และการคลิกลิงก์ที่มี target="_top" จะไม่มีผล
  • ฟีเจอร์ที่ทริกเกอร์โดยอัตโนมัติ (องค์ประกอบของแบบฟอร์มที่เน้นอัตโนมัติ วิดีโอที่เล่นอัตโนมัติ ฯลฯ) จะถูกบล็อก
  • ปลดล็อกตัวชี้ไม่ได้
  • ระบบจะไม่สนใจแอตทริบิวต์ seamless ใน iframes ในเอกสารที่มีกรอบ

นี่ไม่เป็นความจริงเลย และเอกสารที่โหลดลงใน iframe ที่มีแซนด์บ็อกซ์อย่างสมบูรณ์ก็มีความเสี่ยงน้อยมากจริงๆ แน่นอนว่าวิธีนี้ก็ไม่ได้มีประโยชน์มากนักเช่นกัน คุณอาจเลิกใช้แซนด์บ็อกซ์เต็มรูปแบบสำหรับเนื้อหาคงที่บางอย่างได้ แต่ส่วนใหญ่แล้ว คุณอาจต้องการทำให้สิ่งต่างๆ หายไป

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

  • allow-forms อนุญาตให้ส่งแบบฟอร์ม
  • allow-popups อนุญาตป๊อปอัป (ช็อก!)
  • allow-pointer-lock อนุญาตการล็อกตัวชี้ (เซอร์ไพรส์!)
  • allow-same-origin ช่วยให้เอกสารคงต้นฉบับไว้ หน้าที่โหลดจาก https://example.com/ จะยังคงเข้าถึงข้อมูลของต้นทางนั้นได้
  • allow-scripts อนุญาตให้เรียกใช้ JavaScript และยังอนุญาตให้ฟีเจอร์ทริกเกอร์โดยอัตโนมัติ (เนื่องจากใช้งานผ่าน JavaScript ได้ยาก)
  • allow-top-navigation ช่วยให้เอกสารหลุดออกจากเฟรมได้โดยไปยังหน้าต่างระดับบนสุด

ด้วยเหตุนี้ เราจึงสามารถประเมินได้อย่างชัดเจนว่าเพราะเหตุใดเราจึงมีชุดแฟล็กแซนด์บ็อกซ์ที่เฉพาะเจาะจงในตัวอย่าง Twitter ข้างต้น

  • ต้องใช้ allow-scripts เนื่องจากหน้าที่โหลดลงในเฟรมจะเรียกใช้ JavaScript บางรายการเพื่อจัดการกับการโต้ตอบของผู้ใช้
  • ต้องใช้ allow-popups เนื่องจากปุ่มจะแสดงแบบฟอร์มการทวีตในหน้าต่างใหม่
  • ต้องใช้ allow-forms เนื่องจากแบบฟอร์มนี้ควรส่งแบบฟอร์มทวีต
  • จำเป็นต้องใช้ allow-same-origin เนื่องจากคุกกี้ของ twitter.com จะไม่สามารถเข้าถึงได้ และผู้ใช้ก็จะเข้าสู่ระบบเพื่อโพสต์แบบฟอร์มไม่ได้

สิ่งสําคัญที่ควรทราบคือแฟล็กแซนด์บ็อกซ์ที่นำไปใช้กับเฟรมจะมีผลกับหน้าต่างหรือเฟรมที่สร้างขึ้นในแซนด์บ็อกซ์ด้วย ซึ่งหมายความว่าเราต้องเพิ่ม allow-forms ลงในแซนด์บ็อกซ์ของเฟรม แม้ว่าแบบฟอร์มจะอยู่ในหน้าต่างที่เฟรมปรากฏขึ้นเท่านั้น

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

การแยกสิทธิ์

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

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

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

ทำแซนด์บ็อกซ์ eval() อย่างปลอดภัย

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

Evalbox เป็นแอปพลิเคชันที่น่าตื่นเต้นซึ่งจะใช้สตริงแล้วประเมินเป็น JavaScript ว้าว ใช่ไหมล่ะ คือสิ่งที่คุณ เฝ้ารอมาตลอดหลายปี แน่นอนว่านี่เป็นแอปพลิเคชันที่อันตรายพอสมควร เนื่องจากการอนุญาตให้ JavaScript แบบกำหนดเองเรียกใช้ได้หมายความว่าข้อมูลทั้งหมดที่ต้นทางมีให้สามารถดึงข้อมูลได้ เราจะลดความเสี่ยงที่จะเกิด Bad ThingsTM ขึ้นโดยการตรวจสอบให้แน่ใจว่าโค้ดทำงานภายในแซนด์บ็อกซ์ ซึ่งจะทำให้ปลอดภัยกว่าเล็กน้อย เราจะดำเนินการโค้ดจากด้านใน โดยเริ่มจากเนื้อหาของเฟรม ดังนี้

<!-- 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() ระบบได้รวมการเรียกนี้ไว้ในบล็อกการลองแล้ว เนื่องจากการดำเนินการที่ถูกแบนภายใน 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" &amp;&amp; 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/ เฟรมหน้าอื่นในต้นทางเดียวกันที่มีแซนด์บ็อกซ์ซึ่งมีทั้งแฟล็ก allow-same-origin และ allow-scripts หน้าที่อยู่ในเฟรมจะเข้าถึงหน้าหลักและนำแอตทริบิวต์แซนด์บ็อกซ์ออกทั้งหมด

เล่นในแซนด์บ็อกซ์ของคุณ

ตอนนี้คุณใช้แซนด์บ็อกซ์ในเบราว์เซอร์ต่างๆ ได้แล้ว เช่น Firefox 17 ขึ้นไป, IE10 ขึ้นไป และ Chrome ในเวลาที่เขียน (แน่นอนว่ามีตารางการสนับสนุนล่าสุด) การใช้แอตทริบิวต์ sandbox กับ iframes ที่ระบุไว้จะช่วยให้คุณให้สิทธิ์บางอย่างแก่เนื้อหาที่แสดงได้เฉพาะสิทธิ์ที่จำเป็นเพื่อให้เนื้อหาทำงานได้อย่างถูกต้อง ซึ่งเป็นการมอบโอกาสให้คุณลดความเสี่ยงที่เกี่ยวข้องกับการรวมเนื้อหาของบุคคลที่สาม ที่มากกว่าและทำได้มากกว่าที่ทำได้ด้วยนโยบายรักษาความปลอดภัยเนื้อหา

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

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

อ่านเพิ่มเติม

  • "การแยกสิทธิ์ในแอปพลิเคชัน HTML5" เป็นบทความที่น่าสนใจเกี่ยวกับการออกแบบเฟรมเวิร์กขนาดเล็ก และการประยุกต์ใช้กับแอป HTML5 ที่มีอยู่ 3 แอป

  • แซนด์บ็อกซ์จะมีความยืดหยุ่นมากขึ้นเมื่อรวมกับแอตทริบิวต์ iframe ใหม่อีก 2 รายการ ได้แก่ srcdoc และ seamless แบบแรกจะช่วยให้คุณสร้างเฟรมที่มีเนื้อหาได้โดยไม่ต้องใช้โอเวอร์เฮดของคำขอ HTTP และแท็กแบบหลังจะช่วยให้รูปแบบแทรกลงในเนื้อหาที่เฟรม ทั้งสองมีการรองรับเบราว์เซอร์ที่ไม่ค่อยน่าพอใจอยู่ในตอนนี้ (Chrome และ WebKit ทุกคืน) แต่จะเป็นชุดค่าผสมที่น่าสนใจในอนาคต เช่น คุณอาจใส่ความคิดเห็นแบบแซนด์บ็อกซ์ในบทความผ่านโค้ดต่อไปนี้

        <iframe sandbox seamless
                srcdoc="<p>This is a user's comment!
                           It can't execute script!
                           Hooray for safety!</p>"></iframe>