Mundarija (40)
- Bu darsda
- 1. Nega bu kerak?
- 2. textContent — matnni o'qish va yozish
- 2.1 O'qish
- 2.2 Yozish
- 2.3 Son, bo'sh satr va null
- 2.4 Nega textContent xavfsiz?
- 2.5 Jonli hududga xabar yozish
- 3. innerText — ko'zga ko'rinadigan matn
- 4. innerHTML — HTML sifatida o'qish va yozish
- 4.1 O'qish: element ichidagi HTML
- 4.2 Yozish: satrdan elementlar
- 4.3 Brauzer satrni "tuzatadi"
- 4.4 <script> ishlamaydi — lekin bu himoya emas
- 4.5 innerHTML += tuzog'i
- 5. outerHTML — element o'zi bilan birga
- 6. Hujumchi nigohi: XSS innerHTML orqali
- 6.1 Hujumni jonli ko'ramiz
- 6.2 Xuddi shu ma'lumot — textContent bilan
- 6.3 Ikkalasini bosib solishtiring
- 6.4 Hujumchi yana qayerdan kiradi
- 7. HTML kerak bo'lsa nima qilish kerak?
- 7.1 Tuzilmani o'zingiz yasang, ma'lumotni textContent bilan qo'ying
- 7.2 Ekranlash funksiyasi
- 7.3 setHTML — brauzerning o'z tozalovchisi
- 8. Qaysi birini tanlash kerak?
- 9. Ko'p uchraydigan xatolar
- 9.1 input ga textContent yozish
- 9.2 Narxni almashtirib, qalinlikni yo'qotish
- 9.3 "O'zimizniki" deb begona ma'lumotni innerHTML ga berish
- 9.4 innerHTML += sikl ichida
- 9.5 Ekranlashda & ni oxirida almashtirish
- 10. Mashqlar
- 1-mashq (oson): Narxni yangilang
- 2-mashq (o'rta): Xavfsiz ro'yxat
- 3-mashq (qiyin): Ekranlash va qolip
- 4-mashq: Portfolio qadami — footer'dagi yil
- 11. Real ishda
- Xulosa
- Manbalar
JavaScript'da matnni o'zgartirish: textContent, innerHTML va XSS xavfi
Qisqacha: Elementdagi matnni almashtirish uchun
element.textContent = "yangi matn"yozing — u matnni har doim oddiy matn sifatida qo'yadi. Uning qo'shnisiinnerHTMLesa berilgan satrni HTML deb o'qiydi: foydalanuvchi yozgan matnni unga bersangiz, ichidagi<img onerror="...">kabi kod ishga tushadi — bu XSS hujumi. Qoida: ma'lumot —textContentbilan, HTML — faqat o'zingiz yozgan satrdan.
Bu darsda
textContentbilan elementdagi matnni o'qiy va almashtira olasiz.textContent,innerTextvainnerHTMLfarqini va qaysi biri qachon kerakligini bilasiz.innerHTMLvaouterHTMLbilan HTML qo'yishni va ularning tuzoqlarini tushunasiz.- XSS hujumi
innerHTMLorqali qanday ishlashini jonli ko'rib, undan himoyalana olasiz. - Yangi
setHTMLmetodi nima va nega uni hali har joyda ishlatib bo'lmasligini bilasiz.
Oldin bilishingiz kerak: Elementlarni tanlash, Template literals, HTML darajasidagi xavfsizlik, Jonli hududlar va dinamik kontent.
1. Nega bu kerak?
O'tgan darsda elementni topishni o'rgandik. Topgandan keyingi eng ko'p qilinadigan ish — uning ichidagi narsani almashtirish. Narx o'zgardi — yangi narxni yozish. Savatga taom qo'shildi — "Savatda 3 ta taom" deb yozish. Serverdan mehmonlarning izohlari keldi — ularni ro'yxatga chiqarish.
Bu ishlarning hammasi uchun brauzer uchta asosiy xususiyat beradi: textContent, innerText va innerHTML. Ular bir-biriga juda o'xshaydi. Ko'p boshlovchi farqini bilmay, qo'liga birinchi kelganini ishlatadi. Ko'pincha bu innerHTML bo'ladi — u qulayroq ko'rinadi.
HTML darajasidagi xavfsizlik darsidagi voqeani eslang. «Bahor» saytida "Mehmonlar fikri" bo'limi bor edi. Hujumchi izohga oddiy matn o'rniga HTML yozdi, sayt uni "boricha" chiqardi — va kod Jasur akaning brauzerida ishladi. Bu hujumning nomi — XSS (Cross-Site Scripting, saytlararo skript): begona odamning JavaScript kodi sizning saytingizda, mehmonning brauzerida ishlab ketishi. O'sha darsda "matnni sahifaga qo'yadigan dastur — server yoki JavaScript" degan edik. Bugun o'sha dasturni o'zimiz yozamiz. Va aynan qaysi bitta so'z — textContent yoki innerHTML — saytni himoya qilishini yoki hujumchiga ochib berishini ko'ramiz.
Hayotdan o'xshatish: choyxonadagi menyu doskasi. Otabek doskaga mehmonning izohini bo'r bilan, harfma-harf ko'chiradi — bu textContent. Izohda "osh tekin!" deb yozilgan bo'lsa ham, bu shunchaki yozuv: kassa osh uchun pul olishda davom etadi. Uning teskarisi — innerHTML. U izohni buyruq deb bajaradigan ofitsiantga o'xshaydi: "osh tekin!" o'qidi — darhol tekin osh tarqata boshladi.
2. textContent — matnni o'qish va yozish
2.1 O'qish
textContent — elementning ichidagi barcha matn, teglarsiz. Ichma-ich elementlarning matni ham qo'shiladi:
<p id="taom">Osh — <b>35 000</b> so'm</p>
<script>
const taom = document.querySelector("#taom");
console.log(taom.textContent);
console.log(taom.textContent.length);
</script>Konsolda:
Osh — 35 000 so'm
17<b> tegi yo'qoldi, lekin uning ichidagi "35 000" qoldi. DOM daraxti darsidagi tilda aytsak: textContent elementning ichidagi hamma matn tugunlarini tartib bilan yig'ib, bitta satrga ulaydi.
2.2 Yozish
textContent ga yangi qiymat berilsa, element ichidagi hamma narsa o'chadi va o'rniga bitta matn tuguni qo'yiladi:
<p id="taom">Osh — <b>35 000</b> so'm</p>
<script>
const taom = document.querySelector("#taom");
taom.textContent = "Osh — 38 000 so'm";
console.log(taom);
console.log(taom.children.length);
</script>Konsolda:
<p id="taom">Osh — 38 000 so'm</p>
0Natijaga qarang: narx endi qalin emas. <b> elementi ham, uning qalinligi ham ketdi — children.length endi 0. Shuning uchun textContent ni faqat kerakli eng kichik elementga yozing. Narxni almashtirmoqchi bo'lsangiz, butun p ni emas, faqat b ni toping (Elementlarni tanlash):
<p id="taom">Osh — <b class="narx">35 000</b> so'm</p>
<script>
const narx = document.querySelector("#taom .narx");
narx.textContent = "38 000";
console.log(document.querySelector("#taom"));
</script>Konsolda:
<p id="taom">…</p>Endi narx yangilandi va qalinligicha qoldi. Konsolda … chiqdi, chunki p ichida endi bola element bor — jonli oyna konsoli uni qisqartiradi. Kod b ga tegdi, p ning qolgan qismiga emas. 38 000 — shu misol uchun o'ylab topilgan narx, «Bahor» menyusi o'zgarmaydi.
2.3 Son, bo'sh satr va null
textContent ga son bersangiz, u satrga aylanadi. Bo'sh satr yoki null bersangiz — element bo'shaydi:
<p id="savat">Savat bo'sh emas</p>
<script>
const savat = document.querySelector("#savat");
savat.textContent = 3;
console.log(typeof savat.textContent, savat.textContent);
savat.textContent = "";
console.log(savat.childNodes.length);
</script>Konsolda:
string 3
0textContent = "" — elementni tozalashning eng qisqa yo'li. Undan keyin childNodes da birorta ham tugun qolmaydi.
2.4 Nega textContent xavfsiz?
Eng muhim xususiyati: textContent ga nima bersangiz ham, u har doim matn bo'lib qoladi. Hatto HTML teglari bo'lsa ham:
<p id="izoh"></p>
<script>
const izoh = document.querySelector("#izoh");
izoh.textContent = "<b>Osh zo'r!</b>";
console.log(izoh.textContent);
console.log(izoh.innerHTML);
</script>Konsolda:
<b>Osh zo'r!</b>
<b>Osh zo'r!</b>Natija oynasida qalin matn yo'q — <b> belgilari ekranda harf sifatida ko'rinadi. Ikkinchi qatorga qarang: brauzer < ni o'zi < ga aylantirib qo'ydi. Bu — HTML xavfsizligi darsidagi ekranlash (escaping). textContent uni siz uchun avtomatik qiladi.
Tekshirib ko'ring:
<p>Narx: <span>5 000</span></p>dagipgap.textContent = "Narx: 6 000"yozildi. Endip.querySelector("span")nima qaytaradi?
Javob
null. textContent ga yozish p ning ichidagi hamma narsani, jumladan span ni ham o'chiradi va o'rniga bitta matn tugunini qo'yadi. Faqat narxni o'zgartirish kerak bo'lsa, span ning o'zining textContent iga yozish kerak edi.
2.5 Jonli hududga xabar yozish
Jonli hududlar darsida va'da qilgan edik: aria-live hudud sahifada oldindan turadi, JavaScript esa faqat uning matnini almashtiradi. Mana, o'sha almashtirishning o'zi:
<button type="button">Savatga</button>
<p id="savat-xabar" aria-live="polite"></p>
<script>
const xabar = document.querySelector("#savat-xabar");
xabar.textContent = "Osh savatga qo'shildi. Savatda 3 ta taom.";
console.log(xabar.textContent);
</script>Konsolda:
Osh savatga qo'shildi. Savatda 3 ta taom.Hozircha xabar sahifa ochilishi bilan yoziladi. Uni tugma bosilganda yozishni addEventListener darsida qilamiz. Malika NVDA bilan saytda bo'lsa, matn o'zgarishi bilan ekran o'quvchi uni ovoz chiqarib o'qiydi. Element o'zgarmadi, faqat matn — aynan shu "e'lon qil" degan signal.
3. innerText — ko'zga ko'rinadigan matn
innerText ham matn qaytaradi, lekin boshqacha: u sahifada ko'zga qanday ko'rinsa, shunday beradi. Buning uchun brauzer CSS'ni hisobga oladi:
<style>
.katta { text-transform: uppercase; }
</style>
<p id="taom">Osh <span hidden>(sir: ziravor)</span>
tayyor</p>
<p id="sarlavha" class="katta">bugungi menyu</p>
<script>
const taom = document.querySelector("#taom");
console.log(JSON.stringify(taom.textContent));
console.log(JSON.stringify(taom.innerText));
const sarlavha = document.querySelector("#sarlavha");
console.log(sarlavha.textContent, "|", sarlavha.innerText);
</script>Konsolda:
"Osh (sir: ziravor)\n tayyor"
"Osh tayyor"
bugungi menyu | BUGUNGI MENYUMatnni JSON.stringify bilan chiqardik — DOM daraxti darsidagi usul: Enter \n bo'lib ko'rinadi. Uch farqni ko'ring:
hiddenspan'ning matnitextContentda bor,innerTextda yo'q: u ekranda ko'rinmaydi.- HTML'dagi Enter va bo'sh joylar
textContentda saqlangan,innerTextda esa ekrandagidek bitta probelga qisqargan. text-transform: uppercaseham hisobga olindi:innerTextekrandagi katta harflarni berdi.
Ko'rinadigan matnni hisoblash uchun brauzer sahifaning joylashuvini (layout) o'lchaydi. Shuning uchun innerText textContent dan sekinroq. Ko'p elementda, sikl ichida bu sezilishi mumkin — sababini Rendering pipeline darsida ko'ramiz.
innerText ga yozish ham textContent ga o'xshaydi — xavfsiz, matn sifatida. Bitta farq: matndagi \n belgilari <br> ga aylanadi.
textContent |
innerText |
|
|---|---|---|
| Nimani beradi | HTML'dagi hamma matn | Ekranda ko'rinadigan matn |
| CSS'ni hisobga oladimi | Yo'q | Ha (hidden, display: none, text-transform) |
| Tezligi | Tez | Sekinroq (layout kerak) |
| Qayerda bor | Har qanday tugunda | Faqat HTML elementlarida |
Amaliy qoida: yozish uchun deyarli doim textContent. innerText — faqat "foydalanuvchi aynan nimani ko'ryapti?" degan savol kerak bo'lganda, masalan ko'rinadigan matnni nusxalashda.
Tekshirib ko'ring: Avtomatik test kartadagi taom nomini o'qib, "OSH" ga tenglashtirmoqchi. HTML'da "Osh" yozilgan, CSS esa uni
uppercasebilan chiqaradi. Test qaysi xususiyatni o'qisa,"OSH"ni oladi?
Javob
innerText — u CSS'ni hisobga oladi va ekrandagi katta harflarni beradi. textContent esa HTML'dagi "Osh" ni qaytaradi. Shuning uchun testlar ba'zan "foydalanuvchi ko'radigan matn" uchun innerText ga o'xshash usuldan foydalanadi.
4. innerHTML — HTML sifatida o'qish va yozish
4.1 O'qish: element ichidagi HTML
innerHTML element ichini HTML satri sifatida qaytaradi — teglari bilan:
<ul id="menyu"><li>Osh</li><li class="yangi">Manti</li></ul>
<script>
const menyu = document.querySelector("#menyu");
console.log(menyu.innerHTML);
console.log(menyu.textContent);
</script>Konsolda:
<li>Osh</li><li class="yangi">Manti</li>
OshMantiBu satr — fayldagi matn emas. Brauzer uni DOM'dan qaytadan yasaydi (DOM — manba kodi emas). Shuning uchun atributlar tartibi yoki qo'shtirnoqlar siz yozgandan biroz farq qilishi mumkin.
4.2 Yozish: satrdan elementlar
Endi teskarisi: innerHTML ga satr berilsa, brauzer uni HTML deb o'qiydi va elementlarga aylantiradi. Bir va'dani eslang: Template literals darsida backtick ichida yig'ilgan HTML "hozircha shunchaki satr", uni sahifaga qo'yishni keyin o'rganamiz. Mana o'sha joy:
<div id="karta"></div>
<script>
const nomi = "Manti";
const narx = 30000;
const html = `
<h3>${nomi}</h3>
<p class="narx">${narx} so'm</p>
`;
const karta = document.querySelector("#karta");
karta.innerHTML = html;
console.log(karta.children.length);
console.log(karta.querySelector(".narx"));
</script>Konsolda:
2
<p class="narx">30000 so'm</p>Satr endi haqiqiy h3 va p elementlariga aylandi: ularni querySelector bilan topsa bo'ladi, CSS ularni bezaydi. Bu juda qulay — shuning uchun innerHTML mashhur.
E'tibor bering: bu yerda nomi va narx ni biz o'zimiz yozdik. Ular kodning ichida, hech kim ularni o'zgartira olmaydi. Xavf ma'lumot tashqaridan kelganda boshlanadi — buni «Hujumchi nigohi» bo'limida ko'ramiz.
4.3 Brauzer satrni "tuzatadi"
Satrdagi HTML xato bo'lsa, brauzer DOM daraxti darsidagidek uni o'zi tuzatadi:
<div id="d"></div>
<script>
const d = document.querySelector("#d");
d.innerHTML = "<p>Osh <b>tayyor";
console.log(d.innerHTML);
</script>Konsolda:
<p>Osh <b>tayyor</b></p>Yopilmagan b va p ni brauzer o'zi yopdi. Xato chiqmaydi — bu yaxshi tomoni ham, yomon tomoni ham: noto'g'ri yozilgan HTML jimgina "boshqacha" bo'lib qoladi.
4.4 <script> ishlamaydi — lekin bu himoya emas
innerHTML orqali qo'yilgan <script> tegi bajarilmaydi. Standart shunday yozilgan:
<div id="d"></div>
<script>
const d = document.querySelector("#d");
d.innerHTML = "<script>console.log('ishladi')<\/script>";
console.log(d.children.length, d.firstElementChild.nodeName);
</script>Konsolda:
1 SCRIPTSkript DOM'ga qo'shildi, lekin "ishladi" yozuvi chiqmadi. <\/script> dagi teskari chiziq — kichik hiyla: bo'lmasa brauzer satr ichidagi </script> ni tashqi skriptning oxiri deb tushunardi.
Bu yerda xavfli xulosa chiqarish oson: "demak, innerHTML xavfsiz". Yo'q! HTML xavfsizligi darsidan eslang: hujumda <script> ning o'zi shart emas. Bu haqda pastda.
4.5 innerHTML += tuzog'i
Ro'yxat oxiriga bitta element qo'shish uchun ko'p boshlovchi shunday yozadi:
<ul id="menyu"><li>Osh</li></ul>
<script>
const menyu = document.querySelector("#menyu");
const osh = menyu.querySelector("li");
console.log(osh.isConnected);
menyu.innerHTML += "<li>Manti</li>";
console.log(osh.isConnected);
console.log(menyu.querySelector("li") === osh);
</script>Konsolda:
true
false
falseEkranda hammasi joyida: osh va manti. Lekin konsolga qarang. isConnected — "element hozir sahifadami?" degan savol. Oldin osh sahifada edi, endi — yo'q! Sahifadagi "Osh" — boshqa, yangi element.
Sababi: a += b aslida a = a + b. Brauzer avval butun ichki HTML'ni satrga aylantiradi, unga yangi qismni qo'shadi, keyin hamma narsani o'chirib, butun satrdan elementlarni qaytadan yasaydi. Natijada:
- oldin olingan o'zgaruvchilar (
osh) endi sahifada yo'q elementga qaraydi; - elementlarga keyin qo'shiladigan tinglovchilar (hodisalar) yo'qoladi;
- forma maydonlariga yozilgan matn o'chadi;
- ro'yxat uzun bo'lsa, har qo'shishda hammasi qayta quriladi — sekin.
Bitta element qo'shishning to'g'ri yo'llari — insertAdjacentHTML va append — Element yaratish, joylash va o'chirish darsida.
Tekshirib ko'ring: Nega
innerHTML +=dan keyinosh.textContent = "Palov"yozilsa, ekranda hech narsa o'zgarmaydi?
Javob
osh o'zgaruvchisi eski elementga qaraydi — u endi sahifada emas (isConnected — false). Unga yozilgan matn xotiradagi "uzilgan" elementda qoladi. Ekrandagi "Osh" esa innerHTML += yasagan yangi element. Uni qaytadan topish kerak: menyu.querySelector("li").
5. outerHTML — element o'zi bilan birga
innerHTML — elementning ichi. outerHTML — elementning o'zi va ichi:
<ul id="menyu"><li>Osh</li></ul>
<script>
const menyu = document.querySelector("#menyu");
console.log(menyu.innerHTML);
console.log(menyu.outerHTML);
</script>Konsolda:
<li>Osh</li>
<ul id="menyu"><li>Osh</li></ul>outerHTML ga yozish elementni butunlay almashtiradi. Va bu yerda yana bitta tuzoq bor:
<p id="aksiya">Bugun aksiya yo'q</p>
<script>
const aksiya = document.querySelector("#aksiya");
aksiya.outerHTML = "<h2 id='aksiya'>Ko'k choy bepul!</h2>";
console.log(aksiya, aksiya.isConnected);
console.log(document.querySelector("#aksiya"));
</script>Konsolda:
<p id="aksiya">Bugun aksiya yo'q</p> false
<h2 id="aksiya">Ko'k choy bepul!</h2>Ekranda — yangi h2. Lekin aksiya o'zgaruvchisi hamon eski p ga qaraydi: u sahifadan chiqarib tashlangan. Yangi elementni ishlatish uchun uni qaytadan topish kerak. outerHTML ni o'qish debug uchun qulay; yozish esa kamdan-kam kerak — elementni almashtirishning aniqroq yo'li replaceWith (Element yaratish va o'chirish).
6. Hujumchi nigohi: XSS innerHTML orqali
6.1 Hujumni jonli ko'ramiz
Endi eng muhim qism — XSS'ni o'z ko'zimiz bilan ko'ramiz. «Bahor» saytida "Mehmonlar fikri" bor. Izohlar serverdan keladi — ularni mehmonlar yozgan. Dasturchi ularni chiqarish uchun qulay yo'lni tanladi:
<h2>Mehmonlar fikri</h2>
<ul id="izohlar"></ul>
<script>
const izohlar = [
"Osh zo'r, xizmat a'lo!",
"Manti yaxshi " +
'<img src="x" onerror="console.log(\'XSS: kod ishladi\')">',
];
const royxat = document.querySelector("#izohlar");
for (const izoh of izohlar) {
royxat.innerHTML += `<li>${izoh}</li>`;
}
console.log("Izohlar chiqarildi");
</script>Konsolda:
Izohlar chiqarildi
XSS: kod ishladiIkkinchi qatorni hujumchi yozmadi — uni mehmonning brauzeri bajardi. Ikkinchi izohda img tegi bor. Brauzer x degan rasmni yuklay olmadi va onerror ichidagi kodni ishga tushirdi. Natijada ikkinchi izohda faqat "Manti yaxshi" va buzilgan rasm belgisi ko'rinadi — mehmon hech narsa sezmaydi.
Bizning misolda kod faqat konsolga yozdi. Haqiqiy hujumda console.log o'rnida boshqa kod turadi. U sahifani o'zgartiradi, mehmon nomidan so'rov yuboradi, u yozayotgan parolni o'qiydi. Origin qoidasi bu yerda yordam bermaydi: kod sizning saytingizda turibdi, brauzer uni "o'ziniki" deb biladi.
Diqqat: Bu jonli oyna — izolyatsiyalangan "qum qutisi" (sandbox). Hujum shu oynaning ichida qoladi, darsga yoki saytga zarar yetmaydi. Lekin xuddi shu kod oddiy sahifada ham aynan shunday ishlaydi.
Hujum qanday yo'l bosganini diagrammada ko'ring — yuqoridan pastga:
flowchart TD
H["Hujumchi izohi"] --> S["Server bazasi"]
S --> J["JavaScript sahifaga qo'yadi"]
J -->|innerHTML| P["Brauzer HTML deb o'qiydi"]
P --> I["img: rasm yo'q"]
I --> K["onerror: kod ishladi"]
J -.->|textContent| T["Ekranda oddiy matn"]
classDef xavf fill:#fdeee6,stroke:#b4461a
classDef xavfsiz fill:#e8f1ec,stroke:#1f6f4a
class P,I,K xavf
class T xavfsizHamma narsa bitta joyda hal bo'ladi: ma'lumot innerHTML ga tushdimi yoki textContent ga.
6.2 Xuddi shu ma'lumot — textContent bilan
Endi o'sha izohlarni xavfsiz yo'l bilan chiqaramiz. Har izoh uchun li kerak — uni document.createElement("li") yaratadi, append esa ro'yxat oxiriga qo'shadi. Ikkalasini Element yaratish darsida to'liq o'rganamiz, bugun faqat qolipni ko'ring:
<h2>Mehmonlar fikri</h2>
<ul id="izohlar"></ul>
<script>
const izohlar = [
"Osh zo'r, xizmat a'lo!",
"Manti yaxshi " +
'<img src="x" onerror="console.log(\'XSS: kod ishladi\')">',
];
const royxat = document.querySelector("#izohlar");
for (const izoh of izohlar) {
const li = document.createElement("li");
li.textContent = izoh;
royxat.append(li);
}
console.log("Izohlar chiqarildi");
</script>Konsolda:
Izohlar chiqarildi"XSS" qatori yo'q. Natijaga qarang: hujumchining <img ...> yozuvi ekranda harflar bo'lib turibdi. Mehmon uni o'qiydi va "kimdir g'alati narsa yozibdi" deb o'tib ketadi. Kod ishlamadi.
6.3 Ikkalasini bosib solishtiring
Quyidagi oynada ikki tugma bor. Ular bitta hujumchi izohini ikki xil yo'l bilan qo'shadi. Tugma bosilganda kod ishlashi uchun addEventListener("click", ...) ishlatdik — "bosilganda shu funksiyani chaqir" degani, uni addEventListener asoslari darsida to'liq o'rganamiz:
<button type="button" id="xavfli">innerHTML bilan</button>
<button type="button" id="xavfsiz">textContent bilan</button>
<p id="izoh"></p>
<script>
const izoh = document.querySelector("#izoh");
const matn =
'Zo\'r! <img src="x" onerror="console.log(\'XSS!\')">';
document.querySelector("#xavfli")
.addEventListener("click", () => {
izoh.innerHTML = matn;
});
document.querySelector("#xavfsiz")
.addEventListener("click", () => {
izoh.textContent = matn;
});
</script>"innerHTML bilan" ni bosing — konsolda qizil emas, oddiy XSS! qatori chiqadi: hujumchining kodi ishladi. "textContent bilan" ni bosing — konsol jim, ekranda esa hujumchining matni harflar bo'lib turadi. Har bosishda paragraf qaytadan yoziladi, shuning uchun tartibni almashtirib ham sinab ko'ring.
6.4 Hujumchi yana qayerdan kiradi
innerHTML yolg'iz emas. Satrni HTML deb o'qiydigan har qanday joy — "eshik". Ularni xavfsizlik tilida sink (lavabo) deyishadi: ma'lumot oqib kelib, kodga aylanadigan joy.
| Xavfli (satrni HTML deb o'qiydi) | Xavfsiz (matn sifatida) |
|---|---|
innerHTML, outerHTML |
textContent |
insertAdjacentHTML (Element yaratish) |
innerText |
document.write (eski, ishlatmang) |
createElement + textContent |
Ma'lumot esa ko'p joydan kelishi mumkin: izoh, ism, forma maydoni, URL'dagi ?qidiruv=... qismi, boshqa saytdan kelgan javob. Qoida bitta: o'zingiz yozmagan har qanday satr — begona. Begona satr xavfli ustunga tushmasin.
7. HTML kerak bo'lsa nima qilish kerak?
Ba'zan begona ma'lumotni HTML ichiga qo'yish kerak bo'ladi: masalan, kartada nom qalin, narx alohida rangda. Uchta yo'l bor.
7.1 Tuzilmani o'zingiz yasang, ma'lumotni textContent bilan qo'ying
Eng ishonchli yo'l — HTML qolipini o'zingiz yozasiz (u ichida begona ma'lumot yo'q), keyin begona qiymatlarni textContent bilan joyiga qo'yasiz:
<article id="karta"></article>
<script>
const taom = { nomi: "Manti <i>yangi</i>", narx: "30 000" };
const karta = document.querySelector("#karta");
karta.innerHTML = `
<h3 class="taom-nomi"></h3>
<p><b class="narx"></b> so'm</p>
`;
karta.querySelector(".taom-nomi").textContent = taom.nomi;
karta.querySelector(".narx").textContent = taom.narx;
console.log(karta.querySelector(".taom-nomi").textContent);
</script>Konsolda:
Manti <i>yangi</i>innerHTML ga faqat bizning qolipimiz tushdi. Taom nomi (u ham tashqaridan kelgan bo'lishi mumkin) textContent bilan qo'yildi — <i> kursivga aylanmadi, harflar bo'lib qoldi. Bu qolip real loyihalarda juda ko'p uchraydi. Uni <template> tegi bilan yanada qulay qilishni Ko'p elementni samarali chizish darsida ko'ramiz.
7.2 Ekranlash funksiyasi
Ikkinchi yo'l — begona matnni HTML satriga qo'yishdan oldin ekranlash: beshta maxsus belgini entity'ga almashtirish. Jadvalni HTML xavfsizligi darsida ko'rgansiz. JavaScript'da u replaceAll bilan yoziladi:
<p id="izoh"></p>
<script>
function ekranla(matn) {
return matn
.replaceAll("&", "&")
.replaceAll("<", "<")
.replaceAll(">", ">")
.replaceAll('"', """)
.replaceAll("'", "'");
}
const begona = '<img src="x" onerror="console.log(1)"> & choy';
const xavfsiz = ekranla(begona);
console.log(xavfsiz);
const izoh = document.querySelector("#izoh");
izoh.innerHTML = `<b>Izoh:</b> ${xavfsiz}`;
</script>Konsolda:
<img src="x" onerror="console.log(1)"> & choyEkranda "Izoh:" qalin, hujumchining matni esa harflar bo'lib ko'rinadi — xuddi textContent dagidek. 1 konsolga chiqmadi.
Tartibga e'tibor bering: & birinchi almashtiriladi. Nega? Agar oxirida almashtirsangiz, oldingi qadamlar yasagan < ichidagi & ham & ga aylanadi va ekranda < o'rniga < yozuvi chiqib qoladi. Bu xavfsizlik teshigi emas, lekin matn buziladi. Ikki marta ekranlash ham xuddi shu xatoni beradi.
Maslahat: Ekranlash funksiyasini o'zingiz yozish — o'rganish uchun yaxshi. Real loyihada iloji boricha birinchi yo'l (
textContent) yoki tayyor vosita ishlatiladi. O'zi yozgan "tozalovchi"da bitta belgini unutish oson. Ayniqsa, ma'lumothrefyokisrcga tushsa, ekranlash yetmaydi:javascript:bilan boshlangan havola baribir ishlaydi. Bu holatlarni XSS va DOM xavfsizligi darsida ko'ramiz.
7.3 setHTML — brauzerning o'z tozalovchisi
Uchinchi yo'l — Sanitizer API (sanitize — "tozalash"). Uning asosiy metodi element.setHTML(satr). U innerHTML kabi HTML qo'yadi, lekin oldin xavfli qismlarni olib tashlaydi: <script>, onerror kabi on... atributlar, javascript: havolalar.
<div id="izoh"></div>
<script>
const izoh = document.querySelector("#izoh");
const begona =
'<b>Osh</b> zo\'r! <img src="x" onerror="console.log(1)">';
if ("setHTML" in izoh) {
izoh.setHTML(begona);
console.log(izoh.innerHTML);
} else {
console.log("Bu brauzerda setHTML yo'q");
}
</script>Konsolda:
<b>Osh</b> zo'r!<b> qoldi — qalin "Osh" ekranda. img esa butunlay olib tashlandi, 1 chiqmadi. Bu natija Chrome'da olingan. "setHTML" in izoh — "bu elementda shunday metod bormi?" degan tekshiruv (in operatori). Brauzeringizda u bo'lmasa, konsolda "Bu brauzerda setHTML yo'q" chiqadi.
Qachon chiqdi va qayerda bor (web-features, 2026-yil oktabr holati):
| Brauzer | setHTML |
|---|---|
| Chrome, Edge | 146-versiyadan |
| Firefox | 148-versiyadan |
| Safari (iPhone ham) | yo'q |
Demak, setHTML hali Baseline emas (Veb standartlari). O'zbekistonda iPhone ko'p — Safari'siz yechimga tayanib bo'lmaydi. Shuning uchun bugun uni yolg'iz ishlatmang. Hozircha amalda ko'proq DOMPurify degan kutubxona ishlatiladi — u ham xuddi shu ishni qiladi va hamma brauzerda ishlaydi. Kutubxona ulashni keyinroq o'rganamiz, hozir bilish shart emas.
Yana bir nom uchrashi mumkin: setHTMLUnsafe. Nomidagi "Unsafe" (xavfli) so'zi bejiz emas — u tozalamaydi, innerHTML ga o'xshaydi. Yangi kodda adashtirmang.
Tekshirib ko'ring: Dasturchi shunday "himoya" yozdi:
izoh.replaceAll("<script>", ""), keyininnerHTML. Hujumchi buni qanday chetlab o'tadi?
Javob
<script> umuman shart emas: <img src="x" onerror="..."> yoki <svg onload="..."> ham kodni ishga tushiradi. Bundan tashqari <SCRIPT> (katta harf) yoki <scr<script>ipt> kabi hiylalar bor — birinchi <script> olib tashlanganda ikkinchisi "yopishib" yangi teg hosil qiladi. "Xavfli so'zlarni o'chirish" yondashuvi ishlamaydi. To'g'ri yo'l — textContent yoki ishonchli tozalovchi.
8. Qaysi birini tanlash kerak?
Diagrammani yuqoridan o'qing:
flowchart TD
S{"Nima qo'yamiz?"}
S -->|faqat matn| T["textContent"]
S -->|HTML| B{"Kim yozgan?"}
B -->|o'zimiz, kod ichida| I["innerHTML"]
B -->|begona: mehmon, server| Q{"Tuzilmani o'zimiz yasay olamizmi?"}
Q -->|ha| C["qolip + textContent"]
Q -->|yo'q| D["tozalovchi: DOMPurify, setHTML"]Kundalik ishda 90% holatda textContent yetadi. innerHTML — faqat o'zingiz yozgan, ichida begona hech narsa bo'lmagan HTML uchun.
9. Ko'p uchraydigan xatolar
9.1 input ga textContent yozish
<input id="ism" value="Ali" aria-label="Ism">
<script>
const ism = document.querySelector("#ism");
ism.textContent = "Vali";
console.log(ism.value, "|", ism.textContent);
</script>Konsolda:
Ali | ValiMaydonda hamon "Ali". input — bo'sh element, uning ichida matn ko'rsatiladigan joy yo'q. Uning ko'rinadigan qiymati — value xususiyati: ism.value = "Vali". Xato chiqmaydi — textContent ko'rinmas joyga yozildi. value atributi va xususiyatining farqini keyingi darsda ko'ramiz.
9.2 Narxni almashtirib, qalinlikni yo'qotish
p.textContent = ... ichidagi hamma elementni o'chiradi («Yozish» bo'limidagi misol). Faqat o'zgaradigan qismni span yoki b ga o'rang va o'shani toping.
9.3 "O'zimizniki" deb begona ma'lumotni innerHTML ga berish
"Bu ma'lumot o'zimizning serverimizdan keladi, xavfsiz". Server ma'lumotni qayerdan oldi? Agar uni biror foydalanuvchi yozgan bo'lsa (izoh, ism, manzil) — u begona. Server uni ekranlamagan bo'lishi mumkin. Brauzerda ham himoyani qo'yish — ikkinchi devor.
9.4 innerHTML += sikl ichida
Har aylanishda butun ro'yxat qayta quriladi va oldingi elementlar o'zgaruvchilari "uziladi" («innerHTML += tuzog'i» bo'limi). Ro'yxat qo'shish — createElement va append bilan.
9.5 Ekranlashda & ni oxirida almashtirish
"<" → < → &lt;. Ekranda < yozuvi chiqadi. & doim birinchi.
10. Mashqlar
1-mashq (oson): Narxni yangilang
Ko'k choy narxi o'zgardi. Faqat narxni (.narx) 6 000 qiling, qolgan matn va qalinlik saqlansin. Keyin butun qatorning matnini konsolga chiqaring. Kutilgan natija: Ko'k choy — 6 000 so'm.
<p id="choy">Ko'k choy — <b class="narx">5 000</b> so'm</p>
<script>
// shu yerga yozing
</script>Yechim
<p id="choy">Ko'k choy — <b class="narx">5 000</b> so'm</p>
<script>
const choy = document.querySelector("#choy");
choy.querySelector(".narx").textContent = "6 000";
console.log(choy.textContent);
</script>Konsolda:
Ko'k choy — 6 000 so'mButun p ga yozsangiz, natija matni bir xil bo'lardi, lekin narx qalin bo'lmay qolardi. 6 000 — mashq uchun narx, «Bahor» menyusida ko'k choy 5 000 so'm.
2-mashq (o'rta): Xavfsiz ro'yxat
ismlar massividagi bron qilgan mehmonlar ismini #bronlar ro'yxatiga chiqaring. Bitta ism — hujumchiniki. Talablar: XSS qatori konsolga chiqmasin; oxirida konsolga Jami: 3 ta bron yozilsin.
Ishora: «textContent bilan» bo'limidagi qolip — createElement("li"), textContent, append — for...of ichida.
<h3>Bugungi bronlar</h3>
<ul id="bronlar"></ul>
<script>
const ismlar = [
"Malika",
"Bobur",
'<img src="x" onerror="console.log(\'XSS\')">Sardor',
];
// shu yerga yozing
</script>Yechim
<h3>Bugungi bronlar</h3>
<ul id="bronlar"></ul>
<script>
const ismlar = [
"Malika",
"Bobur",
'<img src="x" onerror="console.log(\'XSS\')">Sardor',
];
const bronlar = document.querySelector("#bronlar");
for (const ism of ismlar) {
const li = document.createElement("li");
li.textContent = ism;
bronlar.append(li);
}
console.log(`Jami: ${bronlar.children.length} ta bron`);
</script>Konsolda:
Jami: 3 ta bronUchinchi qatorda hujumchining yozuvi harflar bo'lib ko'rinadi. bronlar.children.length o'rniga ismlar.length ham yozsa bo'ladi — lekin DOM'dan sanash "sahifada haqiqatan nechta element bor?" degan savolga javob beradi.
3-mashq (qiyin): Ekranlash va qolip
Taom kartasini innerHTML bilan yasang: h3 da nom, p da narx va " so'm". Nom tashqaridan keladi va unda HTML bo'lishi mumkin. Ikki xil yo'l bilan yeching: (a) «Ekranlash funksiyasi» bo'limidagi ekranla bilan; (b) qolip + textContent bilan. Ikkala holatda ham konsolga h3 ning textContent ini chiqaring — natija bir xil bo'lishi kerak: Lag'mon <b>achchiq</b>.
<p>Ikki karta — ikki yo'l:</p>
<article id="a"></article>
<article id="b"></article>
<script>
const taom = { nomi: "Lag'mon <b>achchiq</b>", narx: "28 000" };
// (a) — #a ga, (b) — #b ga
</script>Yechim
<p>Ikki karta — ikki yo'l:</p>
<article id="a"></article>
<article id="b"></article>
<script>
function ekranla(matn) {
return matn
.replaceAll("&", "&")
.replaceAll("<", "<")
.replaceAll(">", ">")
.replaceAll('"', """)
.replaceAll("'", "'");
}
const taom = { nomi: "Lag'mon <b>achchiq</b>", narx: "28 000" };
// (a) ekranlash
const a = document.querySelector("#a");
a.innerHTML = `
<h3>${ekranla(taom.nomi)}</h3>
<p>${ekranla(taom.narx)} so'm</p>
`;
console.log(a.querySelector("h3").textContent);
// (b) qolip + textContent
const b = document.querySelector("#b");
b.innerHTML = "<h3></h3><p><span></span> so'm</p>";
b.querySelector("h3").textContent = taom.nomi;
b.querySelector("span").textContent = taom.narx;
console.log(b.querySelector("h3").textContent);
</script>Konsolda:
Lag'mon <b>achchiq</b>
Lag'mon <b>achchiq</b>Ikkalasi bir xil ko'rinadi. Farq — xatoga chidamlilikda. (a) da ekranla ni bitta joyda unutsangiz, teshik ochiladi. (b) da begona ma'lumot umuman HTML satriga tushmaydi — unutadigan narsa yo'q. Narx ham ekranlandi: hozir u bizniki, lekin ertaga serverdan kelishi mumkin.
4-mashq: Portfolio qadami — footer'dagi yil
Portfolio footer'ida © 2026 Ismingiz. yozilgan. Yangi yil kelsa, oltita sahifada qo'lda almashtirish kerak. Buni JavaScript'ga topshiramiz.
- Oltita sahifaning footer'ida yilni
spanga o'rang:© <span id="yil">2026</span> Ismingiz.HTML'dagi 2026 — zaxira: JavaScript ishlamasa ham yil ko'rinadi. asosiy.jsgayilniYangilafunksiyasini qo'shing:#yilni topsin, bo'lmasa jim tugasin (erta qaytish), bor bo'lsa —textContentga joriy yilni yozsin.- Joriy yil:
new Date().getFullYear().Date— sana va vaqt bilan ishlaydigan tayyor obyekt, Sayoz va chuqur nusxalash darsidagetFullYearni ko'rgansiz. SanalarniDateasoslari darsida chuqur o'rganamiz. - Funksiyani fayl oxirida, oldingi chaqiruvlardan keyin chaqiring: har yangi funksiya va uning chaqiruvi — faylning eng pastiga.
npm run check, commit:JS: footer yilini avtomatik yangila.
Yechim
asosiy.js ga:
function yilniYangila() {
const yil = document.querySelector("#yil");
if (yil === null) {
return;
}
yil.textContent = new Date().getFullYear();
}
yilniYangila();Footer (har sahifada):
<footer>
<p>© <span id="yil">2026</span> Aziz Karimov.</p>
</footer>Mini-sinov — joriy yil konsolda va footer'da:
<footer>
<p>© <span id="yil">2026</span> Aziz Karimov.</p>
</footer>
<script>
function yilniYangila() {
const yil = document.querySelector("#yil");
if (yil === null) {
return;
}
yil.textContent = new Date().getFullYear();
}
yilniYangila();
console.log(typeof document.querySelector("#yil").textContent);
</script>Konsolda:
stringgetFullYear() son qaytaradi, textContent uni satrga aylantirdi — «Son, bo'sh satr va null» bo'limidagidek. Bu yerda innerHTML kerak emas: yil — oddiy matn. Footer'dagi yilni hozir faqat kompyuteringiz soatini o'zgartirib tekshirish mumkin — muhim emas, kod bir xil ishlaydi.
11. Real ishda
- Har bir dinamik sahifa — savat soni, bildirishnoma matni, qidiruv natijalari —
textContentbilan yangilanadi. Kod ko'rigida (code review)innerHTMLko'rinsa, birinchi savol: "bu yerga begona ma'lumot tushishi mumkinmi?" - Freymvorklar (React, Vue — kursda alohida o'rganamiz) matnni sukut bo'yicha ekranlaydi — ularda ham "HTML qo'yish" uchun maxsus, ataylab qo'rqinchli nomli yo'l bor (React'da
dangerouslySetInnerHTML). Nomi "xavfli" — bugungi saboq aynan shu. - Linterlar — kodni avtomatik tekshiradigan vositalar (kursda alohida o'rganamiz) —
innerHTMLga o'zgaruvchi berilganini ogohlantirish bilan belgilay oladi. - Brauzer himoyalari: Content Security Policy (CSP) va Trusted Types
innerHTMLga begona satr tushishini brauzer darajasida to'sishi mumkin (XSS va DOM xavfsizligi, Brauzer xavfsizlik modeli). - Intervyuda tez-tez so'raladi: "
textContent,innerTextvainnerHTMLfarqi?", "XSS nima va undan qanday himoyalanasiz?" Bugun ikkalasiga javob berishni o'rgandingiz.
Xulosa
textContent— elementning hamma matni; unga yozish ichidagi hamma narsani bitta matn bilan almashtiradi va har doim xavfsiz.innerText— ekranda ko'rinadigan matn (CSS'ni hisobga oladi), sekinroq.innerHTMLsatrni HTML deb o'qiydi;+=hamma elementlarni qayta yaratadi;<script>ishlamaydi, lekinonerrorishlaydi.outerHTMLelementni almashtiradi — eski o'zgaruvchi uzilgan elementga qaraydi.- XSS: begona satr HTML deb o'qilganda hujumchining kodi ishlaydi. Himoya:
textContent, qolip +textContent, ekranlash (&birinchi) yoki tozalovchi. setHTML— Chrome 146+ va Firefox 148+ da bor, Safari'da yo'q: hali Baseline emas.
Keyingi dars: Atributlar, xususiyatlar va dataset — elementning matnini emas, atributlarini o'zgartiramiz va nega input da value ikki xil ekanini ko'ramiz.
Manbalar
- MDN: "Node: textContent property", "HTMLElement: innerText property", "Element: innerHTML property" — developer.mozilla.org
- MDN: "Element: setHTML() method", "HTML Sanitizer API" — developer.mozilla.org
- OWASP: "Cross Site Scripting Prevention Cheat Sheet" — cheatsheetseries.owasp.org
- web-features: "sanitizer" — github.com/web-platform-dx/web-features
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!