ปลอดภัย

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

ปกป้องบัญชีนักพัฒนาแอป

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

ใช้บทบาทสมาชิกที่เหมาะสม

หากผู้เผยแพร่โฆษณามีสมาชิกหลายคน โปรดตรวจสอบว่าบทบาทที่มอบให้ผู้ใช้แต่ละคน เหมาะสม

ห้ามใช้ HTTP

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

ขอสิทธิ์ขั้นต่ำ

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

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

fetch() แบบข้ามต้นทาง

ส่วนขยายจะใช้ได้เฉพาะ fetch() และ XMLHttpRequest() เพื่อรับทรัพยากรจากส่วนขยายและจากโดเมนที่ระบุในสิทธิ์เท่านั้น โปรดทราบว่าตัวแฮนเดิล fetch ใน Service Worker จะสกัดกั้นการเรียกทั้ง 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
}

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

{
  "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() และ innerHTML

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

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

ใช้ Content Script อย่างรอบคอบ

แม้ว่าContent Script จะอยู่ในโลกที่แยกจากกัน แต่ก็ไม่ได้ปลอดภัยจากการโจมตี

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

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

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

ลงทะเบียนและปรับปรุงอินพุต

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

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

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

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

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

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