اسکریپت های محتوا

اسکریپت‌های محتوا فایل‌هایی هستند که در چارچوب صفحات وب اجرا می‌شوند. آن‌ها با استفاده از مدل شیءگرای سند (DOM) استاندارد، قادر به خواندن جزئیات صفحات وبی هستند که مرورگر بازدید می‌کند، تغییراتی در آن‌ها ایجاد می‌کند و اطلاعات را به افزونه والد خود منتقل می‌کند.

قابلیت‌های اسکریپت محتوا را درک کنید

اسکریپت‌های محتوا می‌توانند مستقیماً به APIهای افزونه‌های زیر دسترسی داشته باشند:

اسکریپت‌های محتوا نمی‌توانند مستقیماً به سایر APIها دسترسی داشته باشند. اما می‌توانند با تبادل پیام با سایر بخش‌های افزونه شما، به طور غیرمستقیم به آنها دسترسی پیدا کنند.

همچنین می‌توانید با استفاده از APIهایی مانند fetch() از طریق یک اسکریپت محتوا به فایل‌های دیگر در افزونه خود دسترسی پیدا کنید. برای انجام این کار، باید آنها را به عنوان منابع قابل دسترسی از طریق وب اعلام کنید. توجه داشته باشید که این کار منابع را در معرض هرگونه اسکریپت شخص ثالث یا شخص ثالثی که در همان سایت اجرا می‌شوند نیز قرار می‌دهد.

کار در جهان‌های منزوی

اسکریپت‌های محتوا در یک دنیای ایزوله قرار دارند و به یک اسکریپت محتوا اجازه می‌دهند بدون ایجاد تداخل با اسکریپت‌های محتوای صفحه یا سایر افزونه‌ها، در محیط جاوا اسکریپت خود تغییراتی ایجاد کند.

یک افزونه ممکن است در یک صفحه وب با کدی مشابه مثال زیر اجرا شود.

صفحه وب.html

<html>
  <button id="mybutton">click me</button>
  <script>
    var greeting = "hello, ";
    var button = document.getElementById("mybutton");
    button.person_name = "Bob";
    button.addEventListener(
        "click", () => alert(greeting + button.person_name + "."), false);
  </script>
</html>

آن افزونه می‌تواند اسکریپت محتوای زیر را با استفاده از یکی از تکنیک‌های ذکر شده در بخش تزریق اسکریپت‌ها تزریق کند.

اسکریپت محتوا.js

var greeting = "hola, ";
var button = document.getElementById("mybutton");
button.person_name = "Roberto";
button.addEventListener(
    "click", () => alert(greeting + button.person_name + "."), false);

با این تغییر، هر دو هشدار به ترتیب با کلیک روی دکمه ظاهر می‌شوند.

تزریق اسکریپت‌ها

اسکریپت‌های محتوا می‌توانند به صورت ایستا ، پویا یا تزریق برنامه‌نویسی‌شده تعریف شوند.

تزریق با اعلان‌های استاتیک

برای اسکریپت‌هایی که باید به‌طور خودکار روی مجموعه‌ای از صفحات شناخته‌شده اجرا شوند، از اعلان‌های اسکریپت محتوای استاتیک در manifest.json استفاده کنید.

اسکریپت‌های استاتیک تعریف‌شده در مانیفست تحت کلید "content_scripts" ثبت می‌شوند. آن‌ها می‌توانند شامل فایل‌های جاوا اسکریپت، فایل‌های CSS یا هر دو باشند. همه اسکریپت‌های محتوای خودکار باید الگوهای منطبق را مشخص کنند.

مانیفست.json

{
 "name": "My extension",
 ...
 "content_scripts": [
   {
     "matches": ["https://*.nytimes.com/*"],
     "css": ["my-styles.css"],
     "js": ["content-script.js"]
   }
 ],
 ...
}

نام نوع توضیحات
matches آرایه‌ای از رشته‌ها الزامی. مشخص می‌کند که این اسکریپت محتوا به کدام صفحات تزریق خواهد شد. برای جزئیات بیشتر در مورد نحو این رشته‌ها به Match Patterns و برای اطلاعات در مورد نحوه حذف URLها به Match patterns and globs مراجعه کنید.
css آرایه‌ای از رشته‌ها اختیاری. فهرست فایل‌های CSS که باید به صفحات منطبق تزریق شوند. این فایل‌ها به ترتیبی که در این آرایه ظاهر می‌شوند، قبل از ساخت یا نمایش هرگونه DOM برای صفحه، تزریق می‌شوند.
js آرایه‌ای از رشته‌ها اختیاری. فهرست فایل‌های جاوا اسکریپتی که باید به صفحات منطبق تزریق شوند. فایل‌ها به ترتیبی که در این آرایه ظاهر می‌شوند تزریق می‌شوند. هر رشته در این فهرست باید حاوی یک مسیر نسبی به منبعی در دایرکتوری ریشه افزونه باشد. اسلش‌های (`/`) در ابتدای هر رشته به طور خودکار حذف می‌شوند.
run_at اجرا کن اختیاری. مشخص می‌کند که اسکریپت چه زمانی باید به صفحه تزریق شود. مقدار پیش‌فرض document_idle است.
match_about_blank بولی اختیاری. اینکه آیا اسکریپت باید در یک قاب about:blank تزریق شود که در آن قاب والد یا قاب آغازین با یکی از الگوهای اعلام شده در matches مطابقت دارد. پیش‌فرض روی false است.
match_origin_as_fallback بولی اختیاری. اینکه آیا اسکریپت باید در فریم‌هایی که توسط یک مبدا منطبق ایجاد شده‌اند، اما URL یا مبدا آنها ممکن است مستقیماً با الگو مطابقت نداشته باشد، تزریق شود یا خیر. این فریم‌ها شامل فریم‌هایی با طرح‌های مختلف، مانند about: data: blob: و filesystem: می‌شوند. همچنین به تزریق در فریم‌های مرتبط مراجعه کنید.
world دنیای اعدام اختیاری. دنیای جاوا اسکریپت برای اجرای یک اسکریپت در داخل آن. مقدار پیش‌فرض آن ISOLATED است. همچنین به بخش «کار در دنیاهای ایزوله» مراجعه کنید.

در یک مرحله مشخص از چرخه حیات سند، اسکریپت‌های محتوایی که به صورت ایستا در مانیفست اعلام شده‌اند، اولین اسکریپت‌هایی هستند که تزریق می‌شوند، قبل از اینکه اسکریپت‌های محتوایی به هر روش دیگری ثبت شوند. آنها به ترتیبی که در مانیفست مشخص شده‌اند، تزریق می‌شوند.

تزریق با اعلان‌های پویا

اسکریپت‌های محتوای پویا زمانی مفید هستند که الگوهای تطبیق برای اسکریپت‌های محتوا به خوبی شناخته شده نباشند یا زمانی که اسکریپت‌های محتوا نباید همیشه روی میزبان‌های شناخته شده تزریق شوند.

اعلان‌های پویا که در کروم ۹۶ معرفی شدند، مشابه اعلان‌های ایستا هستند، اما شیء اسکریپت محتوا با استفاده از متدهایی در فضای نام chrome.scripting به جای manifest.json در کروم ثبت می‌شود. API اسکریپت همچنین به توسعه‌دهندگان افزونه‌ها اجازه می‌دهد تا:

مانند اعلان‌های ایستا، اعلان‌های پویا می‌توانند شامل فایل‌های جاوا اسکریپت، فایل‌های CSS یا هر دو باشند.

سرویس-ورکر.js

chrome.scripting
  .registerContentScripts([{
    id: "session-script",
    js: ["content.js"],
    persistAcrossSessions: false,
    matches: ["*://example.com/*"],
    runAt: "document_start",
  }])
  .then(() => console.log("registration complete"))
  .catch((err) => console.warn("unexpected error", err))

سرویس-ورکر.js

chrome.scripting
  .updateContentScripts([{
    id: "session-script",
    excludeMatches: ["*://admin.example.com/*"],
  }])
  .then(() => console.log("registration updated"));

سرویس-ورکر.js

chrome.scripting
  .getRegisteredContentScripts()
  .then(scripts => console.log("registered content scripts", scripts));

سرویس-ورکر.js

chrome.scripting
  .unregisterContentScripts({ ids: ["session-script"] })
  .then(() => console.log("un-registration complete"));

تزریق به صورت برنامه‌نویسی‌شده

از تزریق برنامه‌ریزی‌شده برای اسکریپت‌های محتوایی که باید در پاسخ به رویدادها یا در موارد خاص اجرا شوند، استفاده کنید.

برای تزریق اسکریپت محتوا به صورت برنامه‌نویسی‌شده، افزونه شما به مجوزهای میزبان برای صفحه‌ای که سعی در تزریق اسکریپت‌ها به آن دارد، نیاز دارد. مجوزهای میزبان را می‌توان با درخواست آنها به عنوان بخشی از مانیفست افزونه یا به طور موقت با استفاده از "activeTab" اعطا کرد.

در ادامه نسخه‌های مختلفی از یک افزونه مبتنی بر activeTab ارائه شده است.

مانیفست.json:

{
  "name": "My extension",
  ...
  "permissions": [
    "activeTab",
    "scripting"
  ],
  "background": {
    "service_worker": "background.js"
  },
  "action": {
    "default_title": "Action Button"
  }
}

اسکریپت‌های محتوا می‌توانند به صورت فایل تزریق شوند.

اسکریپت محتوا.js


document.body.style.backgroundColor = "orange";

سرویس-ورکر.js:

chrome.action.onClicked.addListener((tab) => {
  chrome.scripting.executeScript({
    target: { tabId: tab.id },
    files: ["content-script.js"]
  });
});

یا، می‌توان بدنه‌ی یک تابع را تزریق و به عنوان یک اسکریپت محتوا اجرا کرد.

سرویس-ورکر.js:

function injectedFunction() {
  document.body.style.backgroundColor = "orange";
}

chrome.action.onClicked.addListener((tab) => {
  chrome.scripting.executeScript({
    target : {tabId : tab.id},
    func : injectedFunction,
  });
});

توجه داشته باشید که تابع تزریق‌شده یک کپی از تابعی است که در فراخوانی chrome.scripting.executeScript() به آن ارجاع داده شده است، نه خود تابع اصلی. در نتیجه، بدنه تابع باید مستقل باشد؛ ارجاع به متغیرهای خارج از تابع باعث می‌شود که اسکریپت محتوا ReferenceError را نمایش دهد.

هنگام تزریق به عنوان یک تابع، می‌توانید آرگومان‌هایی را نیز به تابع ارسال کنید.

سرویس-ورکر.js

function injectedFunction(color) {
  document.body.style.backgroundColor = color;
}

chrome.action.onClicked.addListener((tab) => {
  chrome.scripting.executeScript({
    target : {tabId : tab.id},
    func : injectedFunction,
    args : [ "orange" ],
  });
});

حذف تطابق‌ها و جانشین‌ها

برای سفارشی‌سازی تطبیق صفحه مشخص‌شده، فیلدهای زیر را در یک ثبت اعلانی وارد کنید.

نام نوع توضیحات
exclude_matches آرایه‌ای از رشته‌ها اختیاری. صفحاتی را که این اسکریپت محتوا در غیر این صورت به آنها تزریق می‌شد، شامل نمی‌شود. برای جزئیات بیشتر در مورد نحو این رشته‌ها، به الگوهای تطبیق مراجعه کنید.
include_globs آرایه‌ای از رشته‌ها اختیاری. بعد از matches اعمال می‌شود تا فقط URLهایی را که با این glob مطابقت دارند، شامل شود. این برای شبیه‌سازی کلمه کلیدی @include Greasemonkey در نظر گرفته شده است.
exclude_globs آرایه‌ای از رشته اختیاری. پس از matches اعمال می‌شود تا URLهایی که با این glob مطابقت دارند، حذف شوند. هدف از این کار شبیه‌سازی کلمه کلیدی @exclude Greasemonkey است.

اگر هر دو مورد زیر درست باشند، اسکریپت محتوا به صفحه تزریق می‌شود:

  • آدرس اینترنتی (URL) آن با هر الگوی matches و هر الگوی include_globs مطابقت دارد.
  • این URL با الگوی exclude_matches یا exclude_globs نیز مطابقت ندارد. از آنجا که ویژگی matches الزامی است، exclude_matches ، include_globs و exclude_globs فقط می‌توانند برای محدود کردن صفحاتی که تحت تأثیر قرار می‌گیرند، استفاده شوند.

افزونه‌ی زیر اسکریپت محتوا را به https://www.nytimes.com/health تزریق می‌کند اما به https://www.nytimes.com/business تزریق نمی‌کند.

مانیفست.json

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["https://*.nytimes.com/*"],
      "exclude_matches": ["*://*/*business*"],
      "js": ["contentScript.js"]
    }
  ],
  ...
}

سرویس-ورکر.js

chrome.scripting.registerContentScripts([{
  id : "test",
  matches : [ "https://*.nytimes.com/*" ],
  excludeMatches : [ "*://*/*business*" ],
  js : [ "contentScript.js" ],
}]);

ویژگی‌های جانشین (glob) از سینتکس متفاوت و انعطاف‌پذیرتری نسبت به الگوهای تطبیق پیروی می‌کنند. رشته‌های جانشین قابل قبول، URLهایی هستند که ممکن است حاوی ستاره‌های "wildcard" و علامت سوال باشند. ستاره ( * ) با هر رشته‌ای با هر طولی، از جمله رشته خالی، مطابقت دارد، در حالی که علامت سوال ( ? ) با هر کاراکتر واحدی مطابقت دارد.

برای مثال، glob https://???.example.com/foo/\* با هر یک از موارد زیر مطابقت دارد:

  • https://www.example.com/foo/bar
  • https://the.example.com/foo/

با این حال، با موارد زیر مطابقت ندارد :

  • https://my.example.com/foo/bar
  • https://example.com/foo/
  • https://www.example.com/foo

این افزونه اسکریپت محتوا را به https://www.nytimes.com/arts/index.html و https://www.nytimes.com/jobs/index.htm* تزریق می‌کند، اما به https://www.nytimes.com/sports/index.html تزریق نمی‌کند:

مانیفست.json

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["https://*.nytimes.com/*"],
      "include_globs": ["*nytimes.com/???s/*"],
      "js": ["contentScript.js"]
    }
  ],
  ...
}

این افزونه اسکریپت محتوا را به https://history.nytimes.com و https://.nytimes.com/history تزریق می‌کند، اما به https://science.nytimes.com یا https://www.nytimes.com/science تزریق نمی‌کند:

مانیفست.json

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["https://*.nytimes.com/*"],
      "exclude_globs": ["*science*"],
      "js": ["contentScript.js"]
    }
  ],
  ...
}

برای دستیابی به محدوده صحیح، می‌توان یکی، همه یا برخی از این موارد را در نظر گرفت.

مانیفست.json

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["https://*.nytimes.com/*"],
      "exclude_matches": ["*://*/*business*"],
      "include_globs": ["*nytimes.com/???s/*"],
      "exclude_globs": ["*science*"],
      "js": ["contentScript.js"]
    }
  ],
  ...
}

زمان اجرا

فیلد run_at زمان تزریق فایل‌های جاوا اسکریپت به صفحه وب را کنترل می‌کند. مقدار ترجیحی و پیش‌فرض "document_idle" است. برای سایر مقادیر ممکن، به نوع RunAt مراجعه کنید.

مانیفست.json

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["https://*.nytimes.com/*"],
      "run_at": "document_idle",
      "js": ["contentScript.js"]
    }
  ],
  ...
}

سرویس-ورکر.js

chrome.scripting.registerContentScripts([{
  id : "test",
  matches : [ "https://*.nytimes.com/*" ],
  runAt : "document_idle",
  js : [ "contentScript.js" ],
}]);
نام نوع توضیحات
document_idle رشته ترجیح داده می‌شود. هر زمان که ممکن است از "document_idle" استفاده کنید.

مرورگر زمانی را برای تزریق اسکریپت‌ها بین "document_end" و بلافاصله پس از اجرای رویداد window.onload انتخاب می‌کند. لحظه دقیق تزریق به پیچیدگی سند و مدت زمان بارگذاری آن بستگی دارد و برای سرعت بارگذاری صفحه بهینه شده است.

اسکریپت‌های محتوایی که در "document_idle" اجرا می‌شوند، نیازی به گوش دادن به رویداد window.onload ندارند، آنها تضمین می‌کنند که پس از تکمیل DOM اجرا شوند. اگر یک اسکریپت قطعاً نیاز به اجرا پس از window.onload داشته باشد، افزونه می‌تواند با استفاده از ویژگی document.readyState بررسی کند که آیا onload قبلاً اجرا شده است یا خیر.
document_start رشته اسکریپت‌ها بعد از هر فایلی از css تزریق می‌شوند، اما قبل از اینکه هر DOM دیگری ساخته شود یا هر اسکریپت دیگری اجرا شود.
document_end رشته اسکریپت‌ها بلافاصله پس از تکمیل DOM تزریق می‌شوند، اما قبل از اینکه منابع فرعی مانند تصاویر و فریم‌ها بارگذاری شوند.

فریم‌ها را مشخص کنید

برای اسکریپت‌های محتوای اعلانی مشخص‌شده در مانیفست، فیلد "all_frames" به افزونه اجازه می‌دهد تا مشخص کند که آیا فایل‌های جاوا اسکریپت و CSS باید به تمام فریم‌هایی که با الزامات URL مشخص‌شده مطابقت دارند تزریق شوند یا فقط به بالاترین فریم در یک تب:

مانیفست.json

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["https://*.nytimes.com/*"],
      "all_frames": true,
      "js": ["contentScript.js"]
    }
  ],
  ...
}

هنگام ثبت اسکریپت‌های محتوا از طریق برنامه‌نویسی با استفاده از chrome.scripting.registerContentScripts(...) ، می‌توان از پارامتر allFrames برای تعیین اینکه آیا اسکریپت محتوا باید به تمام فریم‌هایی که با الزامات URL مشخص شده مطابقت دارند تزریق شود یا فقط به بالاترین فریم در یک تب، استفاده کرد. این فقط با tabId قابل استفاده است و در صورت مشخص بودن frameIds یا documentIds قابل استفاده نیست:

سرویس-ورکر.js

chrome.scripting.registerContentScripts([{
  id: "test",
  matches : [ "https://*.nytimes.com/*" ],
  allFrames : true,
  js : [ "contentScript.js" ],
}]);

افزونه‌ها ممکن است بخواهند اسکریپت‌هایی را در فریم‌هایی اجرا کنند که به یک فریم منطبق مرتبط هستند، اما خودشان با آن فریم مطابقت ندارند. یک سناریوی رایج در این مورد، فریم‌هایی با URLهایی هستند که توسط یک فریم منطبق ایجاد شده‌اند، اما URLهای آنها با الگوهای مشخص شده اسکریپت مطابقت ندارند.

این مورد زمانی اتفاق می‌افتد که یک افزونه بخواهد فریم‌هایی با URLهایی که طرح‌های about: data: blob: و filesystem: دارند را تزریق کند. در این موارد، URL با الگوی اسکریپت محتوا مطابقت نخواهد داشت (و در مورد about: و data: حتی URL والد یا مبدا را در URL وارد نکنید، مانند about:blank یا data:text/html,<html>Hello, World!</html> ). با این حال، این فریم‌ها هنوز هم می‌توانند با فریم ایجادکننده مرتبط باشند.

برای تزریق به این فریم‌ها، افزونه‌ها می‌توانند ویژگی "match_origin_as_fallback" را در مشخصات اسکریپت محتوا در مانیفست مشخص کنند.

مانیفست.json

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["https://*.google.com/*"],
      "match_origin_as_fallback": true,
      "js": ["contentScript.js"]
    }
  ],
  ...
}

وقتی مشخص شده و روی true تنظیم شده باشد، کروم برای تعیین اینکه آیا فریم مطابقت دارد یا خیر، به جای URL خود فریم، به مبدأ آغازگر فریم نگاه می‌کند. توجه داشته باشید که این ممکن است با مبدأ فریم هدف نیز متفاوت باشد (مثلاً data: URLها مبدأ تهی دارند).

آغازگر فریم، فریمی است که فریم هدف را ایجاد یا پیمایش کرده است. اگرچه این معمولاً والد مستقیم یا آغازگر است، اما ممکن است اینطور نباشد (مانند موردی که یک فریم، یک iframe را درون یک iframe دیگر پیمایش می‌کند).

از آنجا که این مقایسه، مبدأ فریم آغازگر را نشان می‌دهد، فریم آغازگر می‌تواند در هر مسیری از آن مبدأ روشن باشد. برای روشن شدن این مفهوم، کروم از هر اسکریپت محتوایی که با "match_origin_as_fallback" روی true تنظیم شده باشد، می‌خواهد که مسیر * را نیز مشخص کند.

وقتی هر دو "match_origin_as_fallback" و "match_about_blank" مشخص شده باشند، "match_origin_as_fallback" اولویت پیدا می‌کند.

ارتباط با صفحه جاسازی

اگرچه محیط‌های اجرای اسکریپت‌های محتوا و صفحاتی که میزبان آنها هستند از یکدیگر جدا هستند، اما به DOM صفحه دسترسی مشترک دارند. اگر صفحه بخواهد از طریق اسکریپت محتوا با اسکریپت محتوا یا با افزونه ارتباط برقرار کند، باید این کار را از طریق DOM مشترک انجام دهد.

یک مثال را می‌توان با استفاده از window.postMessage() انجام داد:

اسکریپت محتوا.js

var port = chrome.runtime.connect();

window.addEventListener("message", (event) => {
  // We only accept messages from ourselves
  if (event.source !== window) {
    return;
  }

  if (event.data.type && (event.data.type === "FROM_PAGE")) {
    console.log("Content script received: " + event.data.text);
    port.postMessage(event.data.text);
  }
}, false);

مثال.js

document.getElementById("theButton").addEventListener("click", () => {
  window.postMessage(
      {type : "FROM_PAGE", text : "Hello from the webpage!"}, "*");
}, false);

صفحه غیر افزونه، example.html، پیام‌هایی را برای خودش ارسال می‌کند. این پیام توسط اسکریپت محتوا رهگیری و بررسی شده و سپس به فرآیند افزونه ارسال می‌شود. به این ترتیب، صفحه یک خط ارتباطی با فرآیند افزونه ایجاد می‌کند. عکس این عمل نیز از طریق روش‌های مشابه امکان‌پذیر است.

دسترسی به فایل‌های افزونه

برای دسترسی به یک فایل افزونه از طریق اسکریپت محتوا، می‌توانید chrome.runtime.getURL() را فراخوانی کنید تا URL مطلق فایل افزونه خود را همانطور که در مثال زیر نشان داده شده است ( content.js ) دریافت کنید:

اسکریپت محتوا.js

let image = chrome.runtime.getURL("images/my_image.png")

برای استفاده از فونت‌ها یا تصاویر در یک فایل CSS، می‌توانید @@extension_id برای ساخت یک URL مانند مثال زیر ( content.css ) استفاده کنید:

محتوا.css

body {
 background-image:url('chrome-extension://__MSG_@@extension_id__/background.png');
}

@font-face {
 font-family: 'Stint Ultra Expanded';
 font-style: normal;
 font-weight: 400;
 src: url('chrome-extension://__MSG_@@extension_id__/fonts/Stint Ultra Expanded.woff') format('woff');
}

تمام دارایی‌ها باید به عنوان منابع قابل دسترسی از طریق وب در فایل manifest.json تعریف شوند:

مانیفست.json

{
 ...
 "web_accessible_resources": [
   {
     "resources": [ "images/*.png" ],
     "matches": [ "https://example.com/*" ]
   },
   {
     "resources": [ "fonts/*.woff" ],
     "matches": [ "https://example.com/*" ]
   }
 ],
 ...
}

سیاست امنیت محتوا

اسکریپت‌های محتوایی که در جهان‌های ایزوله اجرا می‌شوند، سیاست امنیتی محتوای (CSP) زیر را دارند:

script-src 'self' 'wasm-unsafe-eval' 'inline-speculation-rules' chrome-extension://abcdefghijklmopqrstuvwxyz/; object-src 'self';

مشابه محدودیت‌های اعمال‌شده بر سایر زمینه‌های افزونه، این مورد از استفاده از eval() و همچنین بارگیری اسکریپت‌های خارجی جلوگیری می‌کند.

برای افزونه‌های بدون بسته‌بندی، CSP شامل localhost نیز می‌شود:

script-src 'self' 'wasm-unsafe-eval' 'inline-speculation-rules' http://localhost:* http://127.0.0.1:* chrome-extension://abcdefghijklmopqrstuvwxyz/; object-src 'self';

وقتی یک اسکریپت محتوا به دنیای اصلی تزریق می‌شود، CSP صفحه اعمال می‌شود.

ایمن بمانید

در حالی که جهان‌های ایزوله یک لایه محافظتی ایجاد می‌کنند، استفاده از اسکریپت‌های محتوا می‌تواند باعث ایجاد آسیب‌پذیری در یک افزونه و صفحه وب شود. اگر اسکریپت محتوا، محتوا را از یک وب‌سایت جداگانه دریافت می‌کند، مثلاً با فراخوانی fetch() ، مراقب باشید که قبل از تزریق، محتوا را در برابر حملات اسکریپت‌نویسی بین‌سایتی فیلتر کنید. برای جلوگیری از حملات "مرد میانی"، فقط از طریق HTTPS ارتباط برقرار کنید.

حتماً صفحات وب مخرب را فیلتر کنید. برای مثال، الگوهای زیر خطرناک هستند و در Manifest V3 مجاز نیستند:

نکن

اسکریپت محتوا.js

const data = document.getElementById("json-data");
// WARNING! Might be evaluating an evil script!
const parsed = eval("(" + data + ")");
نکن

اسکریپت محتوا.js

const elmt_id = ...
// WARNING! elmt_id might be '); ... evil script ... //'!
window.setTimeout("animate(" + elmt_id + ")", 200);

در عوض، API های امن‌تری را ترجیح دهید که اسکریپت اجرا نمی‌کنند:

انجام دهید

اسکریپت محتوا.js

const data = document.getElementById("json-data")
// JSON.parse does not evaluate the attacker's scripts.
const parsed = JSON.parse(data);
انجام دهید

اسکریپت محتوا.js

const elmt_id = ...
// The closure form of setTimeout does not evaluate scripts.
window.setTimeout(() => animate(elmt_id), 200);