Amaliy tadqiqot: Soddalashtirilgan tizimga kirish xavfsizligini kuchaytirish

Amaliy tadqiqot: Soddalashtirilgan tizimga kirish xavfsizligini kuchaytirish

-Telefon raqamining oxirgi to‘rtta raqami parolga aylanganda-

1. Orqa fon: Havola orqali kirish qulayligi va uning yashirin xavfi

Men ishlagan loyiha yirik umumiy shifoxona uchun elektron bemor so‘rovnomasi tizimi edi. Bemorlar qabuldan oldin shifoxona tomonidan mobil qurilmalariga yuborilgan so‘rovnomani to‘ldiradi, tibbiyot xodimlari esa konsultatsiya vaqtida natijalardan foydalanadi. Tizim Keycloak asosidagi autentifikatsiya, Java/Spring mikroservislar backend’i va React frontend’idan iborat. Men allaqachon ishlayotgan ushbu tizimga xatolarni tuzatish va ekspluatatsion qo‘llab-quvvatlash uchun qo‘shildim. Ushbu maqola texnik xizmat ko‘rsatish vazifalari davomida duch kelgan muammomdan boshlanadi.

Ushbu tizimga kirishning asosiy yo‘li — "havola orqali kirish". Bemorlar shifoxona tomonidan Alimtalk orqali yuborilgan so‘rovnoma havolasini ochib, ro‘yxatdan o‘tmasdan yoki parol kiritmasdan, faqat telefon raqamining oxirgi to‘rtta raqamini kiritish orqali so‘rovnomani darhol to‘ldirishlari mumkin.

image1.png

1-rasm. Havola orqali kirish jarayoni

Muammo mijoz tomonidan o‘tkazilgan xavfsizlik tekshiruvi vaqtida aniqlandi. Ular quyidagi xavotirni bildirishdi: "Agar havola orqali kirgan foydalanuvchi rasmiy a’zo bo‘lsa, u butun a’zolar bo‘limiga kira olmaydimi?" Muammoni qayta yaratganimizda, bu xavotir o‘rinli ekanligi ma’lum bo‘ldi. Agar havolani oluvchi ID va parol bilan avvaldan ro‘yxatdan o‘tgan a’zo bo‘lsa, Keycloak ushbu a’zo hisobiga token berardi. Ekranlar va API’lar kirish usullarini umuman farqlamagani sababli, faqat telefon raqamining oxirgi to‘rtta raqami bilan autentifikatsiya qilingan sessiya My Page, bildirishnomalar va so‘rovnomalarning to‘liq tarixiga kira olardi. Rasmiy a’zolar uchun oxirgi to‘rtta raqam amalda parolga aylanardi. Bu esa matnli xabarni ko‘ra oladigan uchinchi tomon 10 000 ta mumkin bo‘lgan kombinatsiyadan iborat atigi to‘rt xonali raqam yordamida boshqa shaxsning tibbiyotga oid ma’lumotlariga kira olishini anglatardi. Mijoz muammoni bartaraf etish bo‘yicha rasmiy so‘rov yubordi.

2. Talablarni belgilash: "Havola orqali kirgan foydalanuvchilar mehmonlar bilan bir xil ko‘rilishi kerak"

Eng oddiy yechim rasmiy a’zolar uchun havola orqali kirishni bloklash bo‘lardi, ammo bu xizmatning asosiy qulayligini — "Foydalanuvchilar havolani bosish orqali so‘rovnomani osonlik bilan to‘ldira oladi" — yo‘qqa chiqarardi. Mijoz bilan muhokamalardan so‘ng ushbu foydalanuvchilarni bloklamaslik, balki ularning imtiyozlarini pasaytirishga qaror qildik. Boshqacha aytganda, "Havola orqali kirish sessiyasi, hisob rasmiy a’zoga tegishli bo‘lsa ham, a’zo bo‘lmagan (mehmon) sessiyasi bilan mutlaqo bir xil ko‘rilishi kerak."

  • Havola orqali sessiya sukut bo‘yicha faqat ayni safar yuborilgan so‘rovnoma ekranini taqdim etadi.

  • Avvalgi so‘rovnomalar tarixini faqat foydalanuvchining ismi va tug‘ilgan sanasini talab qiladigan [Avvalgi yozuvlarni ko‘rish] tugmasi orqali shaxsni tasdiqlashdan o‘tgandan keyin ko‘rish mumkin.

  • My Page va bildirishnomalar kabi faqat a’zolar uchun mo‘ljallangan menyular ko‘rsatilmaydi. (Kiosk yo‘li bundan mustasno.)

Talablar shu tarzda tartibga solingach, texnik muammo bitta savolga qisqardi: tizim "ushbu sessiya qanday kirganini" ishonchli tarzda aniqlay olishini qanday ta’minlash mumkin?

3. Texnik tanlov: Kirish usuli qayerda qayd etilishi kerak?

Kirish usuli haqidagi ma’lumotlarni qayerda saqlash va ularni qanday uzatish bo‘yicha uchta yondashuvni ko‘rib chiqdik.

  • ① Frontend holati (sessionStorage va boshqalar): Uni joriy etish oson, ammo developer tools orqali o‘zgartirish mumkinligi sababli xavfsizlikka oid qarorlar uchun asos sifatida ishonchli emas.

  • ② Server sessiyasi: U JWT asosidagi stateless arxitekturaga mos kelmaydi va bog‘liqlikni yuzaga keltiradi, chunki bir nechta mikroservisning har biri sessiyalar omboriga murojaat qilishi kerak bo‘ladi.

  • ③ Token claim’i: Bu yondashuv kirish usulini identifikatsiya provayderi bo‘lgan Keycloak tomonidan imzolangan token ichiga joylashtiradi. Uni o‘zgartirib bo‘lmaydi, frontend va backend esa qo‘shimcha qidiruvlarsiz uni aniqlashi mumkin.

③-variantni tanladik. Biz nafaqat "kim kirgani", balki "qanday kirgani" ham identifikatsiya provayderi kafolatlashi kerak bo‘lgan ma’lumot ekanini belgiladik. Dastlab undan faqat ekranlarni cheklash uchun foydalansak-da, keyinchalik yondashuvni backend API’larini bloklashgacha kengaytirsak, undan o‘zgartirishsiz qayta foydalanish mumkin bo‘ladi.

3-1. Keycloak’da joriy etish: User Session Note va Mapper

Ushbu tizimda havola orqali kirish uchun Keycloak SPI orqali maxsus Authenticator allaqachon ishlayotgan edi. Kirish oqimi login formasi parametrlari asosida havola, kiosk yoki standart ID/parol orqali kirishga ajralgani sababli, havola orqali kirish muvaffaqiyatli yakunlangandagina User Session Note’ni qayd etadigan kod qo‘shdik.

// LoginAuthenticator.java
if (formData.containsKey(FIELD_PHONE_LAST_4)) {
    // [CASE 1] 링크(전화번호 뒤 4자리) 로그인
    user = handlePhoneLogin(context, formData);
    if (user != null) {
        // User Session Note mapper를 통해 토큰 claim으로 발급된다
        context.getAuthenticationSession()
            .setUserSessionNote("login_method", "link");
    }
} else {
    // 키오스크 / 일반 ID/PW 로그인 — note를 기록하지 않는다
    ...
}

User Session Note faqat Keycloak sessiyasi ichida mavjud bo‘ladi, shuning uchun uni token claim’i sifatida ochish uchun mijozning maxsus scope’iga protocol mapper ro‘yxatdan o‘tkazilishi kerak.

# Keycloak 관리 콘솔 — 클라이언트 dedicated scope > Add mapper (By configuration)
Mapper type          : User Session Note
User Session Note    : login_method
Token Claim Name     : login_method
Claim JSON Type      : String
Add to ID token      : On
Add to access token  : On

O‘zgartirishni qo‘llagandan so‘ng ikki kirish usuliga tegishli tokenlarni taqqoslaganimizda, claim faqat havola orqali kirish tokenida mavjudligi, ID/parol tokenida esa umuman yo‘qligi ko‘rindi.

// 링크 로그인 토큰 payload (일부)
{
  "preferred_username": "u-93f2...",
  "login_method": "link",   // <- mapper가 발급한 claim
  ...
}

// ID/PW 로그인 토큰 payload (일부) - login_method claim 자체가 없다
{
  "preferred_username": "u-93f2...",
  ...
}

Bu ataylab ishlab chiqilgan xavfsiz holatga qaytish dizaynidir. Aniqlash mantiqi kirishni "faqat claim qiymati link bo‘lganda" cheklaydi. Shu sababli aniqlash kodida xato yuz bersa yoki tokenni tahlil qilish muvaffaqiyatsiz tugasa ham, natija har doim "cheklamaslik" sifatida cheklovni qo‘llamasdan davom etadi. Shunday qilib, rasmiy a’zolar uchun mavjud oqimga ta’sir qilinmaydi.

4. Frontend ilovasi: Bitta aniqlash utilitasi, oltita nazorat nuqtasi

Frontend’da claim’ni o‘qish uchun yagona funksiyani umumiy kutubxonaga joylashtirdik va ekranlardagi nazorat nuqtalarini unga murojaat qiladigan qildik.

/** 링크 로그인 세션 여부 — ID/PW 토큰에는 claim 자체가 없다 */
export const isLinkLoginSession = (): boolean => {
  const token = getAccessToken();
  if (!token) return false;
  try {
    return JSON.parse(atob(token.split('.')[1]))?.login_method === 'link';
  } catch {
    return false;   // 파싱 실패 시에도 "제한하지 않음" (fail-safe)
  }
};

Mavjud ekranlar mehmon rejimini foydalanuvchi a’zo bo‘lmaganiga (isGuest) qarab boshqarardi. Shu sababli havola sessiyalarini qo‘shib, avtorizatsiyani tekshiruvchi hook ichiga birlashtirilgan isRestricted tushunchasini kiritdik. Endi ekranlar faqat shu qiymatni tekshirishi kerak.

const isGuest = user?.isGuest ?? false;
const isLinkSession = isLinkLoginSession();
const isRestricted = isGuest || isLinkSession;  // 제한 세션

Ushbu mezonni oltita nazorat nuqtasiga qo‘lladik: marshrutlash layout’i, menyu hook’i, dastlabki kirish sahifasi, bemor dashboard’i, umumiy header va so‘rovnomalar ro‘yxati. Cheklangan sessiyalarda faqat yuborilgan so‘rovnoma va [Avvalgi yozuvlarni ko‘rish] qoladi. Shaxsni tasdiqlash yakunlangach, foydalanuvchilar bosh sahifa, so‘rovnoma bo‘limi yoki tafsilotlar sahifasidan chiqish orqali bir xil tarzda avvalgi tarix sahifasiga yo‘naltiriladigan oqimni standartlashtirdik. Mobil pastki navigatsiya faqat shaxsni tasdiqlash yakunlangandan keyin ko‘rsatiladi.

5. API qatlami: Ochiqlik va himoya o‘rtasidagi muvozanat

Ekranlarni mehmon darajasidagi kirish bilan moslashtirish qarama-qarshi yo‘nalishda muammo tug‘dirdi. Mehmon ekranlari chaqiradigan uchta API — shaxsni tasdiqlash, mehmon so‘rovnomalari ro‘yxati va mehmonlar tarixini qidirish — ROLE_GUEST bilan cheklangan edi. Shuning uchun ularni ROLE_USER tokenlariga ega havola sessiyasi a’zolari uchun ham ochish kerak bo‘ldi. Ushbu o‘zgarish ruxsatlarni kengaytirgani sababli uning xavfsizligini alohida tekshirdik. Uchala API ham maqsadli bemorni mijoz kiritgan ma’lumotdan emas, token’dagi autentifikatsiya qilingan subject’dan oladi va faqat Redis’da qayd etilgan shaxsni tasdiqlashdan o‘tilgani bayrog‘ini (TTL: 30 minutes) qayta tekshirgandan keyin ma’lumot qaytaradi. Natijada boshqa shaxs ma’lumotlariga olib boradigan yo‘l yaratilmadi.

Aksincha, "sessiya havola sessiyasi bo‘lganda a’zolar uchun mo‘ljallangan API’larni backend’da bloklash"ni joriy qamrovdan chiqarishga qaror qildik. Bu sohalar ilgari faqat ekran darajasida cheklangan, a’zolarga xos API’lar esa o‘z himoya mexanizmlariga ega edi, shuning uchun haqiqiy xavf past bo‘lgan. Biroq claim Access Token tarkibiga kiritilgani sababli tizimni keyinchalik kengaytirish uchun asos yaratildi: zarur bo‘lsa, backend avtorizatsiya mantiqi claim’ni o‘qib, kirishni bloklashi mumkin.

image2.png

2-rasm. Umumiy arxitektura — kirish usuli claim’ining tarqalishi va aniqlash nuqtalari

6. Ishlab chiqarishga joriy etishdan olingan saboqlar: Jim ishlamay qoladigan konfiguratsiya

Eng katta saboq koddan emas, balki joriy etish jarayonidan olindi. Authenticator (SPI) kod bo‘lgani uchun deployment pipeline orqali o‘tadi, mapper esa Keycloak realm’ida joylashgan "konfiguratsiya" bo‘lib, har bir muhit uchun ma’muriy konsol orqali qo‘lda ro‘yxatdan o‘tkazilishi kerak. Muammo shundaki, bu konfiguratsiya mavjud bo‘lmaganda hech narsa noto‘g‘ri ishlayotgandek ko‘rinmaydi. Claim shunchaki berilmaydi va aniqlash funksiyasi xavfsiz holatga qaytadigan qilib ishlab chiqilgani sababli jimgina false qiymatini qaytaradi. Natijada ekran cheklovlari yo‘qoladi, ammo hammasi odatdagidek ko‘rinadi. Bunday "jim ishlamay qolish" holatini foydalanuvchi murojaatlari orqali aniqlash ehtimoli ham juda past.

Shu sababli deployment checklist’iga quyidagi bandlarni aniq qo‘shdik.

  • Ishlab chiqarishga joriy etishda Keycloak konsolida User Session Note mapper’ini qo‘lda ro‘yxatdan o‘tkazish (DEV/STG bilan bir xil konfiguratsiya bilan)

  • Joriy etishdan so‘ng darhol havola orqali kirish tokenlarida login_method claim’i mavjudligini, ID/parol tokenlarida esa mavjud emasligini o‘zaro tekshirish

  • Yakuniy ekran darajasidagi tekshiruvni o‘tkazish: havola sessiyalarida faqat a’zolar uchun mo‘ljallangan menyular ko‘rsatilmasligi kerak

Shundan beri kodni joriy etishning o‘zi bilan yakunlab bo‘lmaydigan har qanday o‘zgarishlarni — ayniqsa xatosiz, jim ishlamay qoladigan konfiguratsiyalarni — joriy etishdan so‘ng darhol bajariladigan faol tekshiruv tartiblari bilan birga checklist bandlari sifatida boshqarib kelmoqdamiz.

7. Xulosa

Xatolarni tuzatish bo‘yicha qo‘llab-quvvatlash sifatida boshlangan ish oxir-oqibat autentifikatsiya arxitekturasini yaxshilashga aylandi. Biz havola orqali kirish qulayligini saqlab qolgan holda, telefon raqamining oxirgi to‘rtta raqamidan foydalanib shaxsiy ma’lumotlar ekranlariga kirish imkonini bergan zaiflikni bartaraf etdik. Ushbu jarayonda orttirilgan nuqtayi nazar boshqa loyihalarga ham tatbiq etilishi mumkin, deb hisoblayman.

  • Autentifikatsiya "usuli" ham identifikatsiya provayderi kafolatlashi kerak bo‘lgan ma’lumotdir. Kirish usulini imzolangan token claim’iga joylashtirish namunasi soddalashtirilgan autentifikatsiya va ijtimoiy tarmoqlar orqali kirish kabi bir nechta autentifikatsiya yo‘llariga ega har qanday tizimda qo‘llanilishi mumkin.

  • Xatoning qanday yo‘nalishda yuz berishi avvaldan loyihalashtirilishi kerak. Kirishni "faqat claim mavjud bo‘lganda" cheklaydigan tuzilma tufayli hech qanday xato mavjud foydalanuvchilar faoliyatini buzadigan tarzda tarqalmadi.

  • Koddan tashqaridagi konfiguratsiyalar checklist’lar yordamida boshqarilishi kerak. O‘tkazib yuborilganda xato bermasdan jimgina o‘chiriladigan konfiguratsiyalar har doim joriy etishdan so‘ng darhol bajariladigan tekshiruv tartibi bilan birga hujjatlashtirilishi kerak.

eunice

Site footer