18-bo‘lim

Xavfsizlik

XSS va chiqishni ekranlash, yo'ldan chiqish hujumi, so'rovlarni cheklash, xavfsizlik sarlavhalari, maxfiy ma'lumot va bog'liqliklar xavfi.

🕑 10 daqiqa o‘qish 📄 854 so‘z 👁 0 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. XSS - chiqishni ekranlash
  2. Yo'ldan chiqish hujumi
  3. So'rovlarni cheklash
  4. Xavfsizlik sarlavhalari
  5. Maxfiy ma'lumot
  6. Bog'liqliklar
  7. Qisqa ro'yxat
  8. Xulosa

Oldingi bo'limlarda xavfsizlik haqida yo'l-yo'lakay gapirdik. Bu bo'limda qolganlarini bir joyga yig'amiz.

Asosiy tamoyil bitta: tashqaridan kelgan hech narsaga ishonmang.

XSS - chiqishni ekranlash #

JavaScript
function ekranla(matn) {
    return String(matn)
        .replaceAll("&", "&")
        .replaceAll("<", "&lt;")
        .replaceAll(">", "&gt;")
        .replaceAll('"', "&quot;")
        .replaceAll("'", "&#39;");
}

const yomon = '<script>alert("xato")</script>';

console.log("Xom:", yomon);
console.log("Ekranlangan:", ekranla(yomon));
console.log("Skript qoldimi:", ekranla(yomon).includes("<script>"));
Natija
Xom: <script>alert("xato")</script>
Ekranlangan: &lt;script&gt;alert(&quot;xato&quot;)&lt;/script&gt;
Skript qoldimi: false
XSS - foydalanuvchi kodini sizning sahifangizda ishlatish

Tasavvur qiling: izohlar bo'limi bor va kimdir izoh sifatida yuqoridagi matnni yozdi.

Agar uni sahifaga shundayligicha qo'ysangiz, brauzer uni matn emas, kod deb biladi va ishga tushiradi. Skript esa boshqa foydalanuvchilarning cookie sini o'g'irlashi mumkin.

Bu XSS (Cross-Site Scripting) deb ataladi.

Himoya ikki qavatli:

  1. Chiqishni ekranlang - yuqoridagi kabi. Zamonaviy shablon dvigatellari buni avtomatik qiladi; innerHTML esa qilmaydi. Brauzerda textContent ishlating.
  2. httpOnly cookie (17-bo'lim) - skript sessiyani o'qiy olmaydi.

Muhim nozik joy: ekranlash chiqishda bo'ladi, kiritishda emas. Ma'lumotni bazaga asl holida saqlang - chunki u JSON ga, elektron pochtaga yoki CSV ga ham chiqishi mumkin va har birining ekranlash qoidasi boshqa.

Yo'ldan chiqish hujumi #

JavaScript
import { join, resolve, sep } from "node:path";

const ildiz = resolve("/var/www/ommaviy");

function xavfliYol(soralgan) {
    return join(ildiz, soralgan);
}

function xavfsizYol(soralgan) {
    const toliq = resolve(ildiz, soralgan);
    if (toliq !== ildiz && !toliq.startsWith(ildiz + sep)) {
        return null;
    }
    return toliq;
}

const yaxshi = "rasmlar/logo.png";
const yomon = "../../../etc/parol";

console.log("Xavfli, yaxshi so'rov:", xavfliYol(yaxshi));
console.log("Xavfli, yomon so'rov:", xavfliYol(yomon));
console.log("Xavfsiz, yaxshi so'rov:", xavfsizYol(yaxshi));
console.log("Xavfsiz, yomon so'rov:", xavfsizYol(yomon));
Natija
Xavfli, yaxshi so'rov: /var/www/ommaviy/rasmlar/logo.png
Xavfli, yomon so'rov: /etc/parol
Xavfsiz, yaxshi so'rov: /var/www/ommaviy/rasmlar/logo.png
Xavfsiz, yomon so'rov: null
join o'zi himoya qilmaydi

Ikkinchi qatorga qarang: join .. larni hisoblab, yo'lni papkadan butunlay chiqarib yubordi. Natijada tizim fayli ochildi.

Bu yo'ldan chiqish (path traversal) hujumi. 12-bo'limdagi joker belgili marshrut aynan shunga ochiq edi.

Himoya uch qadam:

  1. So'ralgan yo'lni normallashtiring;
  2. Ildizga nisbatan to'liq yo'lga aylantiring;
  3. Natija ildiz ichida qolganini tekshiring.

Eng ishonchli yechim esa - foydalanuvchi bergan matnni yo'l qilib ishlatmaslik. Fayllarni bazadagi identifikator bo'yicha toping, nom bo'yicha emas.

Statik fayllar uchun express.static ni ishlating - u bu tekshiruvni o'zi qiladi.

So'rovlarni cheklash #

JavaScript
import express from "express";

const app = express();

function cheklov({ oyna, chegara }) {
    const urinishlar = new Map();
    let soat = 0;

    const qatlam = (sorov, javob, keyingi) => {
        const kalit = sorov.ip ?? "nomalum";
        const yozuv = urinishlar.get(kalit) ?? { soni: 0, boshi: soat };

        if (soat - yozuv.boshi >= oyna) {
            yozuv.soni = 0;
            yozuv.boshi = soat;
        }

        yozuv.soni++;
        urinishlar.set(kalit, yozuv);

        if (yozuv.soni > chegara) {
            javob.status(429).json({ xato: "juda ko'p so'rov" });
            return;
        }
        keyingi();
    };

    qatlam.soatniSur = (n) => { soat += n; };
    return qatlam;
}

const cheklagich = cheklov({ oyna: 60, chegara: 3 });
app.use(cheklagich);
app.get("/", (s, j) => j.json({ holat: "yaxshi" }));

const server = app.listen(0);
const port = server.address().port;
const asos = `http://localhost:${port}/`;

const holatlar = [];
for (let i = 0; i < 5; i++) {
    holatlar.push((await fetch(asos)).status);
}
console.log("Besh so'rov:", holatlar.join(", "));

cheklagich.soatniSur(61);
console.log("Oyna tugagach:", (await fetch(asos)).status);

server.close();
Natija
Besh so'rov: 200, 200, 200, 429, 429
Oyna tugagach: 200

429 Too Many Requests - "juda ko'p so'radingiz" degan holat kodi.

Kirish sahifasini albatta cheklang

Cheklovsiz kirish shakli - parolni taxmin qilish uchun ochiq eshik. Hujumchi soniyada minglab parolni sinab ko'ra oladi.

Kamida ikki joyni cheklang:

  1. Kirish va parolni tiklash - IP va login bo'yicha, qattiq chegara bilan.
  2. Butun API - umumiy, kengroq chegara bilan.

Yuqoridagi misol soddalashtirilgan: u xotirada saqlaydi, demak server qayta ishga tushsa yoki bir nechta server bo'lsa ishlamaydi. Haqiqiy loyihada Redis yoki express-rate-limit paketi ishlatiladi.

Diqqat: sorov.ip teskari proksi ortida noto'g'ri bo'lishi mumkin. Bunday holatda app.set("trust proxy", 1) kerak - lekin uni faqat ishonchli proksi ortida yozing.

Xavfsizlik sarlavhalari #

JavaScript
import express from "express";

const app = express();

app.disable("x-powered-by");

app.use((sorov, javob, keyingi) => {
    javob.set({
        "X-Content-Type-Options": "nosniff",
        "X-Frame-Options": "DENY",
        "Referrer-Policy": "no-referrer",
        "Content-Security-Policy": "default-src 'self'",
    });
    keyingi();
});

app.get("/", (s, j) => j.json({ holat: "yaxshi" }));

const server = app.listen(0);
const port = server.address().port;

const javob = await fetch(`http://localhost:${port}/`);

console.log("x-powered-by:", javob.headers.get("x-powered-by"));
console.log("nosniff:", javob.headers.get("x-content-type-options"));
console.log("frame:", javob.headers.get("x-frame-options"));
console.log("csp bor:", javob.headers.has("content-security-policy"));

server.close();
Natija
x-powered-by: null
nosniff: nosniff
frame: DENY
csp bor: true
x-powered-by ni nima uchun o'chirish kerak

Birinchi qator null - va bu aynan kerak edi.

Odatiy holda Express har bir javobga X-Powered-By: Express sarlavhasini qo'shadi. U hech qanday foyda bermaydi, lekin hujumchiga qaysi texnologiya ishlatilayotganini bepul aytib beradi. Shundan keyin u aynan Express ning ma'lum zaifliklarini qidira boshlaydi.

app.disable("x-powered-by") uni butunlay olib tashlaydi.

Bu "noaniqlik orqali xavfsizlik" - u o'z-o'zidan himoya emas, lekin bepul va foydasi bor.

SarlavhaNimadan himoya qiladi
X-Content-Type-Options: nosniffBrauzer fayl turini taxmin qilishidan
X-Frame-Options: DENYSahifani begona saytga joylashdan
Referrer-PolicyManzil boshqa saytga sizib chiqishidan
Content-Security-PolicyBegona skript ishlashidan

Amalda bularni qo'lda yozmasdan, helmet paketi ishlatiladi - u oqilona odatiy qiymatlarni beradi.

Maxfiy ma'lumot #

JavaScript
const sozlama = {
    port: process.env.PORT ?? "3000",
    bazaUrl: process.env.BAZA_URL ?? "sqlite::memory:",
    maxfiyKalit: process.env.MAXFIY_KALIT ?? null,
};

function xavfsizKorinish(s) {
    return {
        ...s,
        maxfiyKalit: s.maxfiyKalit ? "***" : null,
    };
}

console.log(xavfsizKorinish(sozlama));

if (!sozlama.maxfiyKalit) {
    console.log("Ogohlantirish: MAXFIY_KALIT berilmagan");
}
Natija
{ port: '3000', bazaUrl: 'sqlite::memory:', maxfiyKalit: null }
Ogohlantirish: MAXFIY_KALIT berilmagan
Maxfiy ma'lumotni jurnalga yozmang

Eng ko'p uchraydigan sizib chiqish yo'li - jurnal fayllari.

JavaScript
console.log("Sozlama:", sozlama);          // kalit jurnalda
console.log("So'rov:", sorov.headers);     // cookie va token jurnalda
console.error(xato);                 // xatoda parol bo'lishi mumkin

Jurnal ko'pincha uchinchi tomon xizmatiga yuboriladi, uzoq saqlanadi va unga ko'p odam kirishi mumkin.

Qoidalar:

  1. Butun obyektni jurnalga tashlamang - kerakli maydonlarni tanlab yozing.
  2. Maxfiy maydonlarni niqoblang (yuqoridagi ***).
  3. Mijozga qaytadigan xatoda tafsilot bo'lmasin (10-bo'lim).
  4. .env ni git ga qo'shmang (2-bo'lim).

Va eng muhimi: kalit tasodifan git ga tushsa, uni o'chirish yetarli emas - u tarixda qoladi. Kalitni almashtirish kerak.

Bog'liqliklar #

Eng katta xavf - o'zingiz yozmagan kod

4-bo'limda aytilgan edi: har bir npm install - begona kodga ishonch.

Amaliy choralar:

  1. npm audit ni muntazam ishlating.
  2. package-lock.json va npm ci - kutilmagan versiya kelib qolmaydi.
  3. Paket qo'shishdan oldin standart kutubxonani tekshiring. Node da bugun fetch, test yurituvchi, .env o'qish va SQLite bor.
  4. npm install skriptlarni ishga tushirishi mumkin. Ishonchsiz paket uchun --ignore-scripts bayrog'i bor.
  5. Bog'liqliklarni kam saqlang. Har bir olib tashlangan paket - kamaygan xavf.

Qisqa ro'yxat #

XavfHimoyaBo'lim
SQL in'yeksiyaTayyorlangan so'rovlar16
XSSChiqishni ekranlash, httpOnly18, 17
CSRFsameSite cookie17
Yo'ldan chiqishYo'lni tekshirish18
Parol o'g'irlashscrypt + tuz17
Ommaviy tayinlashRuxsat etilganlar ro'yxati14
Katta so'rovlimit va 41310, 13
Taxmin qilishSo'rovlarni cheklash18
Ma'lumot sizishiXato tafsilotini yashirish10
Amaliy topshiriq
  1. HTML ekranlaydigan funksiya yozing.
  2. <script> teg qolmasligini tekshiring.
  3. join bilan ../../.. ni sinab ko'ring.
  4. Yo'lni ildiz ichida ekanini tekshiradigan funksiya yozing.
  5. So'rovlarni cheklovchi qatlam yozing.
  6. 429 holat kodini qaytaring.
  7. x-powered-by ni o'chiring.
  8. To'rtta xavfsizlik sarlavhasini qo'ying.
  9. Maxfiy kalitni niqoblab chiqaring.
  10. npm audit ni ishga tushiring.

Xulosa #

  • Tashqaridan kelgan hech narsaga ishonmang.
  • XSS dan himoya - chiqishni ekranlash va httpOnly cookie; ekranlash kiritishda emas, chiqishda.
  • join yo'ldan chiqishdan himoya qilmaydi - natija ildiz ichidami, tekshiring.
  • Kirish sahifasini albatta cheklang; 429 qaytaring.
  • x-powered-by ni o'chiring va xavfsizlik sarlavhalarini qo'ying.
  • Maxfiy ma'lumotni jurnalga yozmang; sizib chiqqan kalitni almashtiring.
  • Bog'liqliklarni kam saqlang va npm ci ishlating.

Keyingi bo'limda testlarni o'rganamiz.

Xatolik topdingizmi?

Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.