স্যানিটাইজার API এর সাথে নিরাপদ DOM ম্যানিপুলেশন

নতুন স্যানিটাইজার এপিআই-এর লক্ষ্য হল একটি শক্তিশালী প্রসেসর তৈরি করা যাতে কোনও পৃষ্ঠায় নিরাপদে স্ট্রিং ঢোকানো যায়।

জ্যাক জে
Jack J

অ্যাপ্লিকেশনগুলি সর্বদা অবিশ্বস্ত স্ট্রিংগুলির সাথে মোকাবিলা করে, কিন্তু HTML ডকুমেন্টের অংশ হিসাবে সেই সামগ্রীটি নিরাপদে রেন্ডার করা জটিল হতে পারে। পর্যাপ্ত যত্ন ছাড়াই, দুর্ঘটনাক্রমে ক্রস-সাইট স্ক্রিপ্টিং (XSS) এর জন্য সুযোগ তৈরি করা সহজ যা দূষিত আক্রমণকারীরা কাজে লাগাতে পারে।

এই ঝুঁকি কমাতে, নতুন স্যানিটাইজার API প্রস্তাবের লক্ষ্য হল একটি শক্তিশালী প্রসেসর তৈরি করা যাতে কোনও পৃষ্ঠায় নিরাপদে স্ট্রিংগুলি সন্নিবেশ করা যায়। এই নিবন্ধটি API-এর সাথে পরিচয় করিয়ে দেয় এবং এর ব্যবহার ব্যাখ্যা করে।

// Expanded Safely !!
$div.setHTML(`<em>hello world</em><img src="" onerro>r=alert(0)`, new Sanitizer())

ব্যবহারকারীর ইনপুট এড়িয়ে যাওয়া

DOM-এ ব্যবহারকারীর ইনপুট, কোয়েরি স্ট্রিং, কুকি কন্টেন্ট ইত্যাদি প্রবেশ করানোর সময়, স্ট্রিংগুলিকে সঠিকভাবে এস্কেপ করতে হবে। .innerHTML এর মাধ্যমে DOM ম্যানিপুলেশনের দিকে বিশেষ মনোযোগ দেওয়া উচিত, যেখানে আনএসকেপড স্ট্রিংগুলি XSS-এর একটি সাধারণ উৎস।

const user_input = `<em>hello world</em><img src="" onerro>r=alert(0)`
$div.innerHTML = user_input

যদি আপনি উপরের ইনপুট স্ট্রিংয়ে HTML স্পেশাল ক্যারেক্টার এড়িয়ে যান অথবা .textContent ব্যবহার করে এটি প্রসারিত করেন, তাহলে alert(0) কার্যকর হবে না। তবে, যেহেতু ব্যবহারকারীর দ্বারা যোগ করা <em> স্ট্রিং হিসাবেও প্রসারিত হয়, তাই HTML-এ টেক্সট ডেকোরেশন ধরে রাখার জন্য এই পদ্ধতিটি ব্যবহার করা যাবে না।

এখানে সবচেয়ে ভালো কাজ হলো পালানো নয়, বরং জীবাণুমুক্ত করা

ব্যবহারকারীর ইনপুট স্যানিটাইজ করা হচ্ছে

পালানো এবং জীবাণুমুক্ত করার মধ্যে পার্থক্য

এস্কেপিং বলতে বিশেষ HTML অক্ষরগুলিকে HTML Entities দিয়ে প্রতিস্থাপন করাকে বোঝায়।

স্যানিটাইজিং বলতে HTML স্ট্রিং থেকে অর্থগতভাবে ক্ষতিকারক অংশ (যেমন স্ক্রিপ্ট এক্সিকিউশন) অপসারণকে বোঝায়।

উদাহরণ

পূর্ববর্তী উদাহরণে, <img onerror> এর ফলে ত্রুটি হ্যান্ডলারটি কার্যকর করা হয়, কিন্তু যদি onerror হ্যান্ডলারটি সরানো হয়, তাহলে <em> অক্ষত রেখে DOM-এ এটি নিরাপদে প্রসারিত করা সম্ভব হবে।

// XSS 🧨
$div.innerHTML = `<em>hello world</em><img src="" onerro>r=alert(0)`
// Sanitized ⛑
$div.inn<er>HTML = `emh<ell><o world/em>img src=""`

সঠিকভাবে স্যানিটাইজ করার জন্য, ইনপুট স্ট্রিংটিকে HTML হিসাবে পার্স করা, ক্ষতিকারক বলে বিবেচিত ট্যাগ এবং বৈশিষ্ট্যগুলি বাদ দেওয়া এবং ক্ষতিকারকগুলি রাখা প্রয়োজন।

প্রস্তাবিত স্যানিটাইজার এপিআই স্পেসিফিকেশনের লক্ষ্য হল ব্রাউজারগুলির জন্য একটি স্ট্যান্ডার্ড এপিআই হিসাবে এই প্রক্রিয়াকরণ প্রদান করা।

স্যানিটাইজার এপিআই

স্যানিটাইজার API নিম্নলিখিত উপায়ে ব্যবহার করা হয়:

const $div = document.querySelector('div')
const user_i<np>ut = `emhel<lo ><world/emimg src="">; onerror=alert(0)`
$div.setHTML(user_input, { sanitizer: new <San><it>izer() }) /</ d><ivemhello ><worl>d/emimg src=""/div

তবে, { sanitizer: new Sanitizer() } হল ডিফল্ট আর্গুমেন্ট। তাই এটি ঠিক নীচের মত হতে পারে।

$div.setHTML(user_input) // <div><em>hello world</em><img src=&q><uot;>&quot;/div

এটি লক্ষণীয় যে setHTML() Element এ সংজ্ঞায়িত করা হয়েছে। Element এর একটি পদ্ধতি হওয়ায়, পার্স করার প্রসঙ্গটি স্ব-ব্যাখ্যামূলক ( <div> এই ক্ষেত্রে), পার্সিংটি একবার অভ্যন্তরীণভাবে করা হয় এবং ফলাফলটি সরাসরি DOM-এ প্রসারিত হয়।

স্ট্রিং হিসেবে স্যানিটাইজেশনের ফলাফল পেতে, আপনি setHTML() ফলাফল থেকে .innerHTML ব্যবহার করতে পারেন।

const $div = document.createElement('div')
$div.setHTML(user_input)
$div.inner<HT>ML // emhel<lo ><world/emim>g src=""

কনফিগারেশনের মাধ্যমে কাস্টমাইজ করুন

স্যানিটাইজার API ডিফল্টরূপে স্ক্রিপ্ট এক্সিকিউশন ট্রিগার করতে পারে এমন স্ট্রিংগুলি সরানোর জন্য কনফিগার করা হয়। তবে, আপনি একটি কনফিগারেশন অবজেক্টের মাধ্যমে স্যানিটাইজেশন প্রক্রিয়ায় আপনার নিজস্ব কাস্টমাইজেশনও যোগ করতে পারেন।

const config = {
  allowElements: [],
  blockElements: [],
  dropElements: [],
  allowAttributes: {},
  dropAttributes: {},
  allowCustomElements: true,
  allowComments: true
};
// sanitized result is customized by configuration
new Sanitizer(config)

নিম্নলিখিত বিকল্পগুলি নির্দিষ্ট উপাদানটিকে স্যানিটাইজেশনের ফলাফল কীভাবে ব্যবহার করা উচিত তা নির্দিষ্ট করে।

allowElements : স্যানিটাইজারের যেসব উপাদান ধরে রাখা উচিত তার নাম।

blockElements : স্যানিটাইজারের যেসব উপাদান অপসারণ করা উচিত, সেইসব উপাদানের নাম, এবং একই সাথে তাদের সন্তানদেরও ধরে রাখা উচিত।

dropElements : স্যানিটাইজারের যেসব উপাদান অপসারণ করা উচিত, তাদের সন্তানদের নাম সহ।

const str = `hello <b><i>world</i></b>`

$div.setHTML(str)
// <div>hello <b><i>world</i></b></div>

$div.setHTML(str, { sanitizer: new Sanitizer({allowElements: [ "b" <]})> })
//< >divhe<ll><o bw>orld/b/div

$div.setHTML(str, { sanitizer: new Sanitizer({blockElements: [ &quo<t;b>"< >]}) }<)<>/span>
<// d>ivhello iworld/i/div

$div.setHTML(str, { sanitizer: new Sanitizer({allowE<lem>ents: []}) <})
/>/ divhello world/div

আপনি নিম্নলিখিত বিকল্পগুলির সাহায্যে স্যানিটাইজার নির্দিষ্ট বৈশিষ্ট্যগুলিকে অনুমতি দেবে নাকি অস্বীকার করবে তাও নিয়ন্ত্রণ করতে পারেন:

  • allowAttributes
  • dropAttributes

allowAttributes এবং dropAttributes বৈশিষ্ট্যগুলি অ্যাট্রিবিউট মিল তালিকাগুলি আশা করে — এমন বস্তু যার কীগুলি অ্যাট্রিবিউটের নাম এবং মানগুলি লক্ষ্য উপাদানগুলির তালিকা বা * ওয়াইল্ডকার্ড।

const str = `<span id=foo class=bar style="color:> red&<quot;>hello/span`

$div.setHTM<L(s><tr)
// divspan id="foo" class=&quo>t;bar<"><; st>yle="color: red"hello/span/div

$div.setHTML(str, { sanitizer: new Sanitizer({allow<Att><ributes: {"style&q>uot;:< [&qu><ot;s>pan"]}}) })
// divspan style="color: red"hello/span/div

$div.setHTML(str, <{ s><anit>izer:< new ><Sani>tizer({allowAttributes: {"style": ["p"]}}) })
// divspanhello/span/div<

$><div.setHTML(str, { sani>tizer<: new>< San>itizer({allowAttributes: {"style": ["*"]}}) })
// divspan style="<;co><lor: red"hello/span/div

$div.>setHT<ML(st><r, {> sanitizer: new Sanitizer({dropAttributes: {"id": ["span"<;]}>}) })<
// >divspan class="bar" style="color: red"hello/span/div

$div.setHTML(str, { sanitizer: new Sanitizer({allowAttributes: {}}) })
// divhello/div

allowCustomElements হল কাস্টম উপাদানগুলিকে অনুমতি দেওয়ার বা অস্বীকার করার বিকল্প। যদি সেগুলি অনুমোদিত হয়, তবে উপাদান এবং বৈশিষ্ট্যগুলির জন্য অন্যান্য কনফিগারেশনগুলি এখনও প্রযোজ্য।

const str = `<custom-elem>hello</custom-elem>`

$div.setHTML(str)
// <div></div>

const sanitizer = new Sanitizer({
  allowCustomElements: true,
  allowElements: ["div", "custom-elem"]
})
$div.setHTML(str<, {>< sanitizer >})
//< divcustom-e><lemh>ello/custom-elem/div

এপিআই সারফেস

ডোমপিউরিফাইয়ের সাথে তুলনা

DOMPurify একটি সুপরিচিত লাইব্রেরি যা স্যানিটাইজেশন কার্যকারিতা প্রদান করে। স্যানিটাইজার API এবং DOMPurify এর মধ্যে প্রধান পার্থক্য হল যে DOMPurify স্যানিটাইজেশনের ফলাফলকে একটি স্ট্রিং হিসাবে ফেরত দেয়, যা আপনাকে .innerHTML এর মাধ্যমে একটি DOM উপাদানে লিখতে হবে।

const user_input = `<em>hello world</em><img src="" onerro>r=alert(0)`
const sanitized = DOMPurify.sanitize(user_input)
$div.innerHTML = sani<ti>zed
// `emh<ell><o world/em>img src=""`

ব্রাউজারে স্যানিটাইজার API বাস্তবায়িত না হলে DOMPurify একটি ফলব্যাক হিসেবে কাজ করতে পারে।

DOMPurify বাস্তবায়নের কয়েকটি অসুবিধা রয়েছে। যদি একটি স্ট্রিং ফেরত দেওয়া হয়, তাহলে ইনপুট স্ট্রিংটি DOMPurify এবং .innerHTML দ্বারা দুবার পার্স করা হয়। এই ডাবল পার্সিং প্রক্রিয়াকরণের সময় নষ্ট করে, তবে দ্বিতীয় পার্সিংয়ের ফলাফল প্রথমটির থেকে ভিন্ন হলে আকর্ষণীয় দুর্বলতাও দেখা দিতে পারে।

HTML-এর জন্যও প্রসঙ্গ বিশ্লেষণ করা প্রয়োজন। উদাহরণস্বরূপ, <table> তে <td> অর্থবহ, কিন্তু <div> তে নয়। যেহেতু DOMPurify.sanitize() শুধুমাত্র একটি স্ট্রিংকে আর্গুমেন্ট হিসেবে গ্রহণ করে, তাই পার্সিং প্রসঙ্গটি অনুমান করতে হয়েছিল।

স্যানিটাইজার API DOMPurify পদ্ধতির উপর উন্নত এবং ডাবল পার্সিংয়ের প্রয়োজনীয়তা দূর করার জন্য এবং পার্সিং প্রেক্ষাপট স্পষ্ট করার জন্য ডিজাইন করা হয়েছে।

API অবস্থা এবং ব্রাউজার সমর্থন

স্যানিটাইজার এপিআই স্ট্যান্ডার্ডাইজেশন প্রক্রিয়ার মধ্যে আলোচনার অধীনে রয়েছে এবং ক্রোম এটি বাস্তবায়নের প্রক্রিয়াধীন রয়েছে।

ধাপ অবস্থা
১. ব্যাখ্যাকারী তৈরি করুন সম্পূর্ণ
2. স্পেসিফিকেশন খসড়া তৈরি করুন সম্পূর্ণ
৩. মতামত সংগ্রহ করুন এবং নকশার উপর পুনরাবৃত্তি করুন সম্পূর্ণ
৪. ক্রোম অরিজিন ট্রায়াল সম্পূর্ণ
৫. লঞ্চ M105 তে পাঠানোর উদ্দেশ্য

মজিলা: এই প্রস্তাবটিকে প্রোটোটাইপ করার যোগ্য বলে মনে করে এবং সক্রিয়ভাবে এটি বাস্তবায়ন করছে।

ওয়েবকিট: ওয়েবকিট মেইলিং লিস্টে প্রতিক্রিয়া দেখুন।

স্যানিটাইজার API কীভাবে সক্ষম করবেন

Browser Support

  • ক্রোম: সমর্থিত নয়।
  • প্রান্ত: সমর্থিত নয়।
  • ফায়ারফক্স প্রযুক্তি পূর্বরূপ: সমর্থিত।
  • সাফারি: সমর্থিত নয়।

about://flags অথবা CLI বিকল্পের মাধ্যমে সক্ষম করা হচ্ছে

ক্রোম

Chrome স্যানিটাইজার API বাস্তবায়নের প্রক্রিয়াধীন। Chrome 93 বা তার পরবর্তী সংস্করণে, আপনি about://flags/#enable-experimental-web-platform-features ফ্ল্যাগ সক্ষম করে এই আচরণটি চেষ্টা করে দেখতে পারেন। Chrome Canary এবং Dev চ্যানেলের পূর্ববর্তী সংস্করণগুলিতে, আপনি --enable-blink-features=SanitizerAPI এর মাধ্যমে এটি সক্ষম করতে পারেন এবং এখনই এটি চেষ্টা করে দেখতে পারেন। flags দিয়ে Chrome কীভাবে চালানো যায় তার নির্দেশাবলী দেখুন।

ফায়ারফক্স

Firefox একটি পরীক্ষামূলক বৈশিষ্ট্য হিসেবে Sanitizer API প্রয়োগ করে। এটি সক্রিয় করতে, about:configdom.security.sanitizer.enabled ফ্ল্যাগটিকে true এ সেট করুন।

বৈশিষ্ট্য সনাক্তকরণ

if (window.Sanitizer) {
  // Sanitizer API is enabled
}

প্রতিক্রিয়া

আপনি যদি এই APIটি ব্যবহার করে দেখেন এবং আপনার কোন প্রতিক্রিয়া থাকে, তাহলে আমরা এটি শুনতে আগ্রহী। স্যানিটাইজার API GitHub সমস্যা সম্পর্কে আপনার মতামত শেয়ার করুন এবং এই API-তে আগ্রহী স্পেক লেখক এবং ব্যক্তিদের সাথে আলোচনা করুন।

যদি আপনি Chrome এর বাস্তবায়নে কোনও বাগ বা অপ্রত্যাশিত আচরণ খুঁজে পান, তাহলে এটি রিপোর্ট করার জন্য একটি বাগ ফাইল করুনBlink>SecurityFeature>SanitizerAPI উপাদানগুলি নির্বাচন করুন এবং বাস্তবায়নকারীদের সমস্যাটি ট্র্যাক করতে সহায়তা করার জন্য বিশদ ভাগ করুন।

ডেমো

স্যানিটাইজার এপিআই কীভাবে কার্যকরীভাবে কাজ করছে তা দেখতে মাইক ওয়েস্টের স্যানিটাইজার এপিআই প্লেগ্রাউন্ডটি দেখুন:

তথ্যসূত্র


আনস্প্ল্যাশে ছবি তুলেছেন তৌফিক বারভূইয়া