decodex | آموزش برنامه نویسی و طراحی سایت
decodex | چطور از حملات XSS در Vue جلوگیری کنیم؟

چطور از حملات XSS در Vue جلوگیری کنیم؟

حملات XSS از اون دسته باگ هایی هستن که وقتی رخ میدن، مستقیم قلب کاربر و اعتبار محصول رو نشونه میگیرن. خبر خوب اینه که Vue به‌صورت پیش‌فرض خیلی جاها مراقب ماست و داده‌ها رو امن رندر میکنه، ولی کافیه یه جا اشتباه از v-html استفاده کنیم یا یه لینک ناامن بسازیم تا درب نفوذ باز بشه. تو این مقاله قدم به قدم میریم سراغ راهکارهای عملی و تست شده برای جلوگیری از XSS تو Vue.

xss در vue | decodex.ir

۱) XSS دقیقاً چیه و Vue خودش چی کار می‌کنه؟

  • Reflected XSS: ورودی خطرناک از طریق URL یا فرم برمیگرده و همون لحظه اجرا میشه.
  • Stored XSS: داده آلوده در دیتابیس ذخیره میشه و هر بار به کاربرها نمایش داده میشه.
  • DOM-based XSS: وقتی کد فرانت‌اند، خودش بدون رفت و برگشت به سرور، داده خطرناک رو وارد DOM می‌کنه.

Vue پیش‌فرض چه حفاظتی داره؟

در Vue، داده‌هایی که با {{ }} (mustache) یا v-text رندر میشن، به‌صورت خودکار escape میشن و کدهای HTML/JS به عنوان متن ساده نمایش داده میشن. مشکل وقتی شروع می‌شه که:
• از v-html استفاده کنید (مستقیم HTML رو تزریق می‌کنه).
• مقداردهی به ویژگی‌هایی مثل src یا href رو بدون چک کردن انجام بدین.

<!-- امن: Vue محتوای user.name رو escape می‌کنه -->
<p>سلام، {{ user.name }}</p>

<!-- ناامن: اگر comment شامل اسکریپت باشه اجرا می‌شه -->
<div v-html="comment"></div>

۲) نقاط خطر در پروژه‌های Vue

v-html و محتواهای کاربر

  • هر محتوایی که از کاربر میاد (کامنت، بیو، توضیحات) اگر با v-html تزریق بشه، خیلی خطرناکه.
  • فیلترهای قدیمی Vue حذف شدن؛ به جاش باید قبل از رندر، محتوا رو «Sanitize» کنید.

پیوندها، منابع و پروتکل‌ها

  • :href و :src رو بی‌حساب‌وکتاب از دیتای کاربر نسازید. پروتکل‌های مشکوک مثل javascript: می‌تونن اجرا بشن.
  • برای لینک‌های target="_blank" حتماً rel="noopener noreferrer" بگذارید.

قالب‌های داینامیک و کتابخانه‌های ثالث

  • از رندر کردن قالب‌های دلخواه کاربر (Template از سرور یا تنظیمات) اجتناب کنید.
  • کامپوننت‌های شخص ثالث رو قبل از استفاده بررسی کنید: از v-html استفاده می‌کنن؟ تنظیمات امن دارن؟
جلوگیری از حملات xss در vue

۳) راهکارهای عملی سمت کلاینت در Vue

الف) استفاده امن از v-html با DOMPurify

اگر مجبوری HTML رندر کنی، قبلش اینجوری پاکسازی کن:

// نصب: npm i dompurify
import { computed } from 'vue'
import DOMPurify from 'dompurify'

export default {
  props: { rawHtml: { type: String, default: '' } },
  setup(props) {
    const safeHtml = computed(() => DOMPurify.sanitize(props.rawHtml, {
      USE_PROFILES: { html: true }
    }))
    return { safeHtml }
  }
}
<!-- حالا امن‌تر -->
<div v-html="safeHtml"></div>
  • برای محتوای پیچیده تر، لیست سفید tag & property بسازید؛ هرچیزی خارج از لیست شما داخله html اومده ممنوعه و باید حذف بشه.
  • DOMPurify را در SSR هم تنظیم کنید.

ب) ایمن‌سازی URL ها و منابع

قبل از بایند کردن href و src پروتکل رو چک کنید:

function safeUrl (url) {
  try {
    const u = new URL(url, window.location.origin)
    const allowed = ['http:', 'https:', 'mailto:', 'tel:']
    return allowed.includes(u.protocol) ? u.href : '#'
  } catch (e) {
    return '#'
  }
}
<a :href="safeUrl(profile.link)" target="_blank" rel="noopener noreferrer">وب‌سایت</a>
<img :src="safeUrl(avatarUrl)" alt="">
  • برای ناوبری داخلی از <router-link> استفاده کنید تا ورودی های غیر منتظره کمتر اثر بذارن.

ج) قوانین Linting و جلوگیری از خطاهای ناخواسته

با ESLint، استفاده از v-html و الگوهای خطرناک رو محدود کنید:

// .eslintrc.js
module.exports = {
  extends: ['plugin:vue/vue3-recommended'],
  rules: {
    'vue/no-v-html': 'error'
  }
}
  • برای تیم های بزرگ، این قانون ها واقعاً جلوی خطای انسانی رو میگیرن.

د) تست خودکار برای اطمینان از Sanitization

نمونه تست واحد با Vitest/Jest:

it('sanitizes unsafe html', () => {
  const raw = '<img src=x onerror=alert(1)>'
  const safe = DOMPurify.sanitize(raw)
  expect(safe).not.toContain('onerror')
})
  • علاوه بر Unit Test، از ابزارهایی مثل npm audit یا خدماتی مثل Snyk برای پایش وابستگی‌ها استفاده کنید.

۴) لایه‌های دفاعی سمت سرور و تنظیمات امنیتی

الف) سرخط‌های امنیتی (CSP)؛ دفاع دوم شما

با محتاط بودن در فرانت اند همه چیز حل نمیشه. CSP (content security policy) کمک میکنه حتی اگر اسکریپتی درز کرد، اجرا نشه.

Content-Security-Policy: default-src 'self'; 
  script-src 'self' 'nonce-xyz'; 
  style-src 'self' 'unsafe-inline'; 
  img-src 'self' data: https:; 
  object-src 'none'; base-uri 'self'; frame-ancestors 'none';

اگر Node/Express دارید، با Helmet ساده ترش کنید:

// npm i helmet
import helmet from 'helmet'
app.use(helmet())
app.use(helmet.contentSecurityPolicy({
  useDefaults: true,
  directives: {
    'script-src': ["'self'", "'nonce-xyz'"]
  }
}))

ب) Sanitization سمت سرور

  • قبل از ذخیره سازی، ورودی ها رو پاکسازی کنید (به‌خصوص اگر قراره در قالب HTML نمایش داده شن).
  • به لیست سفید tags & properties اکتفا کنید؛ Blacklist اغلب قابل دور زدن میشه.

ج) مراقبت در SSR/Nuxt

  • در SSR، خروجی سرور وارد DOM اولیه میشه؛ هر v-html آلوده میتونه زودتر از کلاینت اجرا بشه.
  • همون سیاست‌های Sanitization را در سرور هم اعمال کنید و از CSP استفاده کنید.

د) جمع‌بندی نکات کلیدی در یک نگاه

مسئلهریسکراهکارابزار/قابلیت
استفاده از v-htmlتزریق اسکریپتSanitize یا پرهیزDOMPurify, vue/no-v-html
لینک/منبع داینامیکjavascript: و اجرابررسی پروتکلsafeUrl, allowlist
باز کردن تب جدیددسترسی Tabnabbingrel ایمنrel="noopener noreferrer"
کتابخانه ثالثرفتار ناامنبازبینی/تنظیماتمستندات، تست
SSR/سروراجرای زودهنگامCSP و SanitizationHelmet، هدرها

جمع‌بندی

Vue بخش بزرگی از مسیر امن سازی رو برامون هموار کرده، اما کلید کار، پرهیز از v-html بدون پاکسازی، کنترل دقیق لینک‌ها و منابع، و فعال‌سازی دفاع‌های لایه به‌ لایه مثل CSP و تست‌های خودکاره. اگر همین امروز چند قانون lint، یه تابع safeUrl و DOMPurify رو به پروژه اضافه کنید، سطح ریسک تون به شکل محسوسی پایین میاد.

تجربه‌ای از مقابله با XSS در Vue داشتید؟ ابزار یا الگوی خاصی به‌درد بخور پیدا کردید؟ توی کامنت‌ها بگید تا بقیه هم استفاده کنن.

دیدگاه شما

ثبت دیدگاه

اگه در مورد این مطلب نظری داری یا در همین موضوع سوالی داری، همینجا مطرح کن تا از دیدگاه ارزشمندت استفاده کنیم و انرژی بگیریم، یا سوالت رو جواب بدیم

در ضمن، شماره موبایلت تو سایت نمایش داده نمیشه و پیش ما به صورت محرمانه میمونه

کد تایید پیامک شده به شماره را وارد نمایید