স্যান্ডবক্সড আইফ্রেমে eval() ব্যবহার করুন

Chrome এর এক্সটেনশন সিস্টেম একটি মোটামুটি কঠোর ডিফল্ট সামগ্রী নিরাপত্তা নীতি (CSP) প্রয়োগ করে৷ নীতির বিধিনিষেধগুলি সহজবোধ্য: স্ক্রিপ্টকে অবশ্যই আলাদা জাভাস্ক্রিপ্ট ফাইলে লাইনের বাইরে সরানো উচিত, addEventListener ব্যবহার করার জন্য ইনলাইন ইভেন্ট হ্যান্ডলারদের রূপান্তর করতে হবে এবং eval() অক্ষম করা হয়েছে৷

যাইহোক, আমরা স্বীকার করি যে বিভিন্ন ধরনের লাইব্রেরি কর্মক্ষমতা অপ্টিমাইজেশান এবং প্রকাশের সহজতার জন্য eval() এবং eval এর মতো গঠন যেমন new Function() ব্যবহার করে। টেমপ্লেটিং লাইব্রেরিগুলি বিশেষভাবে প্রয়োগের এই শৈলীর জন্য প্রবণ। যদিও কিছু কিছু (যেমন Angular.js ) বাক্সের বাইরে CSP সমর্থন করে, অনেক জনপ্রিয় ফ্রেমওয়ার্ক এখনও এমন একটি মেকানিজম আপডেট করেনি যা এক্সটেনশনের eval -লেস ওয়ার্ল্ডের সাথে সামঞ্জস্যপূর্ণ। সেই কার্যকারিতার জন্য সমর্থন অপসারণ তাই বিকাশকারীদের জন্য প্রত্যাশার চেয়ে বেশি সমস্যাযুক্ত প্রমাণিত হয়েছে।

এই নথিটি নিরাপত্তার সাথে আপস না করে আপনার প্রকল্পগুলিতে এই লাইব্রেরিগুলিকে অন্তর্ভুক্ত করার জন্য একটি নিরাপদ প্রক্রিয়া হিসাবে স্যান্ডবক্সিং প্রবর্তন করে৷

কেন স্যান্ডবক্স?

eval একটি এক্সটেনশনের ভিতরে বিপজ্জনক কারণ এটি যে কোডটি কার্যকর করে তার এক্সটেনশনের উচ্চ-অনুমতি পরিবেশের সমস্ত কিছুতে অ্যাক্সেস রয়েছে। একগুচ্ছ শক্তিশালী chrome.* API পাওয়া যায় যা ব্যবহারকারীর নিরাপত্তা এবং গোপনীয়তাকে মারাত্মকভাবে প্রভাবিত করতে পারে; সহজ ডেটা এক্সফিল্ট্রেশন আমাদের উদ্বেগের মধ্যে সবচেয়ে কম। অফারে সমাধান হল একটি স্যান্ডবক্স যেখানে eval এক্সটেনশনের ডেটা বা এক্সটেনশনের উচ্চ-মূল্যের APIগুলিতে অ্যাক্সেস ছাড়াই কোড কার্যকর করতে পারে৷ কোন ডেটা, কোন API, কোন সমস্যা নেই।

আমরা এক্সটেনশন প্যাকেজের ভিতরে নির্দিষ্ট HTML ফাইলগুলিকে স্যান্ডবক্স করা হিসাবে তালিকাভুক্ত করে এটি সম্পন্ন করি। যখনই একটি স্যান্ডবক্সযুক্ত পৃষ্ঠা লোড করা হয়, এটি একটি অনন্য উত্সে সরানো হবে এবং chrome.* APIs৷ যদি আমরা একটি iframe এর মাধ্যমে আমাদের এক্সটেনশনে এই স্যান্ডবক্স করা পৃষ্ঠাটি লোড করি, তাহলে আমরা এটিকে বার্তা পাঠাতে পারি, এটিকে সেই বার্তাগুলির উপর কোনোভাবে কাজ করতে দিতে পারি এবং এটি আমাদেরকে একটি ফলাফল ফিরিয়ে দেওয়ার জন্য অপেক্ষা করতে পারি। এই সহজ মেসেজিং মেকানিজম আমাদেরকে আমাদের এক্সটেনশনের ওয়ার্কফ্লোতে eval -চালিত কোড নিরাপদে অন্তর্ভুক্ত করার জন্য প্রয়োজনীয় সবকিছু দেয়।

একটি স্যান্ডবক্স তৈরি করুন এবং ব্যবহার করুন

আপনি যদি সরাসরি কোডে ডুব দিতে চান, স্যান্ডবক্সিং নমুনা এক্সটেনশনটি ধরুন এবং টেক অফ করুন । এটি হ্যান্ডেলবার টেমপ্লেটিং লাইব্রেরির উপরে নির্মিত একটি ক্ষুদ্র বার্তাপ্রেরণ API এর একটি কার্যকরী উদাহরণ, এবং এটি আপনাকে যেতে যা যা প্রয়োজন তা আপনাকে দিতে হবে। আপনারা যারা একটু বেশি ব্যাখ্যা চান তাদের জন্য, আসুন এখানে একসাথে সেই নমুনাটি দেখি।

ম্যানিফেস্টে ফাইলের তালিকা করুন

প্রতিটি ফাইল যা একটি স্যান্ডবক্সের ভিতরে চালানো উচিত একটি sandbox বৈশিষ্ট্য যোগ করে এক্সটেনশন ম্যানিফেস্টে তালিকাভুক্ত করা আবশ্যক৷ এটি একটি গুরুত্বপূর্ণ পদক্ষেপ, এবং এটি ভুলে যাওয়া সহজ, তাই আপনার স্যান্ডবক্স করা ফাইলটি ম্যানিফেস্টে তালিকাভুক্ত হয়েছে কিনা তা দুবার চেক করুন৷ এই নমুনায়, আমরা চতুরতার সাথে "sandbox.html" নামের ফাইলটিকে স্যান্ডবক্সিং করছি। ম্যানিফেস্ট এন্ট্রি এই মত দেখায়:

{
  ...,
  "sandbox": {
     "pages": ["sandbox.html"]
  },
  ...
}

স্যান্ডবক্স করা ফাইলটি লোড করুন

স্যান্ডবক্স করা ফাইলের সাথে আকর্ষণীয় কিছু করার জন্য, আমাদের এটিকে এমন একটি প্রসঙ্গে লোড করতে হবে যেখানে এটি এক্সটেনশনের কোড দ্বারা সম্বোধন করা যেতে পারে। এখানে, sandbox.html একটি iframe এর মাধ্যমে একটি এক্সটেনশন পৃষ্ঠায় লোড করা হয়েছে। পৃষ্ঠার জাভাস্ক্রিপ্ট ফাইলে এমন কোড রয়েছে যা ব্রাউজার অ্যাকশনটিতে ক্লিক করা হলে স্যান্ডবক্সে একটি বার্তা পাঠায় পৃষ্ঠায় iframe খুঁজে বের করে এবং তার contentWindowpostMessage() কল করে। বার্তাটি এমন একটি বস্তু যার মধ্যে তিনটি বৈশিষ্ট্য রয়েছে: context , templateName , এবং command । আমরা একটি মুহূর্ত মধ্যে context এবং command মধ্যে ডুব করব.

service-worker.js:

chrome.action.onClicked.addListener(() => {
  chrome.tabs.create({
    url: 'mainpage.html'
  });
  console.log('Opened a tab with a sandboxed page!');
});

extension-page.js:

let counter = 0;
document.addEventListener('DOMContentLoaded', () => {
  document.getElementById('reset').addEventListener('click', function () {
    counter = 0;
    document.querySelector('#result').innerHTML = '';
  });

  document.getElementById('sendMessage').addEventListener('click', function () {
    counter++;
    let message = {
      command: 'render',
      templateName: 'sample-template-' + counter,
      context: { counter: counter }
    };
    document.getElementById('theFrame').contentWindow.postMessage(message, '*');
  });

বিপজ্জনক কিছু করুন

যখন sandbox.html লোড করা হয়, তখন এটি হ্যান্ডেলবার লাইব্রেরি লোড করে এবং হ্যান্ডেলবার যেভাবে পরামর্শ দেয় সেভাবে একটি ইনলাইন টেমপ্লেট তৈরি ও সংকলন করে:

extension-page.html:

<!DOCTYPE html>
<html>
  <head>
    <script src="mainpage.js"></script>
    <link href="styles/main.css" rel="stylesheet" />
  </head>
  <body>
    <div id="buttons">
      <button id="sendMessage">Click me</button>
      <button id="reset">Reset counter</button>
    </div>

    <div id="result"></div>

    <iframe id="theFrame" src="sandbox.html" style="display: none"></iframe>
  </body>
</html>

sandbox.html:

   <script id="sample-template-1" type="text/x-handlebars-template">
      <div class='entry'>
        <h1>Hello</h1>
        <p>This is a Handlebar template compiled inside a hidden sandboxed
          iframe.</p>
        <p>The counter parameter from postMessage() (outer frame) is:
          </p>
      </div>
    </script>

    <script id="sample-template-2" type="text/x-handlebars-template">
      <div class='entry'>
        <h1>Welcome back</h1>
        <p>This is another Handlebar template compiled inside a hidden sandboxed
          iframe.</p>
        <p>The counter parameter from postMessage() (outer frame) is:
          </p>
      </div>
    </script>

এই ব্যর্থ হয় না! যদিও Handlebars.compile new Function ব্যবহার করে শেষ হয়, জিনিসগুলি প্রত্যাশিতভাবে কাজ করে, এবং আমরা templates['hello']

ফলাফল ফিরে পাস

আমরা একটি বার্তা শ্রোতা সেট আপ করে এই টেমপ্লেটটিকে ব্যবহারের জন্য উপলব্ধ করব যা এক্সটেনশন পৃষ্ঠা থেকে কমান্ড গ্রহণ করে৷ কী করা উচিত তা নির্ধারণ করতে আমরা পাস করা command ব্যবহার করব (আপনি কেবল রেন্ডারিংয়ের চেয়ে আরও বেশি কিছু করার কল্পনা করতে পারেন; সম্ভবত টেমপ্লেট তৈরি করা? সম্ভবত সেগুলিকে কোনও উপায়ে পরিচালনা করা?), এবং রেন্ডারিংয়ের জন্য context সরাসরি টেমপ্লেটে পাস করা হবে . রেন্ডার করা এইচটিএমএল এক্সটেনশন পৃষ্ঠায় ফেরত পাঠানো হবে যাতে এক্সটেনশনটি পরে এটির সাথে কিছু কার্যকর করতে পারে:

 <script>
      const templatesElements = document.querySelectorAll(
        "script[type='text/x-handlebars-template']"
      );
      let templates = {},
        source,
        name;

      // precompile all templates in this page
      for (let i = 0; i < templatesElements.length; i++) {
        source = templatesElements[i].innerHTML;
        name = templatesElements[i].id;
        templates[name] = Handlebars.compile(source);
      }

      // Set up message event handler:
      window.addEventListener('message', function (event) {
        const command = event.data.command;
        const template = templates[event.data.templateName];
        let result = 'invalid request';

       // if we don't know the templateName requested, return an error message
        if (template) {
          switch (command) {
            case 'render':
              result = template(event.data.context);
              break;
            // you could even do dynamic compilation, by accepting a command
            // to compile a new template instead of using static ones, for example:
            // case 'new':
            //   template = Handlebars.compile(event.data.templateSource);
            //   result = template(event.data.context);
            //   break;
              }
        } else {
            result = 'Unknown template: ' + event.data.templateName;
        }
        event.source.postMessage({ result: result }, event.origin);
      });
    </script>

এক্সটেনশন পৃষ্ঠায় ফিরে, আমরা এই বার্তাটি পাব, এবং আমাদের পাস করা html ডেটা নিয়ে আকর্ষণীয় কিছু করব৷ এই ক্ষেত্রে, আমরা শুধুমাত্র একটি বিজ্ঞপ্তির মাধ্যমে এটিকে প্রতিধ্বনিত করব, কিন্তু এক্সটেনশনের UI-এর অংশ হিসাবে এই HTMLটিকে নিরাপদে ব্যবহার করা সম্পূর্ণরূপে সম্ভব৷ innerHTML এর মাধ্যমে এটি সন্নিবেশ করানো একটি উল্লেখযোগ্য নিরাপত্তা ঝুঁকি তৈরি করে না কারণ আমরা স্যান্ডবক্সের মধ্যে রেন্ডার করা বিষয়বস্তুকে বিশ্বাস করি।

এই প্রক্রিয়াটি টেমপ্লেটিংকে সহজ করে তোলে, তবে এটি অবশ্যই টেমপ্লেটিং এর মধ্যে সীমাবদ্ধ নয়। কন্টেন্ট নিরাপত্তা নীতির অধীনে বাক্সের বাইরে কাজ করে না এমন যেকোনো কোড স্যান্ডবক্স করা যেতে পারে; প্রকৃতপক্ষে, এটি প্রায়ই আপনার এক্সটেনশনের স্যান্ডবক্স উপাদানগুলির জন্য দরকারী যেগুলি সঠিকভাবে চালানোর জন্য আপনার প্রোগ্রামের প্রতিটি অংশকে সঠিকভাবে চালানোর জন্য প্রয়োজনীয় বিশেষাধিকারগুলির ক্ষুদ্রতম সেটে সীমাবদ্ধ করতে। Google I/O 2012-এর রাইটিং সিকিউর ওয়েব অ্যাপস এবং ক্রোম এক্সটেনশন উপস্থাপনা এই কৌশলগুলির কার্যকর কিছু উদাহরণ দেয়, এবং এটি আপনার সময়ের 56 মিনিটের মূল্য।