Asosiy matnga o'tish
Blog

Veb

To'lov tasdiqlanmasdan "muvaffaqiyatli" sahifasi: biznes-mantiq zaifligi

Foydalanuvchi to'lov provayderidan qaytishi bilan "to'lov muvaffaqiyatli" ko'rsatish xato. Holatni faqat provayder callback'i tasdiqlaydi.

· 7 daq. o'qish

Foto: Shixart1985, CC BY 2.0 · Wikimedia Commons

Ko'pchilik veb-xavfsizlik deganda SQL injection yoki XSS'ni tasavvur qiladi. Lekin ekspertiza hisobotlarida tez-tez uchraydigan yana bir toifa bor: biznes-mantiq zaifliklari. Bunday xatolarni avtomatik skanerlar deyarli topmaydi, chunki kod texnik jihatdan "to'g'ri" ishlaydi. Muammo mantiqda: tizim nimaga ishonishi kerak emasligiga ishonadi.

Eng aniq misollardan biri — to'lov oqimi. Bu maqolada o'z mahsulotimiz (soliq-moliya SaaS platformasi) ekspertizasida topilgan holatni va uni qanday yopganimizni ko'rib chiqamiz.

Muammo qanday ko'rinadi

Odatiy to'lov oqimi quyidagicha:

  1. Foydalanuvchi tarifni tanlaydi va "To'lash" tugmasini bosadi.
  2. Sayt to'lov provayderi sahifasiga yo'naltiradi.
  3. Foydalanuvchi karta ma'lumotlarini kiritadi.
  4. Provayder foydalanuvchini saytga qaytaradi (return URL).
  5. Provayder alohida server-server so'rovi bilan (callback yoki webhook) to'lov natijasini xabar qiladi.

Xato 4-qadamda yuz beradi. Ko'p loyihalarda return URL — masalan /payment/success?order=123 — ochilishi bilan sahifa "To'lov muvaffaqiyatli o'tdi" deb ko'rsatadi, ba'zan esa obunani ham faollashtiradi. Ammo bu manzilga foydalanuvchi to'lovni tugatmasdan ham kirishi mumkin: brauzerning manzil satriga qo'lda yozish, sahifani qayta yuklash yoki provayder sahifasidan "orqaga" qaytish yetarli.

Bizning holatda ekspertlar aynan shuni ko'rsatdi: muvaffaqiyat sahifasi provayder to'lovni haqiqatan tasdiqlashidan oldin ko'rinardi. Pul yechilmagan bo'lsa ham, foydalanuvchi interfeysda "to'landi" degan xabarni ko'rardi.

Nega bu jiddiy

  • Moliyaviy zarar. Agar muvaffaqiyat sahifasi xizmatni ham yoqsa, foydalanuvchi pul to'lamasdan pullik funksiyalarga ega bo'ladi.
  • Noto'g'ri hisobot. Buxgalteriya va admin panelda "to'langan" deb ko'ringan, aslida to'lanmagan buyurtmalar paydo bo'ladi.
  • Ishonch masalasi. Foydalanuvchi "to'landi" xabarini ko'radi, keyin xizmat o'chib qoladi — bu qo'llab-quvvatlash xizmatiga ortiqcha murojaatlar degani.

OWASP bu turdagi xatolarni Top 10 (2021) ro'yxatida A04 "Insecure Design" toifasiga kiritadi. CWE'da yaqin tavsif — CWE-840 (Business Logic Errors).

Asosiy qoida: foydalanuvchi brauzeri orqali kelgan har qanday ma'lumot — tasdiq emas, faqat ishora. To'lov holatini faqat provayderning imzolangan server-server xabari o'zgartiradi.

To'g'ri arxitektura

1. Buyurtma holatlari aniq bo'lsin

Har bir to'lov uchun alohida yozuv yarating va uning holatini aniq belgilang: pending, paid, failed, expired. Yangi buyurtma doim pending holatida yaratiladi.

2. Holatni faqat callback o'zgartiradi

Provayder callback'i kelganda:

  • imzo yoki maxfiy kalitni tekshiring (har bir provayderning o'z mexanizmi bor);
  • summa va valyuta buyurtmadagi bilan mos kelishini tekshiring;
  • buyurtma allaqachon paid bo'lsa, qayta ishlamang (idempotentlik);
  • faqat shundan keyin holatni paid ga o'tkazing va xizmatni faollashtiring.

Laravel'dagi soddalashtirilgan misol:

public function callback(Request $request)
{
    abort_unless($this->provider->verifySignature($request), 403);

    $payment = Payment::where('external_id', $request->input('transaction_id'))
        ->lockForUpdate()->firstOrFail();

    if ($payment->status === 'paid') {
        return response()->json(['ok' => true]); // takroriy callback
    }

    abort_unless((int) $request->input('amount') === $payment->amount, 422);

    DB::transaction(function () use ($payment) {
        $payment->update(['status' => 'paid', 'paid_at' => now()]);
        $payment->subscription->activate();
    });

    return response()->json(['ok' => true]);
}

3. Return sahifasi faqat holatni ko'rsatadi

Foydalanuvchi qaytganda sahifa hech narsani o'zgartirmaydi. U bazadagi holatni o'qiydi va unga mos xabar beradi:

  • paid — "To'lov tasdiqlandi";
  • pending — "To'lov tekshirilmoqda" va bir necha soniyada holatni qayta so'raydigan kichik so'rov;
  • failed yoki expired — "To'lov amalga oshmadi" va qayta urinish tugmasi.

Bundan tashqari, return sahifasi faqat shu buyurtma egasiga ochilishi kerak. Aks holda ?order=124 deb boshqa birovning buyurtmasini ko'rish mumkin bo'ladi — bu esa alohida zaiflik (IDOR).

4. Eskirgan pending to'lovlarni tozalang

Callback umuman kelmasligi ham mumkin: foydalanuvchi provayder sahifasini yopib qo'ygan yoki tarmoq uzilgan. Shunday yozuvlar abadiy pending bo'lib qolmasligi kerak. Biz rejalashtirilgan vazifa qo'shdik: ma'lum vaqtdan keyin ham tasdiqlanmagan to'lovlar expired ga o'tkaziladi, kerak bo'lsa provayder API'si orqali yakuniy holati so'raladi.

// routes/console.php
Schedule::call(function () {
    Payment::where('status', 'pending')
        ->where('created_at', '<', now()->subHours(2))
        ->update(['status' => 'expired']);
})->hourly();

Vaqt oralig'ini provayderingiz shartlariga qarab tanlang.

Tekshirish ro'yxati

O'z loyihangizda quyidagilarni tekshirib ko'ring:

  • Return URL'ni qo'lda ochganda xizmat faollashadimi yoki "to'landi" deyiladimi?
  • Callback imzosi tekshiriladimi? Imzosiz so'rov yuborib ko'ring — u rad etilishi kerak.
  • Callback'dagi summa buyurtma summasi bilan solishtiriladimi?
  • Bir xil callback ikki marta kelsa, obuna ikki marta uzaytiriladimi?
  • Eski pending yozuvlar qancha va ularni kim tozalaydi?
  • Return sahifasi boshqa foydalanuvchining buyurtmasini ko'rsatadimi?

Boshqa biznes-mantiq xatolari

To'lov — eng ko'p uchraydigan, lekin yagona misol emas. Ekspertiza hisobotimizda yana bir biznes-mantiq topilmasi bor edi: ayrim amallar obyektning joriy holati tekshirilmasdan bajarilishi mumkin edi. Masalan, allaqachon yopilgan yozuvni tahrirlash yoki tasdiqlash bosqichini chetlab o'tish. Yechim bir xil: har bir amaldan oldin server tomonda "bu holatda bu amal ruxsat etilganmi?" degan savolga javob beradigan tekshiruv bo'lishi kerak. Interfeysdagi yashirilgan tugma himoya emas.

Xulosa

Biznes-mantiq zaifliklari kodni o'qish va jarayonni oxirigacha tushunishni talab qiladi. Shuning uchun biz bunday holatlarni avtomatik skaner bilan emas, Claude AI agenti va mutaxassis birgalikda har bir oqimni birma-bir ko'rib chiqish orqali qidiramiz: agent to'lov, ro'yxatdan o'tish va holat o'zgarishi bilan bog'liq kodni tez tahlil qiladi, mutaxassis esa har bir topilmani amalda tekshiradi va tuzatadi.

Loyihangizni rasmiy ekspertizaga tayyorlamoqchi bo'lsangiz, skanerlash uchun ariza qoldiring. Biz to'lov va boshqa muhim oqimlardagi teshiklarni topib, ekspertizadan oldin yopishga yordam beramiz.