ระบบส่วนขยายของ Chrome บังคับใช้นโยบายรักษาความปลอดภัยเนื้อหา (CSP) เริ่มต้นที่เข้มงวด
ข้อจำกัดของนโยบายไม่ซับซ้อน กล่าวคือต้องย้ายสคริปต์ออกนอกบรรทัดแยกต่างหาก
ต้องแปลงไฟล์ JavaScript, เครื่องจัดการเหตุการณ์ในบรรทัดเพื่อใช้ addEventListener
และ eval()
คือ
ปิดใช้อยู่ แอป Chrome มีนโยบายที่เข้มงวดยิ่งขึ้น และเราค่อนข้างพอใจกับความปลอดภัย
ที่นโยบายเหล่านี้ระบุไว้
อย่างไรก็ตาม เราตระหนักดีว่าไลบรารีต่างๆ ใช้โครงสร้างที่คล้ายกับ eval()
และ eval
เช่น
new Function()
เพื่อการเพิ่มประสิทธิภาพการทำงานและความสะดวกในการแสดงผล ไลบรารีที่มีการเผยแพร่
มีแนวโน้มที่จะติดตั้งใช้งานรูปแบบนี้เป็นพิเศษ แม้ว่าบางโปรแกรม (เช่น Angular.js) จะรองรับ CSP
เฟรมเวิร์กยอดนิยมจำนวนมาก ยังไม่ได้อัปเดตให้เป็นกลไกที่เข้ากันได้กับ
ส่วนขยาย โลกที่น้อยลง eval
การยกเลิกการสนับสนุนฟังก์ชันดังกล่าวจึงเป็นข้อพิสูจน์ว่า
เกิดปัญหากว่าที่คาดไว้สำหรับนักพัฒนาซอฟต์แวร์
เอกสารนี้แนะนำว่าแซนด์บ็อกซ์เป็นกลไกที่ปลอดภัยในการรวมไลบรารีเหล่านี้ไว้ในโปรเจ็กต์ของคุณ โดยไม่กระทบต่อความปลอดภัย เพื่อความกระชับ เราจะใช้คำว่าส่วนขยายทั่วทั้ง จะนำแนวคิดนี้ไปประยุกต์ใช้กับแอปพลิเคชันอย่างเท่าเทียมกัน
ทำไมต้องใช้แซนด์บ็อกซ์
eval
เป็นอันตรายภายในส่วนขยายเนื่องจากโค้ดที่เรียกใช้มีสิทธิ์เข้าถึงทุกอย่างใน
สภาพแวดล้อมที่มีสิทธิ์สูงของส่วนขยาย มี API ของ chrome.*
จำนวนมากที่มีประสิทธิภาพซึ่งอาจช่วย
สร้างผลกระทบอย่างมากต่อความปลอดภัยและความเป็นส่วนตัวของผู้ใช้ การขโมยข้อมูลอย่างง่ายๆ ทำให้เราเป็นกังวลน้อยที่สุด
โซลูชันที่เรานำเสนอคือแซนด์บ็อกซ์ที่ eval
เรียกใช้โค้ดได้โดยไม่ต้องเข้าถึง
ข้อมูลของส่วนขยายหรือ API มูลค่าสูงของส่วนขยาย ไม่มีข้อมูล API ก็ไม่มีปัญหา
เราดำเนินการได้โดยระบุไฟล์ HTML ที่เฉพาะเจาะจงภายในแพ็กเกจส่วนขยายว่าเป็นแบบแซนด์บ็อกซ์
เมื่อใดก็ตามที่โหลดหน้าที่ใช้แซนด์บ็อกซ์ หน้าจะถูกย้ายไปยังต้นทางที่ไม่ซ้ำและถูกปฏิเสธ
เข้าถึง chrome.*
API หากเราโหลดหน้าแซนด์บ็อกซ์นี้ลงในส่วนขยายผ่าน iframe
เราจะสามารถ
ส่งต่อและปล่อยให้ระบบดำเนินการกับข้อความเหล่านั้น และรอให้ระบบส่งกลับ
ผลลัพธ์ กลไกการรับส่งข้อความที่เรียบง่ายนี้ให้ทุกสิ่งที่จำเป็นแก่เราได้อย่างปลอดภัย ซึ่งรวมถึงการขับเคลื่อนด้วย eval
ในเวิร์กโฟลว์ของส่วนขยายของเรา
การสร้างและใช้แซนด์บ็อกซ์
หากคุณต้องการเจาะลึกโค้ดโดยตรง โปรดดูส่วนขยายตัวอย่างแซนด์บ็อกซ์และดู ปิดอยู่ เป็นตัวอย่างการทำงานของ API การรับส่งข้อความขนาดเล็กที่ด้านบนของแถบควบคุม และควรให้ทุกสิ่งที่คุณต้องการในการทำงาน สำหรับคนที่อยากดู ซึ่งเราจะอธิบายเพิ่มเติม ให้ดูตัวอย่างนี้พร้อมกัน
แสดงรายการไฟล์ในไฟล์ Manifest
แต่ละไฟล์ที่ควรเรียกใช้ภายในแซนด์บ็อกซ์ต้องระบุในไฟล์ Manifest ของส่วนขยายด้วยการเพิ่ม
พร็อพเพอร์ตี้ sandbox
ขั้นตอนนี้เป็นขั้นตอนสำคัญ และง่ายที่จะลืม ดังนั้น โปรดตรวจสอบอีกครั้งว่า
ไฟล์ที่ทำแซนด์บ็อกซ์จะแสดงอยู่ในไฟล์ Manifest ในตัวอย่างนี้ เรากำลังแซนด์บ็อกซ์ไฟล์อย่างชาญฉลาด
ชื่อ "sandbox.html" รายการไฟล์ Manifest มีลักษณะดังนี้
{
...,
"sandbox": {
"pages": ["sandbox.html"]
},
...
}
โหลดไฟล์ที่ทำแซนด์บ็อกซ์
ในการสร้างสิ่งที่น่าสนใจกับไฟล์ที่ทำแซนด์บ็อกซ์ เราต้องโหลดไฟล์ในบริบทที่
ก็แก้ไขได้ด้วยโค้ดของส่วนขยาย ที่นี่เราได้โหลด sandbox.html ลงใน
หน้าเหตุการณ์ (eventpage.html) ของส่วนขยายผ่าน iframe
eventpage.js มีโค้ด
ซึ่งจะส่งข้อความไปยังแซนด์บ็อกซ์เมื่อใดก็ตามที่มีการคลิกการทำงานของเบราว์เซอร์ โดยการค้นหา iframe
ในหน้า และเรียกใช้เมธอด postMessage
ใน contentWindow
ข้อความเป็นออบเจ็กต์
ที่มีพร็อพเพอร์ตี้ 2 รายการ ได้แก่ context
และ command
เราจะเจาะลึกเกี่ยวกับทั้งสองนี้ในอีกสักครู่
chrome.browserAction.onClicked.addListener(function() {
var iframe = document.getElementById('theFrame');
var message = {
command: 'render',
context: {thing: 'world'}
};
iframe.contentWindow.postMessage(message, '*');
});
postMessage
API ได้ที่เอกสารประกอบ postMessage
เกี่ยวกับ MDN เอกสารนี้ครบถ้วนสมบูรณ์และควรค่าแก่การอ่าน โดยเฉพาะอย่างยิ่ง โปรดทราบว่าข้อมูลจะส่งต่อกลับมาได้ต่อเมื่อเรียงลำดับได้เท่านั้น ตัวอย่างเช่น ฟังก์ชันไม่เป็นเช่นนั้นทำสิ่งที่เป็นอันตราย
เมื่อโหลด sandbox.html
แอปจะโหลดไลบรารีของแถบควบคุม รวมทั้งสร้างและคอมไพล์แบบอินไลน์
ตามวิธีที่แฮนด์บาร์แนะนำ:
<script src="handlebars-1.0.0.beta.6.js"></script>
<script id="hello-world-template" type="text/x-handlebars-template">
<div class="entry">
<h1>Hello, !</h1>
</div>
</script>
<script>
var templates = [];
var source = document.getElementById('hello-world-template').innerHTML;
templates['hello'] = Handlebars.compile(source);
</script>
นี่ไม่ล้มเหลว แม้ว่า Handlebars.compile
จะใช้ new Function
แล้ว แต่ก็ยังมีสิ่งต่างๆ อยู่
ตามที่คาดไว้ และในที่สุดเราก็ได้เทมเพลตที่รวบรวมไว้ใน templates['hello']
ส่งผลลัพธ์กลับมา
เราจะทำให้เทมเพลตนี้พร้อมใช้งานโดยการตั้งค่า Listener ข้อความที่ยอมรับคำสั่ง
จากหน้ากิจกรรม เราจะใช้ command
ที่ผ่านมาเพื่อกำหนดว่าควรทำอย่างไร (คุณสามารถ
ลองจินตนาการว่าทำได้มากกว่าแค่การแสดงภาพ อาจกำลังสร้างเทมเพลต อาจจัดการ
) และระบบจะส่ง context
ไปยังเทมเพลตโดยตรงเพื่อแสดงผล HTML ที่แสดงผล
จะถูกส่งกลับไปยังหน้ากิจกรรมเพื่อให้ส่วนขยายสามารถทำสิ่งที่มีประโยชน์กับคุณในภายหลัง
<script>
window.addEventListener('message', function(event) {
var command = event.data.command;
var name = event.data.name || 'hello';
switch(command) {
case 'render':
event.source.postMessage({
name: name,
html: templates[name](event.data.context)
}, event.origin);
break;
// case 'somethingElse':
// ...
}
});
</script>
กลับไปที่หน้ากิจกรรม เราได้รับข้อความนี้ พร้อมกับทำสิ่งที่น่าสนใจกับ html
ซึ่งเราส่งผ่านไป ในกรณีนี้ เราจะแสดงข้อความผ่านการแจ้งเตือนบนเดสก์ท็อป
คุณสามารถใช้ HTML นี้เป็นส่วนหนึ่งของ UI ของส่วนขยายได้อย่างปลอดภัย แทรกผ่าน
innerHTML
ไม่ทำให้เกิดความเสี่ยงด้านความปลอดภัยมากนัก แม้ว่าจะถูกบุกรุกจากแซนด์บ็อกซ์โดยสมบูรณ์ก็ตาม
ผ่านการโจมตีที่ชาญฉลาดบางอย่างจะไม่สามารถแทรกเนื้อหาสคริปต์หรือปลั๊กอินที่เป็นอันตรายลงใน
บริบทของส่วนขยายที่มีสิทธิ์สูง
กลไกนี้ทำให้การจัดทำเทมเพลตเป็นเรื่องง่าย แต่แน่นอนว่าไม่จำกัดเพียงเทมเพลต ช่วง โค้ดที่ทำงานนอกกรอบภายใต้นโยบายรักษาความปลอดภัยเนื้อหาที่เข้มงวดสามารถใช้แซนด์บ็อกซ์ได้ ใน ที่จริงแล้ว มักมีประโยชน์กับคอมโพเนนต์แซนด์บ็อกซ์ของส่วนขยายที่จะทำงานได้อย่างถูกต้องตามลำดับ เพื่อจำกัดสิทธิ์ของแต่ละโปรแกรมไว้ในส่วนสิทธิ์ที่มีขนาดเล็กที่สุดที่จำเป็นต่อการดำเนินการ ดำเนินการได้อย่างถูกต้อง งานนำเสนอเรื่องการเขียนเว็บแอปและส่วนขยาย Chrome ที่ปลอดภัยจาก Google ตัวอย่างที่ดีของการนำเทคนิคเหล่านี้ไปใช้จริงในงาน I/O ปี 2012 และเป็นเวลา 56 นาที