چگونه در React حمله XSS بخوریم!


میدانیم که XSS یک آسیب‌پذیری امنیتی وب است که به مهاجم امکان اجرای کدهای مخرب جاوااسکریپتی را در مرورگر قربانی می‌دهد که می تواند کاربر را به سایت‌های مخرب هدایت کند یا در سایت خرابی‌هایی را ایجاد کند.
خوشبختانه React چند کار برای محافظت از برنامه ما در برابر حملات XSS انجام می‌دهد. React عناصر و داده‌های داخل آن را با استفاده از auto escaping خروجی می‌دهد.همه چیز در داخل عنصر را بعنوان یک رشته تفسیر می‌کند و هیچ عنصر اضافی را ارائه نمی‌کند.
این بدان معناست که اگر مقدار داخل عنصر به نحوی توسط یک attacker با برخی تگ‌های نفوذ می‌کرد، React به‌سادگی آن را نادیده می‌گرفت و آن را بعنوان یک رشته در نظر می‌گرفت.

خروجی کد بالا در مرورگر
خروجی کد بالا در مرورگر

همانطور که مشاهده می‌کنید کاربر بعد از فشردن دکمه تایید متن را تغییر داد ولی تگ <b> به‌صورت رشته چاپ شد.

dangerouslySetInnerHTML
بعضی مواقع نیاز است یک کلمه از یک رشته متن را تفییر دهیم برای مثال آن را bold کنیم یا اینکه رنگ یا فونت آن را تغییر دهیم.در اینجور مواقع تکه تکه کردن متن و استایل دهی به تک تک آن‌ها باعث می‌شود کدهای بیشتری بنویسیم و کد تمیزی نداشته باشیم.یکی راه حل برای این موضوع استفاده از ویژگی dangerouslySetInnerHTML است.
هنگامی که از dangerouslySetInnerHTML استفاده می‌شود، React از مقایسه با virtual DOM صرف نظر می‌کند.همانطور که از نامش پیداست استفاده از آن می‌تواند خطرناک باشد زیرا کد ما به‌راحتی در برابر حملات XSS قرار میگیرد:

خروجی کد بالا در مرورگر
خروجی کد بالا در مرورگر


در کد بالا سعی کردیم کلمات "نام کاربری" و "گذرواژه" را با استفاده از تگ <b> به شکل bold چاپ کنیم.برای تگ <b> یک رویداد نوشتیم که وقتی نشانگر ماوس روی کلمات bold شده قرار گرفت یک alert را نمایش دهد.حالا ما یک آسیب پذیری XSS در سایت خود داریم که مهاجم با استفاده از آن می‌تواند کد جاوااسکریپتی خود را اجرا کند.

نحوه پیشگیری
اگر مجبور به استفاده از dangerouslySetInnerHTML در کدهای خود هستید بهتر است از یک کتابخانه sanitizer خوب استفاده شود که تا حدی اطمینان حاصل می‌کند کد تمیز است و اسکریپت‌های غیرمنتظره را هنگام رندر در React node اجرا نمی‌کند.تعدادی کتابخانه‌ی sanitizer وجود دارد اما قبل از انتخاب یکی از آن‌ها مزایا و معایب آن‌ها را درنظر بگیرید.از نوشتن روش‌های sanitization خودتان خودداری کنید.

createRef
از createRef برای دسترسی به یک کامپوننت یا عنصر DOM و ذخیره کردن آن در یک متغیر استفاده می‌شود.مثلا برای مدیریت focus یا انتخاب یک متن و تغییر آن.


خروجی کد بالا قبل از ۲ ثانیه
خروجی کد بالا قبل از ۲ ثانیه
خروجی کد بالا پس از ۲ ثانیه و تغییر متن با استفاده از innerHTML
خروجی کد بالا پس از ۲ ثانیه و تغییر متن با استفاده از innerHTML


همانطور که در کد بالا مشاهده میکنید بعد از اینکه DOM کامپوننت بارگیری می‌شود(mount می‌شود) پس از ۲ ثانیه با استفاده از innerHTML به راحتی می‌شود متن عنصر div را تغییر داد.یک attacker می‌تواند بدون درنظر گرفتن عنصر div اسکریپت مخرب خود را در داخل useEffect تزریق کند و خرابی‌هایی را به‌بار آورد.

نحوه پیشگیری
سعی کنید DOM را مستقیما تغییر ندهید.اگر احتیاج به تغییر محتوا بدون رندر اضافی دارید بهتر است از innerText به‌ جای innerHTML استفاده شود.همیشه سعی کنید داده‌ها را از طریق JSX ارائه دهید زیرا React تا حد خوبی مسائل امنیتی را مدیریت می‌کند.