14-bo‘lim

Formalar va validatsiya

HTML forma ma'lumotini o'qish, JSON bilan farqi, maydonlar bo'yicha tekshirish, 400 va 422 kodlari hamda ma'lumotni tozalash.

🕑 9 daqiqa o‘qish 📄 538 so‘z 👁 0 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. Ikki xil forma ma'lumoti
  2. Oddiy tekshiruv
  3. Serverga ulash
  4. Buzuq JSON
  5. Ruxsat etilgan maydonlar
  6. Tozalash
  7. Xulosa

Foydalanuvchidan kelgan har qanday ma'lumot - ishonchsiz. Uni tekshirmasdan ishlatish eng keng tarqalgan xavfsizlik xatosi.

Ikki xil forma ma'lumoti #

JavaScript
import express from "express";

const app = express();

app.use(express.json());
app.use(express.urlencoded({ extended: true }));

app.post("/qabul", (sorov, javob) => {
    javob.json({ turi: sorov.get("content-type"), tana: sorov.body });
});

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

const json = await fetch(asos, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ ism: "Malika", yosh: 20 }),
});
console.log(await json.json());

const forma = await fetch(asos, {
    method: "POST",
    headers: { "Content-Type": "application/x-www-form-urlencoded" },
    body: new URLSearchParams({ ism: "Aziza", yosh: "19" }),
});
console.log(await forma.json());

server.close();
Natija
{ turi: 'application/json', tana: { ism: 'Malika', yosh: 20 } }
{
  turi: 'application/x-www-form-urlencoded',
  tana: { ism: 'Aziza', yosh: '19' }
}

Ikkita muhim farqni ko'ring:

JSONHTML forma
Qatlamexpress.json()express.urlencoded()
Son turiSon bo'lib keladiSatr bo'lib keladi
Formadan kelgan hamma narsa satr

yosh: '19' - qo'shtirnoq ichida. HTML forma faqat matn yuboradi; sonlar, sanalar, mantiqiy qiymatlar - hammasi satr.

Bu 6-bo'limdagi process.env va 12-bo'limdagi sorov.params bilan bir xil tuzoq. Uchalasida ham qoida bitta: aylantiring va tekshiring.

express.urlencoded({ extended: true }) - ichma-ich obyektlarni ham tushunadi (foydalanuvchi[ism]). false bo'lsa, faqat oddiy kalit-qiymat.

Oddiy tekshiruv #

JavaScript
function talabaniTekshir(malumot) {
    const xatolar = {};

    const ism = String(malumot.ism ?? "").trim();
    if (ism.length < 2) {
        xatolar.ism = "ism kamida 2 belgidan iborat bo'lsin";
    } else if (ism.length > 50) {
        xatolar.ism = "ism 50 belgidan oshmasin";
    }

    const ball = Number(malumot.ball);
    if (!Number.isInteger(ball)) {
        xatolar.ball = "ball butun son bo'lsin";
    } else if (ball < 0 || ball > 100) {
        xatolar.ball = "ball 0 va 100 orasida bo'lsin";
    }

    return { toza: { ism, ball }, xatolar };
}

console.log(talabaniTekshir({ ism: "  Malika  ", ball: "88" }));
console.log(talabaniTekshir({ ism: "M", ball: 150 }));
console.log(talabaniTekshir({}));
Natija
{ toza: { ism: 'Malika', ball: 88 }, xatolar: {} }
{
  toza: { ism: 'M', ball: 150 },
  xatolar: {
    ism: "ism kamida 2 belgidan iborat bo'lsin",
    ball: "ball 0 va 100 orasida bo'lsin"
  }
}
{
  toza: { ism: '', ball: NaN },
  xatolar: {
    ism: "ism kamida 2 belgidan iborat bo'lsin",
    ball: "ball butun son bo'lsin"
  }
}

Uch tamoyil:

  1. Tozalash - trim(), keraksiz bo'shliqni olib tashlash.
  2. Aylantirish - Number(), String().
  3. Hamma xatoni yig'ish - birinchisida to'xtamaslik.

Serverga ulash #

JavaScript
import express from "express";

const app = express();
app.use(express.json());

function tekshir(malumot) {
    const xatolar = {};
    const ism = String(malumot.ism ?? "").trim();
    if (ism.length < 2) xatolar.ism = "juda qisqa";

    const ball = Number(malumot.ball);
    if (!Number.isInteger(ball) || ball < 0 || ball > 100) {
        xatolar.ball = "0 va 100 orasida butun son bo'lsin";
    }
    return { toza: { ism, ball }, xatolar };
}

app.post("/talabalar", (sorov, javob) => {
    const { toza, xatolar } = tekshir(sorov.body ?? {});

    if (Object.keys(xatolar).length > 0) {
        javob.status(422).json({ xato: "tekshiruvdan o'tmadi", xatolar });
        return;
    }

    javob.status(201).json({ yaratildi: toza });
});

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

const yubor = async (tana) => {
    const j = await fetch(asos, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(tana),
    });
    return [j.status, await j.json()];
};

console.log(await yubor({ ism: "Nodira", ball: 91 }));
console.log(await yubor({ ism: "X", ball: 500 }));

server.close();
Natija
[ 201, { yaratildi: { ism: 'Nodira', ball: 91 } } ]
[
  422,
  {
    xato: "tekshiruvdan o'tmadi",
    xatolar: { ism: 'juda qisqa', ball: "0 va 100 orasida butun son bo'lsin" }
  }
]
400 va 422 farqi

Ikkalasi ham "mijoz xatosi", lekin ma'nosi boshqa:

  • 400 Bad Request - so'rovning shakli buzuq. Masalan JSON o'qib bo'lmadi yoki kerakli sarlavha yo'q.
  • 422 Unprocessable Content - shakl to'g'ri, lekin mazmuni qoidalarga mos emas. JSON o'qildi, ammo ball 500 edi.

Amalda ko'p loyihalar faqat 400 ishlatadi va bu ham normal. Muhimi - izchil bo'lish: bitta API ichida bir xil holat uchun bir xil kod qaytarsin.

Eng muhimi - xato qaysi maydonda ekanini ayting. Shunda interfeys uni to'g'ri maydon tagida ko'rsata oladi.

Buzuq JSON #

JavaScript
import express from "express";

const app = express();
app.use(express.json());

app.post("/", (s, j) => j.json({ holat: "qabul qilindi" }));

app.use((xato, sorov, javob, keyingi) => {
    if (xato instanceof SyntaxError && "body" in xato) {
        javob.status(400).json({ xato: "JSON o'qib bo'lmadi" });
        return;
    }
    javob.status(500).json({ xato: "ichki xato" });
});

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

const buzuq = await fetch(`http://localhost:${port}/`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: "{ bu json emas",
});

console.log(buzuq.status, await buzuq.json());

server.close();
Natija
400 { xato: "JSON o'qib bo'lmadi" }

express.json() buzuq JSON uchun SyntaxError tashlaydi. Uni ushlamasangiz, mijoz 500 oladi - go'yo server aybdordek.

Aslida aybdor mijoz, shuning uchun 400 to'g'riroq.

Ruxsat etilgan maydonlar #

JavaScript
function faqatRuxsatEtilgan(malumot, ruxsat) {
    const natija = {};
    for (const kalit of ruxsat) {
        if (kalit in malumot) natija[kalit] = malumot[kalit];
    }
    return natija;
}

const kelgan = {
    ism: "Malika",
    ball: 88,
    rol: "admin",
    id: 999,
};

console.log(faqatRuxsatEtilgan(kelgan, ["ism", "ball"]));
Natija
{ ism: 'Malika', ball: 88 }
Kelgan obyektni to'g'ridan-to'g'ri saqlamang

Bu juda xavfli naqsh:

JavaScript
await baza.yarat(sorov.body);        // hammasi o'tadi

Yuqoridagi misolda mijoz rol: "admin" va id: 999 yuborgan edi. Agar butun obyektni saqlasangiz, foydalanuvchi o'zini admin qilib qo'yishi mumkin.

Bu ommaviy tayinlash (mass assignment) zaifligi deb ataladi va u haqiqiy tizimlarda tez-tez uchraydi.

Himoya: ruxsat etilganlar ro'yxati (allow-list). Qaysi maydon kerak bo'lsa, faqat o'shani oling. "Taqiqlanganlar ro'yxati" esa yomon - yangi maydon qo'shilganda uni unutish oson.

Tozalash #

JavaScript
function tozala(matn) {
    return String(matn ?? "")
        .trim()
        .replace(/\s+/g, " ")
        .slice(0, 100);
}

console.log(`"${tozala("   Malika    Karimova  ")}"`);
console.log(`"${tozala(null)}"`);
console.log(tozala("a".repeat(200)).length);

function emailTogrimi(email) {
    const t = String(email ?? "").trim().toLowerCase();
    return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(t) ? t : null;
}

console.log(emailTogrimi("  [email protected] "));
console.log(emailTogrimi("notogri"));
Natija
"Malika Karimova"
""
100
[email protected]
null
Email uchun murakkab naqsh yozmang

Yuqoridagi naqsh juda oddiy va u ataylab shunday.

To'liq to'g'ri email naqshi yuzlab belgidan iborat bo'ladi va baribir hamma holatni qamrab olmaydi. Undan tashqari, murakkab naqshlar ReDoS hujumiga ochiq bo'lishi mumkin: maxsus tanlangan satr regulyar ifodani soatlab ishlashga majbur qiladi.

Amaliy yondashuv: oddiy tekshiruv qiling (@ va nuqta bor), keyin tasdiqlash xati yuboring. Emailning haqiqiyligini faqat shu usul isbotlaydi.

Amaliy topshiriq
  1. express.urlencoded bilan HTML forma ma'lumotini o'qing.
  2. Formadan kelgan son satr ekanini ko'rsating.
  3. Ism va ballni tekshiradigan funksiya yozing.
  4. Hamma xatoni birdaniga qaytaring.
  5. Xatolarni maydon nomi bilan yuboring.
  6. 422 holat kodini qaytaring.
  7. Buzuq JSON yuborib, 400 ni oling.
  8. Ruxsat etilgan maydonlar ro'yxatini yozing.
  9. rol: "admin" yuborib, u o'tmasligini isbotlang.
  10. Matnni trim va uzunlik bilan tozalang.

Xulosa #

  • JSON uchun express.json(), HTML forma uchun express.urlencoded().
  • Formadan kelgan hamma narsa satr - aylantiring va tekshiring.
  • Tekshiruv uch qadam: tozalash, aylantirish, hamma xatoni yig'ish.
  • Xatoni maydon nomi bilan qaytaring.
  • 400 - so'rov shakli buzuq, 422 - mazmuni qoidaga mos emas; eng muhimi izchillik.
  • Buzuq JSON uchun SyntaxError ni ushlab, 400 qaytaring.
  • Kelgan obyektni to'g'ridan-to'g'ri saqlamang - ruxsat etilgan maydonlar ro'yxatini ishlating.
  • Email uchun murakkab naqsh emas, tasdiqlash xati.

Keyingi bo'limda REST API quramiz.

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.