هدف Sanitizer API جدید ساخت یک پردازنده قوی برای رشته های دلخواه است که با خیال راحت در یک صفحه قرار می گیرند.
برنامه ها همیشه با رشته های نامعتبر سروکار دارند، اما ارائه ایمن آن محتوا به عنوان بخشی از یک سند HTML می تواند مشکل باشد. بدون مراقبت کافی، ایجاد تصادفی فرصت هایی برای برنامه نویسی متقابل سایت (XSS) آسان است که مهاجمان مخرب ممکن است از آن سوء استفاده کنند.
برای کاهش این خطر، پیشنهاد Sanitizer API جدید با هدف ایجاد یک پردازنده قوی برای رشته های دلخواه است که به طور ایمن در یک صفحه قرار می گیرند. این مقاله API را معرفی میکند و کاربرد آن را توضیح میدهد.
// Expanded Safely !!
$div.setHTML(`<em>hello world</em><img src="" onerror=alert(0)>`, new Sanitizer())
فرار از ورودی کاربر
هنگام درج ورودی کاربر، رشته های پرس و جو، محتویات کوکی و غیره در DOM، رشته ها باید به درستی فرار شوند. توجه ویژه ای باید به دستکاری DOM از طریق .innerHTML
شود، جایی که رشته های بدون فرار منبع معمولی XSS هستند.
const user_input = `<em>hello world</em><img src="" onerror=alert(0)>`
$div.innerHTML = user_input
اگر از کاراکترهای ویژه HTML در رشته ورودی بالا فرار کنید یا آن را با استفاده از .textContent
گسترش دهید، alert(0)
اجرا نخواهد شد. با این حال، از آنجایی که <em>
اضافه شده توسط کاربر نیز به صورت رشته ای گسترش می یابد، این روش برای حفظ دکوراسیون متن در HTML قابل استفاده نیست.
بهترین کار در اینجا فرار نیست، بلکه ضدعفونی کردن است.
ضدعفونی کردن ورودی کاربر
تفاوت بین فرار و ضدعفونی کردن
فرار به جایگزینی کاراکترهای خاص HTML با موجودیت های HTML اشاره دارد.
Sanitizing به حذف قسمت های مضر معنایی (مانند اجرای اسکریپت) از رشته های HTML اشاره دارد.
مثال
در مثال قبلی، <img onerror>
باعث میشود که کنترلکننده خطا اجرا شود، اما اگر کنترلکننده onerror
حذف شود، میتوان بهطور ایمن آن را در DOM گسترش داد در حالی که <em>
دست نخورده باقی میماند.
// XSS 🧨
$div.innerHTML = `<em>hello world</em><img src="" onerror=alert(0)>`
// Sanitized ⛑
$div.innerHTML = `<em>hello world</em><img src="">`
برای پاکسازی صحیح، لازم است رشته ورودی را بهعنوان HTML تجزیه کنید، برچسبها و ویژگیهایی را که مضر تلقی میشوند حذف کنید و موارد بیضرر را حفظ کنید.
مشخصات Sanitizer API پیشنهادی با هدف ارائه چنین پردازشی به عنوان یک API استاندارد برای مرورگرها است.
API ضد عفونی کننده
Sanitizer API به روش زیر استفاده می شود:
const $div = document.querySelector('div')
const user_input = `<em>hello world</em><img src="" onerror=alert(0)>`
$div.setHTML(user_input, { sanitizer: new Sanitizer() }) // <div><em>hello world</em><img src=""></div>
با این حال، { sanitizer: new Sanitizer() }
آرگومان پیش فرض است. بنابراین می تواند درست مانند زیر باشد.
$div.setHTML(user_input) // <div><em>hello world</em><img src=""></div>
شایان ذکر است که setHTML()
بر روی Element
تعریف شده است. به عنوان یک روش Element
، زمینه تجزیه به خودی خود توضیحی است (در این مورد <div>
)، تجزیه یک بار به صورت داخلی انجام می شود و نتیجه مستقیماً به DOM گسترش می یابد.
برای دریافت نتیجه sanitization به عنوان یک رشته، می توانید از .innerHTML
از نتایج setHTML()
استفاده کنید.
const $div = document.createElement('div')
$div.setHTML(user_input)
$div.innerHTML // <em>hello world</em><img src="">
سفارشی کردن از طریق پیکربندی
Sanitizer 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" ]}) })
// <div>hello <b>world</b></div>
$div.setHTML(str, { sanitizer: new Sanitizer({blockElements: [ "b" ]}) })
// <div>hello <i>world</i></div>
$div.setHTML(str, { sanitizer: new Sanitizer({allowElements: []}) })
// <div>hello world</div>
همچنین میتوانید با گزینههای زیر کنترل کنید که ضدعفونیکننده ویژگیهای مشخصشده را مجاز یا رد کند:
-
allowAttributes
-
dropAttributes
ویژگیهای allowAttributes
و dropAttributes
انتظار لیستهای تطبیق ویژگیها را دارند - اشیایی که کلیدهای آنها نام ویژگیها هستند و مقادیر فهرستهایی از عناصر هدف یا علامت *
هستند.
const str = `<span id=foo class=bar style="color: red">hello</span>`
$div.setHTML(str)
// <div><span id="foo" class="bar" style="color: red">hello</span></div>
$div.setHTML(str, { sanitizer: new Sanitizer({allowAttributes: {"style": ["span"]}}) })
// <div><span style="color: red">hello</span></div>
$div.setHTML(str, { sanitizer: new Sanitizer({allowAttributes: {"style": ["p"]}}) })
// <div><span>hello</span></div>
$div.setHTML(str, { sanitizer: new Sanitizer({allowAttributes: {"style": ["*"]}}) })
// <div><span style="color: red">hello</span></div>
$div.setHTML(str, { sanitizer: new Sanitizer({dropAttributes: {"id": ["span"]}}) })
// <div><span class="bar" style="color: red">hello</span></div>
$div.setHTML(str, { sanitizer: new Sanitizer({allowAttributes: {}}) })
// <div>hello</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 })
// <div><custom-elem>hello</custom-elem></div>
سطح API
مقایسه با DomPurify
DOMPurify یک کتابخانه شناخته شده است که قابلیت پاکسازی را ارائه می دهد. تفاوت اصلی بین Sanitizer API و DOMPurify در این است که DOMPurify نتیجه پاکسازی را به صورت رشته ای برمی گرداند که باید از طریق .innerHTML
در یک عنصر DOM بنویسید.
const user_input = `<em>hello world</em><img src="" onerror=alert(0)>`
const sanitized = DOMPurify.sanitize(user_input)
$div.innerHTML = sanitized
// `<em>hello world</em><img src="">`
زمانی که Sanitizer API در مرورگر پیادهسازی نمیشود، DOMPurify میتواند بهعنوان یک نسخه بازگشتی عمل کند.
پیاده سازی DOMPurify چند جنبه منفی دارد. اگر رشته ای برگردانده شود، رشته ورودی دو بار توسط DOMPurify و .innerHTML
تجزیه می شود. این تجزیه مضاعف زمان پردازش را تلف میکند، اما همچنین میتواند منجر به آسیبپذیریهای جالبی شود که ناشی از مواردی است که نتیجه تجزیه دوم با اولی متفاوت است.
HTML همچنین برای تجزیه نیاز به زمینه دارد. به عنوان مثال، <td>
در <table>
معنی دارد، اما در <div>
معنی ندارد. از آنجایی که DOMPurify.sanitize()
فقط یک رشته را به عنوان آرگومان می گیرد، بافت تجزیه باید حدس می زد.
Sanitizer API رویکرد DOMPurify را بهبود می بخشد و برای حذف نیاز به تجزیه مضاعف و روشن کردن زمینه تجزیه طراحی شده است.
وضعیت API و پشتیبانی از مرورگر
Sanitizer API در فرآیند استانداردسازی در دست بحث است و Chrome در حال اجرای آن است.
مرحله | وضعیت |
---|---|
1. توضیح دهنده ایجاد کنید | کامل |
2. پیش نویس مشخصات را ایجاد کنید | کامل |
3. جمع آوری بازخورد و تکرار در طراحی | کامل |
4. آزمایش اولیه کروم | کامل |
5. راه اندازی کنید | قصد ارسال در M105 |
موزیلا: این پیشنهاد را ارزش نمونه سازی می داند و به طور فعال آن را اجرا می کند.
WebKit: پاسخ را در لیست پستی WebKit ببینید.
نحوه فعال کردن Sanitizer API
فعال کردن از طریق گزینه about://flags
یا CLI
کروم
Chrome در حال اجرای Sanitizer API است. در Chrome 93 یا جدیدتر، میتوانید با فعال کردن flags about://flags/#enable-experimental-web-platform-features
این رفتار را امتحان کنید. در نسخههای قبلی کانال Chrome Canary و Dev، میتوانید آن را از طریق --enable-blink-features=SanitizerAPI
فعال کنید و همین الان آن را امتحان کنید. دستورالعملهای نحوه اجرای Chrome با پرچمها را بررسی کنید.
فایرفاکس
فایرفاکس همچنین Sanitizer API را به عنوان یک ویژگی آزمایشی پیاده سازی می کند. برای فعال کردن آن، پرچم dom.security.sanitizer.enabled
را روی true
در about:config
تنظیم کنید.
تشخیص ویژگی
if (window.Sanitizer) {
// Sanitizer API is enabled
}
بازخورد
اگر این API را امتحان کردید و بازخوردی دارید، مایلیم آن را بشنویم. نظرات خود را در مورد مسائل مربوط به Sanitizer API GitHub به اشتراک بگذارید و با نویسندگان مشخصات و افراد علاقه مند به این API صحبت کنید.
اگر اشکال یا رفتار غیرمنتظرهای در پیادهسازی Chrome پیدا کردید، باگ را ثبت کنید تا آن را گزارش کنید . اجزای Blink>SecurityFeature>SanitizerAPI
را انتخاب کنید و جزئیات را به اشتراک بگذارید تا به پیادهسازان در ردیابی مشکل کمک کنید.
نسخه ی نمایشی
برای دیدن Sanitizer API در عمل، Sanitizer API Playground توسط Mike West را بررسی کنید:
مراجع
- مشخصات HTML Sanitizer API
- مخزن WICG/anitizer-api
- پرسشهای متداول مربوط به API ضد عفونی کننده
- اسناد مرجع HTML Sanitizer API در MDN
عکس از Towfiqu barbhuiya در Unsplash .