JavaRush /Kurslar /All lectures for UZ purposes /Authentication Bo'yicha Umumiy Ma'lumot

Authentication Bo'yicha Umumiy Ma'lumot

All lectures for UZ purposes
Daraja, Dars
Mavjud

Spring Security dan PasswordEncoder interfeysi parolni bir tomonlama o'zgartirish uchun ishlatiladi, shunda uni xavfsiz saqlash mumkin bo'ladi. PasswordEncoder bir tomonlama o'zgartirishni taklif qiladi, shuning uchun u parolni ikki tomonlama o'zgartirish kerak bo'lganda (masalan, ma'lumotlar bazasida autentifikatsiya uchun ishlatiladigan hisob ma'lumotlarini saqlashda) mo'ljallangan emas. Odatda, PasswordEncoder parolni saqlash uchun ishlatiladi, u foydalanuvchining autentifikatsiya paytida kiritgan paroli bilan solishtiriladi.

Saqlangan Parollar Tarixi

Yillar mobaynida parollarni saqlash standart mexanizmi rivojlandi. Dastlab parollar oddiy matn sifatida saqlanardi. Parollar xavfsiz hisoblanardi, chunki parollar saqlanadigan ma'lumotlar bazasiga kirish uchun hisob ma'lumotlari talab qilinadi deb o'ylashardi. Ammo xakerlar SQL-kodning kiritilishi (SQL Injection) orqali foydalanuvchilar nomlari va parolining katta "dump"larini olish yo‘llarini topishdi. Foydalanuvchi hisob ma'lumotlari ommaga tarqalayotganini ko'rib turib, xavfsizlik mutaxassislari foydalanuvchi parollarini himoyasini kuchaytirishni talab qilayotganini tushunishdi.

Dasturchilarga parollarni bir tomonlama hash algoritim, masalan SHA-256 orqali saqlash tavsiya qilindi. Foydalanuvchi autentifikatsiyadan o'tishni sinab ko'rganida, hashlangan parol foydalanuvchining kiritgan parolining hashiga solishtirilardi. Bu demak edi ki, tizim faqat parolning bir tomonlama hashini saqlashi kerak edi. Xakerlik holatida, faqat parol hashlarining bir tomonlama variantlari ochiq qolinardi. Hashlar bir tomonlama bo'lgani uchun va hash orqali parolni bir ko'rsatkichdan tan olish qiyin bo'lgani uchun tizimdagi har bir parolni tanlashga harakat qilishga mantiq yo'q edi. Ushbu yangi tizimni buzish uchun xakerlar qidirish jadvallarini yaratishga qaror qilishdi, ular rainbow table deb nomlanadi. Har bir parolni tahmin qilish o'rniga, ular parolni bir marta hisoblaydilar va uni qidiruv jadvalida saqlashadi.

Rainbow tablelarning samaradorligini kamaytirish uchun dasturchilarga "sertlangan" parollar ishlatish tavsiya qilindi. Parolni hash funktsiyasiga kirish ma'lumotlari sifatida ishlatilishiga qo'shimcha ravishda, har bir foydalanuvchining paroli uchun tasodifiy baytlar (sert deb tanilgan) generatsiya qilindi. Sert va foydalanuvchi paroli hash funktsiyasidan o'tkazilib, natijada noyob hash hosil bo'ladi. Sert foydalanuvchi parolining yonida ochiq matn sifatida saqlanadi. Keyin, agar foydalanuvchi autentifikatsiyaga harakat qilsa, hashlangan parol taqqoslanadi va foydalanuvchiga kiritilgan sertni va parolni hash bilan taqqoslanadi. Sertning noyobligi shuni anglatadiki, rainbow tablelar samaradorligini yo'qotadi, chunki hash har bir sert va parol kombinatsiyasi uchun har xil bo'ladi.

Hozirgi kunda biz kriptografik hashlar, masalan SHA-256 algoritmi, endi xavfsiz emasligini tushunamiz. Sababi shundaki, zamonaviy uskunalar yordamida soniyada milliardlab hash hisob-kitoblarini amalga oshirish mumkin. Bu har bir parolni alohida-alohida buzishni osonlashtiradi.

Dasturchilarga endi parollarni saqlash uchun adaptiv hisoblash-loyiha bo'lmagan funktsiyalarni ishlatish tavsiya qilinmoqda. Parollarni adaptiv hisoblash-loyiha bo'lmagan funktsiyalar yordamida validatsiya qilish resurslar (masalan, protsessor, xotira va hokazo) talab qiladi. Adaptiv hisoblash-loyiha bo'lmagan funktsiya vaqt o'tishi bilan apparat takomillashadigan bo'lgani uchun "mehnattalablik va xarajatlar omili"ni sozlash imkonini beradi. Parolingizni tekshirish taxminan bir soniya davom etishi uchun "mehnattalablik va xarajatlar omili"ni sozlash tavsiya etiladi. Bu muvozanat shuni anglatadiki, xakerlar parolni buzish qiyinroq bo'lgani holda, tizimingizga resurs talab qilish jihatidan katta bosim qilmaslik tavsiya etiladi. Spring Securityda "mehnattalablik va xarajatlar omili"ni adolatli boshlang'ich nuqtasini olishga urinish mavjud, ammo foydalanuvchilarga o'z tizimlariga moslashtirish tavsiya etiladi, chunki tezlik tizimdan tizimga keskin o'zgaradi. Adaptiv hisoblash-loyiha bo'lmagan funktsiyalarning namunalariga bcrypt, PBKDF2, scrypt va argon2 kiradi.

Adaptiv hisoblash-loyiha bo'lmagan funktsiyalar o'zlari katta hisoblash resurslari talab qiladiganligi sababli, har bir so'rov uchun foydalanuvchi nomi va parolni validatsiya qilish ilovaning samaradorligini sezilarli darajada pasaytiradi. Spring Security (yoki boshqa kutubxona) parolni tezlatishni hech qanday tarzda ta'sir qila olmaydi, chunki tegishli xavfsizlik darajasi erishish uchun validatsiya hisoblash resurslarini talab qiladi. Foydalanuvchilarga uzoq muddatli hisob ma'lumotlarini (masalan, foydalanuvchi nomi va parol) qisqa muddatli (masalan, sessiya, OAuth tokeni va hokazo) almashish tavsiya etiladi. Qisqa muddatli hisob ma'lumotlarini tezda xavfsizlikdan mahrum qilmaslik sharti bilan validatsiya qilish mumkin.

DelegatingPasswordEncoder

Spring Security 5.0 versiyasiga qadar NoOpPasswordEncoder dan foydalanilgan, bu esa oddiy matn shaklidagi parollarni talab qildi. "Parol tarixi" bo'limidan kelib chiqqan holda, BCryptPasswordEncoder kabi narsa default bo'lib ishlatiladi deb kutish mumkin edi. Ammo bu uchta muammoni inobatga olmaydi:

  • Eski parol kodlarini ishlatadigan ko'plab dasturning mavjudligi, ularni migratsiya qilish qiyin

  • Parollarni saqlashning eng yaxshi usuli yana o'zgaradi

  • Spring Security framework bo'lib, tez-tez kritikal o'zgarishlar kiritolmaydi

Buning o'rniga, Spring Security barcha ushbu muammolarni hal qilish uchun DelegatingPasswordEncoder ni taqdim etadi:

  • Parollarni saqlashning hozirgi tavsiyalari asosida kodlashni ta'minlash

  • Ruxsat etilgan va eski formatlarda parollarni validatsiya qilish imkoniyati

  • Kelajakda kodlash yangiliklarini ishlab chiqarish imkoniyati

PasswordEncoderFactories dan foydalanib, DelegatingPasswordEncoder ni osongina yaratishingiz mumkin.

DelegatingPasswordEncoder ni Default yaratish
Java
PasswordEncoder passwordEncoder =
    PasswordEncoderFactories.createDelegatingPasswordEncoder();
Kotlin
val passwordEncoder: PasswordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder()

Bundan tashqari, siz o'zingizning custom instansiyani yaratishingiz mumkin. Masalan:

Custom DelegatingPasswordEncoder Yaratish
Java
String idForEncode = "bcrypt";
Map encoders = new HashMap<>();
encoders.put(idForEncode, new BCryptPasswordEncoder());
encoders.put("noop", NoOpPasswordEncoder.getInstance());
encoders.put("pbkdf2", new Pbkdf2PasswordEncoder());
encoders.put("scrypt", new SCryptPasswordEncoder());
encoders.put("sha256", new StandardPasswordEncoder());
PasswordEncoder passwordEncoder =
    new DelegatingPasswordEncoder(idForEncode, encoders);
Kotlin
val idForEncode = "bcrypt"
val encoders: MutableMap<String, PasswordEncoder> = mutableMapOf()
encoders[idForEncode] = BCryptPasswordEncoder()
encoders["noop"] = NoOpPasswordEncoder.getInstance()
encoders["pbkdf2"] = Pbkdf2PasswordEncoder()
encoders["scrypt"] = SCryptPasswordEncoder()
encoders["sha256"] = StandardPasswordEncoder()
val passwordEncoder: PasswordEncoder = DelegatingPasswordEncoder(idForEncode, encoders)

Parollarni saqlash formati

Parollarning umumiy formati quyidagicha:

DelegatingPasswordEncoder Saqlash Formati
{id}encodedPassword

Masalan, id - foydalanishga yaroqli PasswordEncoderni topish uchun ishlatiladigan identifikatsiya, encodedPassword esa tanlangan PasswordEncoder uchun o'ziga xos kodlangan parol. id parolning boshida joylashgan bo'lishi kerak, { bilan boshlanishi va } bilan tugashi kerak. Agar id topilmasa, id null qiymatiga ega bo'ladi. Masalan, quyida har xil idlardan foydalangan holda kodlangan parollar ro'yxati misoli keltirilgan. Barcha asl parollar "password".

DelegatingPasswordEncoder Yordamida Kodlangan Parollar Namunalari
{bcrypt}$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG 
{noop}password 
{pbkdf2}5d923b44a6d129f3ddf3e3c8d29412723dcbde72445e8ef6bf3b508fbf17fa4ed4d6b99ca763d8dc 
{scrypt}$e0801$8bWJaSu2IKSn9Z9kM+TPXfOc/9bdYSrN1oD9qfVThWEwdRTnO7re7Ei+fUZRJ68k9lTyuTeUp4of4g24hHnazw==$OAOec05+bXxvuu/1qZ6NUR+xQYvYv7BeL1QxwRpY5Pc=  
{sha256}97cde38028ad898ebc02e690819fa220e88c62e0699403e94fff291cfffaf8410849f27605abcbc0 
  1. Birinchi parol uchun PasswordEncoderning identifikatori bcrypt bo'ladi va kodlangan parol $2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG sifatida ko'rsatiladi. Mos kelganidan so'ng, BCryptPasswordEncoder ga o'tkaziladi
  2. Ikkinchi parol uchun PasswordEncoderning identifikatori noop bo'ladi, kodlangan parol esa password shaklida bo'ladi. Mos kelganidan so'ng, NoOpPasswordEncoderga o'tkaziladi
  3. Uchinchi parol uchun PasswordEncoderning identifikatori pbkdf2 bo'ladi va kodlangan parol 5d923b44a6d129f3ddf3e3c8d29412723dcbde72445e8ef6bf3b508fbf17fa4ed4d6b99ca763d8dc shaklida bo'ladi. Mos kelganidan so'ng, Pbkdf2PasswordEncoderga o'tkaziladi
  4. To'rtinchi parol uchun PasswordEncoderning identifikatori scrypt bo'ladi va kodlangan parol $e0801$8bWJaSu2IKSn9Z9kM+TPXfOc/9bdYSrN1oD9qfVThWEwdRTnO7re7Ei+fUZRJ68k9lTyuTeUp4of4g24hHnazw==$OAOec05+bXxvuu/1qZ6NUR+xQYvYv7BeL1QxwRpY5Pc= shaklida bo'ladi. Mos kelganidan so'ng, SCryptPasswordEncoderga o'tkaziladi
  5. Yakuniy parol uchun PasswordEncoderning identifikatori sha256 bo'ladi va kodlangan parol 97cde38028ad898ebc02e690819fa220e88c62e0699403e94fff291cfffaf8410849f27605abcbc0 shaklida bo'ladi. Mos kelganidan so'ng, StandardPasswordEncoderga o'tkaziladi

Ba'zi foydalanuvchilar saqlash formatining potentsial xaker uchun ochiq ekanidan xavotirlanishi mumkin. Bu haqida xavotirlanmaslik lozim, chunki parolni saqlash algoritmning yopiq yoki ochiq ekanligiga bog'liq emas. Bundan tashqari, ko'pchilik formatlar xakerlar tomonidan prifixlarsiz ham osongina aniqlanishi mumkin. Masalan, BCrypt parollari ko'pincha $2a$ bilan boshlanadi.

Parolni kodlash

Konstruktoriga yuborilgan idForEncode parollarni kodlashda ishlatiladigan PasswordEncoderni belgilaydi. Yuqorida yaratgan DelegatingPasswordEncoderni hisobga olsak, bu password ni kodlash natijasi BCryptPasswordEncoder ga topshirilishini va {bcrypt} prifix bilan belgilanishini anglatadi. Yakuniy natija quyidagi ko'rinishda bo'ladi:

DelegatingPasswordEncoder Yordamida Kodlash Namunasi
{bcrypt}$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG

Parolni o'zgartirish

Parolni o'zgartirish {id} va konstruktorida kiritilgan PasswordEncoderga id ni o'zlashtirish asosida amalga oshiriladi. Oddiy holda, parol va ko'rsatilmagan id bilan matches(CharSequence, String) chaqiruv natijasi (null qiymatga ega bo'lgan identifikatorni o'z ichiga olgan holda) IllegalArgumentException komandasini keltirib chiqaradi. Ushbu ish amaliyotini DelegatingPasswordEncoder.setDefaultPasswordEncoderForMatches(PasswordEncoder) yordamida sozlash mumkin.

id ni ishlatish orqali har qanday kodlashni o'zgartirish mumkin, ammo kodlash parollarni kodlashda eng zamonaviy kodlashdan foydalanishga ruxsat beradi. Bu juda muhim, chunki shifrlashga nisbatan, parol hashlarining tashkil etilmasliklari juda qiyin bo'ladi. Matnni oddiy qayta tiklash imkoniyati yo'qligi sababli, bu parollarni o'rnini almashtirishni qiyinlashtiradi. NoOpPasswordEncoderni osongina o'tkazish mumkin bo'lgan holda, foydalanuvchilar boshlang'ich punkt sifatida, ularni ishlatishni boshlash osonroq bo'ladi.

Ish boshlash

Agar siz demo-versiyangizni yoki namuna tayyorlayotgan bo'lsangiz, foydalanuvchi parollarini hash qilishga vaqt sarflash biroz noqulay bo'ladi. Ushbu jarayonni osonlashtiruvchi yordamchi mexanizmlar mavjud, ammo ular hali ham ishlab chiqarish o'rnatishlar uchun mo'ljallanmagan.

withDefaultPasswordEncoder Namuna
Java
User user = User.withDefaultPasswordEncoder()
  .username("user")
  .password("password")
  .roles("user")
  .build();
System.out.println(user.getPassword());
// {bcrypt}$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG
Kotlin
val user = User.withDefaultPasswordEncoder()
    .username("user")
    .password("password")
    .roles("user")
    .build()
println(user.password)
// {bcrypt}$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG

Agar siz bir nechta foydalanuvchilar yaratishni xohlasangiz, konstruktorni qayta ishlatishingiz mumkin.

Konstruktorni Qayta Ishlatish Uchun withDefaultPasswordEncoder
Java
UserBuilder users = User.withDefaultPasswordEncoder();
User user = users
  .username("user")
  .password("password")
  .roles("USER")
  .build();
User admin = users
  .username("admin")
  .password("password")
  .roles("USER","ADMIN")
  .build();
Kotlin
val users = User.withDefaultPasswordEncoder()
val user = users
    .username("user")
    .password("password")
    .roles("USER")
    .build()
val admin = users
    .username("admin")
    .password("password")
    .roles("USER", "ADMIN")
    .build()

Bu saqlangan parolni hash qilish imkonini beradi, ammo parollar xotirada ochiq holda qoladi va kompilyatsiyalangan manba kodida ko'rinadi. Shuning uchun bu usul hali ham ishlab chiqarish muhitida xavfsiz deb hisoblanmaydi. Ishlab chiqarish o'rnatishda parollarni tashqi muhitda hash qilish kerak.

Spring Boot CLI yordamida Kodlash

Parolni to'g'ri kodlashning eng oson yo'li – foydalanish Spring Boot CLI.

Masalan, quyidagi buyruq password parolini DelegatingPasswordEncoder bilan ishlatish uchun kodlaydi:

Spring Boot CLI Orqali Encodepassword Namuna
spring encodepassword password
{bcrypt}$2a$10$X5wFBtLrL/kHcmrOGGTrGufsBX8CJ0WpQpF3pgeuxBB/H73BK1DW6

Nosozliklarni Bartaraf Etish

Keyingi xato saqlangan parollardan birida identifikator yo'q bo'lsa yuzaga keladi.

java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"
	at org.springframework.security.crypto.password.DelegatingPasswordEncoder$UnmappedIdPasswordEncoder.matches(DelegatingPasswordEncoder.java:233)
	at org.springframework.security.crypto.password.DelegatingPasswordEncoder.matches(DelegatingPasswordEncoder.java:196)

Xatoni bartaraf etishning eng oddiy usuli – parollaringizni kodlaydigan PasswordEncoderni aniq ko'rsatishdir. Ushbu muammoni hal qilishning eng oson yo'li - hozirgi vaqtda parollaringiz qanday saqlanayotganini aniqlash va to'g'ri PasswordEncoderni ko'rsatishdir.

Agar siz Spring Security 4.2.x dan o'tayotgan bo'lsangiz, NoOpPasswordEncoder ni ochib, avvalgi ish mantiqiga qaytishingiz mumkin.

Bundan tashqari, barcha parollarni to'g'ri identifikator bilan ta'minlash va DelegatingPasswordEncoderni ishlatishda davom etishingiz mumkin. Masalan, agar siz BCryptdan foydalansangiz, parolingizni quyidagicha ko'chirishingiz mumkin:

$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG

ga

{bcrypt}$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG

To'liq xaritalash ro'yxati PasswordEncoderFactories Javadocda keltirilgan.

BCryptPasswordEncoder

BCryptPasswordEncoder realizatsiyasi parollarni hash qilish uchun keng qo'llab-quvvatlanadigan bcrypt algoritmni ishlatadi. Uni qiyinchilik bilan buzish uchun, bcrypt ataylab sekinlashtirilgan. Boshqa adaptiv hisoblash-loyiha bo'lmagan funktsiyalar singari, uning parolingizni tizimingizda tekshirish taxminan 1 soniya davom etishi uchun ehtiyotkorlik bilan sozlanishi kerak. BCryptPasswordEncoder default realizatsiyasi Javadocdagi BCryptPasswordEncoder da 10 ishonchlilik parametri bilan ishlaydi. Parolni tekshirish taxminan 1 soniy

Izohlar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION