ปลอดภัย

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

ปกป้องบัญชีนักพัฒนาซอฟต์แวร์

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

คัดเลือกกลุ่ม

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

ไม่ใช้ HTTP

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

ขอสิทธิ์ต่ำสุด

เบราว์เซอร์ Chrome จำกัดการเข้าถึงสิทธิ์ของส่วนขยายที่ขออย่างชัดแจ้งในไฟล์ Manifest ส่วนขยายควรลดการให้สิทธิ์ให้เหลือน้อยที่สุดด้วยการลงทะเบียน API และเว็บไซต์ที่จำเป็นต้องใช้เท่านั้น

การจำกัดสิทธิ์ของส่วนขยายจะจำกัดสิ่งที่ผู้โจมตีสามารถแสวงหาประโยชน์ได้

การดึงข้อมูลแบบข้ามต้นทาง()

ส่วนขยายจะใช้ได้เฉพาะ fetch() และ XMLHttpRequest() เพื่อรับทรัพยากรจากส่วนขยายและจากโดเมนที่ระบุในสิทธิ์ โปรดทราบว่าตัวแฮนเดิลfetchในตัวทำงานของบริการจะขัดขวางการเรียกใช้ทั้ง 2 รายการ

{
  "name": "Very Secure Extension",
  "version": "1.0",
  "description": "Example of a Secure Extension",
  "host_permissions": [
    "https://developer.chrome.com/*",
    "https://*.google.com/*"
  ],
  "manifest_version": 3
}

ส่วนขยายนี้ในตัวอย่างข้างต้นขอเข้าถึงทุกสิ่งใน developer.chrome.com และโดเมนย่อยของ Google โดยใส่ "https://developer.chrome.com/*" และ "https://*.google.com/*" ไว้ในสิทธิ์ หากส่วนขยายถูกบุกรุก ส่วนขยายนั้นจะยังคงมีสิทธิ์โต้ตอบกับเว็บไซต์ที่มีคุณสมบัติตรงตามรูปแบบการจับคู่เท่านั้น ผู้โจมตีจะมีความสามารถที่จำกัดในการเข้าถึง "https://user_bank_info.com" หรือโต้ตอบกับ "https://malicious_website.com"

จำกัดช่องไฟล์ Manifest

การรวมคีย์และสิทธิ์ที่ไม่จำเป็นไว้ในไฟล์ Manifest จะสร้างช่องโหว่และทำให้มองเห็นส่วนขยายชัดขึ้น จำกัดช่องไฟล์ Manifest ไว้เฉพาะช่องที่ส่วนขยายใช้

เชื่อมต่อภายนอกได้

ใช้ช่อง "externally_connectable" เพื่อประกาศส่วนขยายและหน้าเว็บภายนอกที่ส่วนขยายจะแลกเปลี่ยนข้อมูลด้วย จำกัดบุคคลที่ส่วนขยายสามารถเชื่อมต่อกับภายนอก ไปยังแหล่งที่มาที่เชื่อถือได้

{
  "name": "Super Safe Extension",
  "externally_connectable": {
    "ids": [
      "iamafriendlyextensionhereisdatas"
    ],
    "matches": [
      "https://developer.chrome.com/*",
      "https://*.google.com/*"
    ],
    "accepts_tls_channel_id": false
  },
  ...
}

แหล่งข้อมูลที่เข้าถึงได้บนเว็บ

การทำให้เว็บเข้าถึงทรัพยากรได้ ใต้ส่วน "web_accessible_resources" จะทำให้เว็บไซต์และผู้โจมตีตรวจจับส่วนขยายได้

{
  ...
  "web_accessible_resources": [
    {
      "resources": [ "test1.png", "test2.png" ],
      "matches": [ "https://web-accessible-resources-1.glitch.me/*" ]
    }
  ]
  ...
}

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

มีนโยบายรักษาความปลอดภัยเนื้อหาที่อาจไม่เหมาะสม

ใส่นโยบายรักษาความปลอดภัยเนื้อหาสำหรับส่วนขยายในไฟล์ Manifest เพื่อป้องกันการโจมตีแบบ Cross-site Scripting หากส่วนขยายโหลดเฉพาะทรัพยากรจากตัวเองเท่านั้น ให้ทำดังนี้

{
  "name": "Very Secure Extension",
  "version": "1.0",
  "description": "Example of a Secure Extension",
   "content_security_policy": {
    "extension_pages": "default-src 'self'"
  },
  "manifest_version": 3
}

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

{
  "name": "Very Secure Extension",
  "version": "1.0",
  "description": "Example of a Secure Extension",
   "content_security_policy": {
    "extension_pages": "script-src 'self' 'wasm-unsafe-eval'; object-src 'self';",
    "sandboxed_pages":"script-src 'self' 'wasm-unsafe-eval'; object-src 'self';"
  },

  "manifest_version": 3
}

หลีกเลี่ยง document.write() และ inlineHTML

แม้ว่าการสร้างองค์ประกอบ HTML แบบไดนามิกด้วย document.write() และ innerHTML อาจเป็นวิธีที่ง่ายกว่า แต่เครื่องมือจะออกจากส่วนขยายไว้ และหน้าเว็บที่ส่วนขยายต้องพึ่งพิงและเปิดให้ผู้โจมตีที่แทรกสคริปต์ที่เป็นอันตรายได้ แต่ให้สร้างโหนด DOM ด้วยตนเองและใช้ innerText เพื่อแทรกเนื้อหาแบบไดนามิก

function constructDOM() {
  let newTitle = document.createElement('h1');
  newTitle.innerText = host;
  document.appendChild(newTitle);
}

ใช้สคริปต์เนื้อหาอย่างระมัดระวัง

แม้ว่าสคริปต์เนื้อหาจะอยู่ในโลกที่แยกตัวออกมา แต่สคริปต์เหล่านี้ก็ไม่ได้รับการป้องกันจากการโจมตี โดยมีรายละเอียดดังนี้

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

การดำเนินการที่ใช้ข้อมูลที่ละเอียดอ่อน (เช่น ข้อมูลส่วนตัวของผู้ใช้) หรือ Chrome API ที่มีสิทธิ์เข้าถึงฟังก์ชันของเบราว์เซอร์ควรดำเนินการใน Service Worker ของส่วนขยาย วิธีหลีกเลี่ยงการแสดงสิทธิ์ของส่วนขยายกับสคริปต์เนื้อหาโดยไม่ตั้งใจ

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

ลงทะเบียนและดูแลข้อมูลอินพุต

ป้องกันส่วนขยายจากสคริปต์ที่เป็นอันตรายโดยจำกัดผู้ฟังให้แสดงเฉพาะสิ่งที่ส่วนขยายคาดหวัง ตรวจสอบผู้ส่งข้อมูลที่เข้ามาใหม่ และล้างอินพุตทั้งหมด

ส่วนขยายควรลงทะเบียนสำหรับ runtime.onMessageExternal เท่านั้น หากคาดว่าจะได้รับการสื่อสารจากเว็บไซต์หรือส่วนขยายภายนอก ตรวจสอบว่าผู้ส่งตรงกับ แหล่งข้อมูลที่เชื่อถือเสมอ

// The ID of an external extension
const kFriendlyExtensionId = "iamafriendlyextensionhereisdatas";

chrome.runtime.onMessageExternal.addListener(
  function(request, sender, sendResponse) {
    if (sender.id === kFriendlyExtensionId)
      doSomething();
});

แม้แต่ข้อความผ่านเหตุการณ์ runtime.onMessage จากส่วนขยายเองก็ควรได้รับการตรวจสอบเพื่อให้แน่ใจว่า MessageSender ไม่ได้มาจากสคริปต์เนื้อหาที่ถูกบุกรุก

chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
  if (request.allowedAction)
    console.log("This is an allowed action.");
});