Node.js server xavfsizligi

Serverda ishlaydigan dastur brauzerdagi koddan bir jihati bilan keskin farq qiladi: u sizning fayllaringiz, bazangiz va kalitlaringiz yonida turadi. Xatoning narxi ham shunga yarasha.

Bu darsdagi to’rt mavzu — eng ko’p uchraydigan va eng qimmatga tushadigan xatolar.

1. Maxfiy ma’lumot kodda turmaydi

Eng keng tarqalgan xato shunday ko’rinadi:

// Bunday yozmang
const apiKey = "sk-live-8f2a1c443e7b4c91a2d5";

Kalit kodga yozilgan. Demak u omborga tushadi, jamoadagi hammaga ko’rinadi va ombor ochiq bo’lsa — butun internetga.

To’g’ri yo’l — process darsida ko’rgan muhit o’zgaruvchilari.

.env faylida:

API_KEY=sk-live-8f2a1c443e7b4c91a2d5
DATABASE_PATH=./data/app.db

Kodda:

const apiKey = process.env.API_KEY;

if (!apiKey) {
  console.log("API_KEY berilmagan");
  process.exit(1);
}

console.log("Kalit uzunligi:", apiKey.length);
node --env-file=.env app.js
Kalit uzunligi: 25

Kalit yo’qligini oldindan tekshirish muhim: usiz dastur ishlayveradi va xato ancha keyin, tushunarsiz shaklda chiqadi.

.gitignore majburiy

.env faylini omborga tushmaydigan qilish kerak:

node_modules/
.env
*.db

Tekshiruv usuli:

git status --short

Ro’yxatda .env ko’rinmasligi kerak. Ko’rinsa, .gitignore noto’g’ri yozilgan yoki fayl allaqachon kuzatuvga olingan.

2. Bog’liqliklar xavfi

Bitta paket o’rnatsangiz, u o’z bog’liqliklarini tortadi, ular esa o’zinikini. Natijada loyihada yuzlab begona paket paydo bo’ladi.

Ma’lum zaifliklarni tekshirish uchun buyruq bor:

npm audit

Muammo topilmasa:

found 0 vulnerabilities

Topilsa, taxminan shunday chiqadi:

# npm audit report

semver  <5.7.2
Severity: moderate
semver vulnerable to Regular Expression Denial of Service
fix available via `npm audit fix`

1 moderate severity vulnerability

Tuzatish:

npm audit fix

Paket nomini tekshiring

Hujumchilar mashhur paketga o’xshash nom bilan zararli paket joylashtiradi. Bir harf farq qilgan nom, chalkashtirish uchun qo’yilgan defis — natija bir xil: siz begona kodni o’rnatasiz.

TypeScript darsida buning jonli namunasi uchradi: npx tsc buyrug’i rasmiy kompilyator o’rniga tsc nomli begona paketni yuklab oldi.

O’rnatishdan oldin ko’rib chiqing:

npm view express

Uch narsaga qarang:

Nima Nimani bildiradi
Haftalik yuklab olishlar Juda kam bo’lsa — ehtiyot bo’ling
Oxirgi yangilanish sanasi Yillar oldin bo’lsa, qo’llab-quvvatlanmaydi
Ombor havolasi Ochiq kodmi, muammolar bo’limi jonlimi

3. Foydalanuvchi bergan fayl yo’li

Endi fs va path darslariga tayanadigan mavzu.

Dastur foydalanuvchidan fayl nomini olib, uni o’qib berishi kerak deylik. Xavfli yozuv shunday ko’rinadi:

fs.readFileSync(path.join(uploadsDir, userInput))

Bir qarashda himoyalangandek: fayl uploads papkasidan olinyapti. Muammo userInput ichida nima bo’lishi mumkinligida.

Foydalanuvchi oddiy fayl nomi o’rniga bir necha marta .. yozib yuborsa, path.join ularni hisobga oladi va natijada hosil bo’lgan yo’l uploads dan chiqib ketadi. Shu yo’l bilan tizim fayllarini yoki sizning .env faylingizni so’rash mumkin.

Himoya — yo’lni yig’ib bo’lgandan keyin tekshirish:

const fs = require("node:fs");
const path = require("node:path");

const uploadsDir = path.join(__dirname, "uploads");

function readUserFile(fileName) {
  // Yo'lni to'liq, normallashtirilgan shaklga keltiramiz
  const fullPath = path.resolve(uploadsDir, fileName);

  // Natija ruxsat etilgan papka ichida qoldimi
  if (!fullPath.startsWith(uploadsDir + path.sep)) {
    throw new Error("Ruxsat etilmagan yo'l");
  }

  return fs.readFileSync(fullPath, "utf8");
}

try {
  console.log(readUserFile("notes.txt"));
} catch (error) {
  console.log("Xato:", error.message);
}

Oddiy fayl so’ralganda:

Birinchi qator
Ikkinchi qator

Papkadan chiqishga urinilganda:

Xato: Ruxsat etilmagan yo'l

Kalit qism — path.resolve natijasini tekshirish. .. bo’laklari shu bosqichda hisoblanib bo’ladi, shuning uchun startsWith tekshiruvi ishonchli ishlaydi.

4. Buyruqqa kiritma bermaslik

child_process darsidagi qoidani takrorlaymiz, chunki u eng jiddiy xavflardan biri.

exec berilgan satrni shell orqali bajaradi. Shell esa ;, && va | belgilarini buyruq ajratuvchisi deb biladi. Shuning uchun foydalanuvchi matnini buyruq satriga yopishtirish begona odamga serveringizda o’z buyrug’ini bajarish imkonini beradi.

Yechim — shellni umuman ishlatmaslik:

const { execFile } = require("node:child_process");

function checkHost(host) {
  // Argument alohida massivda ketadi, shell uni izohlamaydi
  execFile("ping", ["-n", "1", host], (error, stdout) => {
    if (error) {
      console.log("Javob kelmadi");
      return;
    }
    console.log("Javob keldi, uzunligi:", stdout.length);
  });
}

checkHost("example.com");

Uchala hujum bir xil mantiqqa asoslanadi: ma’lumot buyruqqa aylanib qolgan.

Hujum Ma’lumot qayerga qo’shilgan Himoya
SQL injection So’rov matniga Parametrli so’rov ?
Shell injection Buyruq satriga execFile va argument massivi
Path traversal Fayl yo’liga Natijani tekshirish

SQL injection darsidagi qoida shu jadvalning birinchi qatori.

Kiruvchi ma’lumotni tekshirish

Umumiy qoida: tashqaridan kelgan qiymat kutilgan shaklda ekanini tasdiqlang.

function parsePage(rawValue) {
  const page = Number(rawValue);

  if (!Number.isInteger(page) || page < 1 || page > 1000) {
    return 1;
  }

  return page;
}

console.log(parsePage("5"));
console.log(parsePage("salom"));
console.log(parsePage("-3"));
console.log(parsePage("999999"));
node validate-demo.js
5
1
1
1

Noto’g’ri qiymat rad etildi va xavfsiz standart qaytdi. Yuqori chegara ham qo’yilgani muhim: juda katta son bilan bazaga og’ir so’rov yuborishning oldini oladi.

Xatolarni foydalanuvchiga ko’rsatmang

Xatolar va jurnal darsida ko’rgan stack trace ichida fayl yo’llari va ba’zan ma’lumotlar bazasi tuzilishi bo’ladi.

Ikki manzilni ajrating:

const { log } = require("./logger");

function handleError(error) {
  // To'liq tafsilot — jurnalga
  log("error", "So'rovni bajarishda xato", {
    errorName: error.name,
    errorMessage: error.message,
  });

  // Foydalanuvchiga — qisqa xabar
  return { message: "Ichki xato yuz berdi" };
}

console.log(handleError(new Error("SQLITE_ERROR: no such table: users")));
{"time":"2026-09-12T13:20:11.004Z","level":"error","message":"So'rovni bajarishda xato","errorName":"Error","errorMessage":"SQLITE_ERROR: no such table: users"}
{ message: 'Ichki xato yuz berdi' }

Jurnalda hamma narsa bor, tashqariga esa faqat umumiy xabar chiqdi.

Node.js ni yangilab turing

Node.js versiyalarida ham zaiflik topiladi va ular yangi chiqarilishlarda tuzatiladi.

node --version
v24.14.1

Qaysi versiya hozir LTS ekanini rasmiy saytdan tekshiring — bu ro’yxat vaqt bilan o’zgaradi.

Amaliy mashq

  1. Kodda yozilgan kalitni .env fayliga ko’chiring va --env-file bilan ishga tushiring;
  2. .gitignore ga .env qo’shib, git status --short da ko’rinmasligini tasdiqlang;
  3. Loyihada npm audit yuriting va hisobotni o’qing;
  4. readUserFile funksiyasini yozib, oddiy fayl nomi bilan hamda papkadan chiqishga urinish bilan sinang;
  5. parsePage funksiyasini yozib, unga son, matn va manfiy qiymat bering;
  6. Xatoni jurnalga to’liq, javobga qisqa yozadigan funksiya tuzing.

4-qadam eng muhimi: fayl yo’lini tekshirish serverdagi eng ko’p e’tibordan chetda qoladigan zaiflik.

Qisqacha xulosa

  • Maxfiy kalit hech qachon kodga yozilmaydi.env va .gitignore ishlatiladi.
  • Git tarixiga tushgan kalit o’chirilmaydi: uni bekor qilish kerak.
  • Har o’rnatilgan paket sizning huquqlaringiz bilan ishlaydi — npm audit bilan tekshirib turing.
  • Paket nomini o’rnatishdan oldin ko’zdan kechiring: o’xshash nomlar hujum vositasi.
  • Foydalanuvchi bergan fayl yo’li path.resolve dan keyin tekshiriladi.
  • Foydalanuvchi matni exec buyrug’iga qo’shilmaydi — execFile va argument massivi ishlatiladi.
  • Xato tafsiloti jurnalga yoziladi, foydalanuvchiga qisqa xabar qaytariladi.

Keyingi darsda tezlik va profil olish — sekin joyni taxmin qilmasdan o’lchash.

Bu dars foydali bo'ldimi?

marta ko'rildi