امنیت
گزارش آسیبپذیریها
وقتی یک آسیبپذیری گزارش میشود، بلافاصله به بالاترین نگرانی ما تبدیل میشود، یک مشارکتکننده تماموقت همهچیز را رها میکند تا روی آن کار کند. برای گزارش یک آسیبپذیری، لطفا آن را به ایمیل security@vuejs.org بفرستید.
در حالی که کشف آسیبپذیریهای جدید به ندرت اتفاق میافتد، ما همچنین توصیه میکنیم همیشه از آخرین نسخههای Vue و کتابخانههای رسمی همراه آن استفاده کنید تا اطمینان حاصل کنید برنامه شما تا حد امکان امن باقی میماند.
قانون شماره 1: هرگز از تمپلیتهای غیرقابل اطمینان استفاده نکنید
مهمترین قانون امنیتی هنگام استفاده از Vue هرگز محتوای غیرقابل اطمینان را درون تمپلیتِ کامپوننت خود استفاده نکنید. انجام این کار معادل اجازه دادن به اجرای JavaScript دلخواه در برنامه شما است - و بدتر از آن، اگر کد سمت سرور رندر شود میتواند منجر به مشکل در سرورها شود. یک نمونه از چنین استفادهای:
js
Vue.createApp({
template: `<div>` + userProvidedString + `</div>` // هرگز این کار را نکنید
}).mount('#app')
تمپلیتهای Vue به JavaScript کامپایل میشوند، عبارات داخل تمپلیتها بخشی از فرایند رندرینگ هستند و اجرا خواهند شد. اگرچه عبارات در یک محیط رندرینگ مخصوص در برابر وجود کد مخرب تست میشوند ولی به دلیل پیچیدگی بالقوه محیطهای اجرا، غیرعملی است که یک فریمورک مانند Vue بدون ایجاد هزینههای غیرواقعگرایانه عملکردی شما را کاملاً در برابر احتمال اجرای کد مخرب حفاظت کند. سادهترین راه برای اجتناب کامل از این دسته از مشکلات، اطمینان حاصل کردن از اینکه محتوای تمپلیتهای Vue شما همیشه قابل اعتماد و کاملاً تحت کنترل شماست.
Vue چه کاری برای محافظت از شما انجام میدهد
HTML content
چه با استفاده از تمپلیت یا توابع رندر، محتوا به صورت خودکار کد میشود. این بدان معناست که در این تمپلیت:
template
<h1>{{ userProvidedString }}</h1>
اگر userProvidedString
حاوی کد مخرب زیر باشد:
js
'<script>alert("hi")</script>'
آنگاه به HTML زیر کد خواهد شد:
template
<script>alert("hi")</script>
و بدین ترتیب از تزریق اسکریپت جلوگیری میکند. این کدنگاری با استفاده از APIهای بومی مرورگر، مانند textContent
انجام میشود، بنابراین تنها زمانی میتواند آسیبپذیری وجود داشته باشد که خود مرورگر آسیبپذیر باشد.
Attribute bindings
به همین ترتیب، attribute binding های پویا نیز به طور خودکار کد میشوند. این بدان معناست که در این قالب:
template
<h1 :title="userProvidedString">
hello
</h1>
اگر userProvidedString
حاوی کد مخرب زیر باشد:
js
'" onclick="alert(\'hi\')'
آنگاه به HTML زیر کد خواهد شد:
template
" onclick="alert('hi')
و بدین ترتیب از بسته شدن ویژگی title
برای تزریق HTML جدید، دلخواه جلوگیری میکند. این کدنگاری با استفاده از APIهای بومی مرورگر، مانند setAttribute
انجام میشود، بنابراین تنها زمانی میتواند آسیبپذیری وجود داشته باشد که خود مرورگر آسیبپذیر باشد.
خطرات بالقوه
در هر برنامه وبی، اجازه اجرای محتوای برسی نشده ارائه شده توسط کاربر به عنوان HTML، CSS یا JavaScript بالقوه خطرناک است، بنابراین باید تا جای ممکن از آن اجتناب شود. زمانهایی وجود دارد که برخی خطرات ممکن است قابل قبول باشند.
برای مثال، سرویسهایی مانند CodePen و JSFiddle اجازه میدهند محتوای ارائه شده توسط کاربر اجرا شود، اما در یک قسمتی است که مورد انتظار است و تا حدی در iframe ها محصور شده است. در مواردی که یک ویژگی مهم ذاتاً نیاز به حدی از آسیبپذیری دارد، به عهده تیم شماست که اهمیت ویژگی را در برابر بدترین سناریوهای امکانپذیر با آسیبپذیری بسنجید.
تزریق HTML
همانطور که قبلاً یاد گرفتید، Vue به طور خودکار محتوای HTML را کد میکند و از تزریق تصادفی HTML قابل اجرا به برنامه شما جلوگیری میکند. با این حال، در مواردی که میدانید HTML امن است، میتوانید به طور صریح محتوای HTML را رندر کنید:
با استفاده از یک تمپلیت:
template<div v-html="userProvidedHtml"></div>
با استفاده از تابع رندر:
jsh('div', { innerHTML: this.userProvidedHtml })
با استفاده از تابع رندر با JSX:
jsx<div innerHTML={this.userProvidedHtml}></div>
هشدار
محتوای HTML ارائه شده توسط کاربر هرگز نمیتواند 100٪ امن در نظر گرفته شود مگر اینکه در یک iframe محصور شده یا در بخشی از برنامه باشد که تنها کاربری که آن HTML را نوشته است میتواند به آن دسترسی داشته باشد. علاوه بر این، اجازه دادن به کاربران برای نوشتن تمپلیتهای Vue خودشان نیز خطرات مشابهی دارد.
تزریق URL
در یک URL مانند این:
template
<a :href="userProvidedUrl">
click me
</a>
اگر URL برسی نشده باشد تا از اجرای JavaScript با استفاده از javascript:
جلوگیری شود، ممکن است مشکل امنیتی وجود داشته باشد. کتابخانههایی مانند sanitize-url برای کمک به این کار وجود دارند، اما توجه داشته باشید: اگر برسی URL را در frontend انجام میدهید، از قبل مشکل امنیتی دارید. URLهای ارائه شده توسط کاربر باید همیشه توسط بکاند شما قبل از ذخیره در پایگاه داده برسی شوند. سپس مشکل برای هر کلاینتی که به API شما متصل میشود از جمله برنامههای موبایل بومی اجتناب میشود. همچنین توجه داشته باشید که حتی با URLهای برسی شده، Vue نمیتواند به شما تضمین دهد که آنها به مقاصد امن منجر میشوند.
تزریق استایل
با توجه به این مثال:
template
<a
:href="sanitizedUrl"
:style="userProvidedStyles"
>
click me
</a>
فرض کنید که sanitizedUrl
برسی شده است، بنابراین قطعاً یک URL واقعی است و JavaScript نیست. با userProvidedStyles
، کاربران مخرب هنوز میتوانند CSS ارائه کنند تا "click jack" کنند، مثلاً لینک را به یک باکس شفاف روی دکمه "ورود" استایل کنند. سپس اگر https://user-controlled-website.com/
طوری ساخته شده باشد که شبیه به صفحه ورود برنامه شما باشد، آنها ممکن است اطلاعات ورود واقعی یک کاربر را ضبط کرده باشند. (مترجم: دکمه رو لینک بده به صفحه فیشینگ بعد با تغییر css ظاهر اونو مخفی کنه)
شاید بتوانید تصور کنید اجازه دادن به محتوای ارائه شده توسط کاربر برای یک عنصر <style>
چه آسیبپذیری بزرگتری را میتواند ایجاد کند، به آن کاربر کنترل کامل برای استایل دادن کل صفحه را میدهد. به همین دلیل است که Vue از رندر کردن تگهای style داخل قالبها مانند این جلوگیری میکند:
template
<style>{{ userProvidedStyles }}</style>
برای محافظت کامل کاربرانتان از click jack، توصیه میکنیم فقط اجازه کنترل کامل بر CSS را در یک iframe محصورشده دهید. به عنوان جایگزین، هنگام ارائه کنترل استایل توسط کاربر از طریق یک پیوند ، توصیه میکنیم از object syntax آن استفاده کنید و فقط اجازه دهید کاربران مقادیری را برای ویژگیهای خاصی که امن است کنترل کنند، مانند این ارائه دهند:
template
<a
:href="sanitizedUrl"
:style="{
color: userProvidedColor,
background: userProvidedBackground
}"
>
click me
</a>
تزریق JavaScript
ما به شدت از رندر کردن عنصر <script>
با Vue منع میکنیم، زیرا تمپلیتها و توابع رندرینگ هرگز نباید عوارض جانبی داشته باشند. با این حال، این تنها راه برای شامل کردن رشتههایی که در زمان اجرا به عنوان JavaScript ارزیابی میشوند، نیست.
هر عنصر HTML ویژگیهایی با مقادیری دارد که رشتههای JavaScript را میپذیرند، مانند onclick
، onfocus
و onmouseenter
. متصل کردن JavaScript ارائه شده توسط کاربر به هر یک از این ویژگیهای رویداد خطر امنیتی بالقوهای است، بنابراین باید از آن اجتناب کرد.
هشدار
مگر اینکه در یک iframe محصور شده یا در بخشی از برنامه باشد که فقط کاربری که آن JavaScript را نوشته میتواند به آن دسترسی داشته باشد، JavaScript ارائه شده توسط کاربر هرگز نمیتواند 100٪ امن در نظر گرفته شود.
گاهی اوقات گزارشهای آسیبپذیری دریافت میکنیم مبنی بر اینکه چگونه میتوان XSS (تزریق کد) را در تمپلیتهای Vue انجام داد. به طور کلی، ما چنین مواردی را آسیبپذیریهای واقعی در نظر نمیگیریم زیرا راه عملی برای محافظت از توسعهدهندگان در برابر دو سناریویی که اجازه XSS میدهند، وجود ندارد:
توسعهدهنده صراحتاً از Vue میخواهد محتوای برسی نشده ارائه شده توسط کاربر، را به عنوان تمپلیتهای Vue رندر کند. این ذاتاً ناامن است و راهی برای Vue برای دانستن منشأ وجود ندارد.
توسعهدهنده Vue را روی یک صفحه کامل HTML متصل میکند که تصادفاً حاوی محتوای رندر شده سمت سرور و ارائه شده توسط کاربر است. این اساساً همان مشکل #1 است، اما گاهی اوقات توسعهدهندگان ممکن است بدون آگاهی انجام دهند. این میتواند منجر به آسیبپذیریهای احتمالی شود که در آن مهاجم HTML ارائه میکند که به عنوان HTML ساده امن است اما به عنوان یک تمپلیت Vue ناامن است. بهترین شیوه این است که هرگز Vue را بر روی نودهایی که ممکن است حاوی محتوای رندر شده سمت سرور و ارائه شده توسط کاربر باشند، متصل نکنید.
Best Practices
قانون کلی این است که اگر اجازه دهید محتوای برسی نشده، ارائه شده توسط کاربر به عنوان HTML، JavaScript یا حتی CSS اجرا شود، ممکن است خود را در معرض حملات قرار دهید. این نصیحت حتی اگر از Vue، یک فریمورک دیگر یا حتی هیچ فریمورکی استفاده نکنید، درست است.
علاوه بر توصیههای ارائه شده برای خطرات بالقوه، توصیه میکنیم با این منابع آشنا شوید:
سپس آنچه را یاد گرفتهاید برای بررسی کد منبع وابستگیهایتان (source code of your dependencies) نیز به کار ببرید تا الگوهای بالقوه خطرناک را پیدا کنید، اگر هر کدام از آنها شامل کامپوننتهای شخص ثالث یا به نحو دیگری بر آنچه در DOM رندر میشود تأثیر میگذارند.
هماهنگی با بکاند
آسیبپذیریهای امنیتی HTTP مانند جعل درخواست متقاطع سایت (CSRF/XSRF) و شمول اسکریپت متقاطع سایت (XSSI) عمدتاً در بکاند رفع میشوند، بنابراین نگرانی Vue نیستند. با این حال، هماهنگی با تیم بکاند برای یادگیری بهترین شیوه برای تعامل با API آنها، مثلاً با ارسال توکنهای CSRF با ارسال فرم، هنوز هم ایده خوبی است.
Server-Side Rendering (SSR)
هنگام استفاده از SSR، برخی نگرانیهای امنیتی اضافی وجود دارد، بنابراین مطمئن شوید که بهترین روش های توضیح داده شده در مستندات SSR ما را دنبال میکنید تا از آسیبپذیریها اجتناب کنید.