36-წუთიანი სამუშაო სესია იმაზე, როგორ დაამტკიცოთ, ვინ არის მომხმარებელი, და როგორ გადაწყვიტოთ, რისი უფლება აქვს — პაროლების ჰეშირებიდან და სესიები vs ტოკენებიდან, OAuth 2.0-სა და OpenID Connect-ის გავლით, RBAC-მდე, სტანდარტებამდე და იმ ინსტრუმენტებამდე, რომლებიც მათ ახორციელებს.
უსაფრთხოების თითქმის ყველა ბაგი ამ ორის აღრევით იწყება. ისინი მკაცრი თანმიმდევრობით მუშაობს: სისტემა ჯერ ადგენს ვინაობას და მხოლოდ შემდეგ ამოწმებს უფლებას. სწორად აითვისეთ თანმიმდევრობა — და სიტყვებიც — და ამ სესიის დანარჩენი ნაწილი ადგილზე დაჯდება.
ჯერ ვინაობა, მერე უფლება. ვინაობის ჩავარდნილი შემოწმება აბრუნებს 401 Unauthorized-ს; უფლების ჩავარდნილი შემოწმება — 403 Forbidden-ს.
სახელდების შენიშვნა HTTP-ის 401 სტატუსს პირდაპირ "Unauthorized" ჰქვია, მაგრამ სინამდვილეში ნიშნავს არაავთენტიფიცირებულს — ისტორიული თავისებურება, რომელიც ღირს იცოდეთ.
პაროლი, PIN-კოდი ან აღდგენის ფრაზა. იაფი და უნივერსალური — მაგრამ ხელახლა გამოსაყენებელი, ფიშინგით მოსაპარი და გამოსაცნობი. არასოდეს იყოს ერთადერთი ფაქტორი იქ, სადაც რამე მნიშვნელოვანია.
ტელეფონი ავთენტიფიკატორის აპლიკაციით, აპარატურული უსაფრთხოების გასაღები ან passkey თქვენს მოწყობილობაზე. მოპარული პაროლი მარტო აღარ ჰყოფნის შემტევს შესასვლელად.
თითის ანაბეჭდი ან სახის სკანი. მოსახერხებელია და ძნელად გასაზიარებელი — მაგრამ სახეს ვერ შეიცვლით, თუ შაბლონი გაჟონავს, ამიტომ ბიომეტრიას მოეპყარით როგორც ლოკალურ განბლოკვას და არა სერვერის საიდუმლოს.
მრავალფაქტორიანი ავთენტიფიკაცია (MFA) უბრალოდ ნიშნავს, რომ ამათგან ორი სხვადასხვა კატეგორიიდან მოითხოვება — ჩვეულებრივ პაროლი პლუს ტელეფონი ან passkey. ეს ყველაზე დიდი ეფექტის მომტანი ერთი კონტროლია, რომელიც შესვლის პროცესს შეგიძლიათ დაუმატოთ.
გატეხვა თუ-ს საკითხი არაა, არამედ როდის-ის. ერთადერთი კითხვაა, რას იპოვის შემტევი თქვენს მონაცემთა ბაზაში. შეინახეთ პაროლები სწორად და სრული დამპი მათთვის თითქმის უსარგებლო იქნება. ეს ის შეცდომაა, რომელსაც გუნდები ყველაზე ხშირად — და ყველაზე მტკივნეულად — უშვებენ.
import { hash, verify } from "argon2" // on sign-up: salt is generated & embedded for you const stored = await hash(plaintext) // on login: re-hash the attempt & compare safely const ok = await verify(stored, attempt) if (!ok) throw new Error("invalid credentials")
პაროლი + უნიკალური salt → ნელი ცალმხრივი ჰეში → შეინახეთ მთელი სტრიქონი. კარგი ბიბლიოთეკა სამივე ნაბიჯს თქვენ მაგივრად აკეთებს.
Password Hashing Competition-ის გამარჯვებული; რეგულირდება მეხსიერებითაც და დროითაც, რაც GPU-სა და ASIC-ით გატეხვას უძლებს. რეკომენდებული პირველი არჩევანი ახალი სისტემებისთვის.
ათწლეულების გამოცდილება რეალურ ბრძოლაში და ხელმისაწვდომია ყველგან. დღესაც სავსებით კარგია; გაითვალისწინეთ ~72-ბაიტიანი შემავალი ლიმიტი. უსაფრთხო, მოსაწყენი არჩევანი.
გამოიყენეთ, როცა მარეგულირებელი მოთხოვნა ავალდებულებს. PBKDF2-ს ნელი რომ დარჩეს, იტერაციების დიდი რაოდენობა სჭირდება — მთელი აზრი სწორედ ის არის, რომ განზრახ ნელი იყოს.
verify), არასოდეს უბრალო ==-ით, რომ დროითი გაჟონვა აირიდოთ.HTTP უმდგომარეობოა — ყოველი მოთხოვნა უცნობივით მოდის. ამიტომ წარმატებული შესვლის შემდეგ ბრაუზერს ვაძლევთ რაღაცას, რასაც ის ყოველ მომდევნო მოთხოვნაზე წარადგენს. ორი დომინანტი მიდგომა არსებობს და მათ შორის კომპრომისი მთელ თქვენს არქიტექტურას განსაზღვრავს.
ქუქი უაზრო ID-ია; სიმართლე იმ საცავშია, რომელსაც სერვერი აკონტროლებს — ამიტომ მომხმარებლის გამოყვანა ერთი წაშლაა.
ტოკენი თავის claims-ებს თავად ატარებს; სერვერი მხოლოდ ხელმოწერას ამოწმებს — სწრაფია და უმდგომარეობო, მაგრამ გაცემულს უკან ვეღარ წაიღებთ.
sub), როდის იწურება ვადა (exp) და როლები თუ scope-ები.JWT არის header.payload.signature. შეცვალეთ payload-ის ერთი ბაიტი და ხელმოწერა აღარ დაემთხვევა.
გაუქმება საცავში ერთი წაშლაა. იდეალურია კლასიკური ვებ-აპლიკაციებისთვის, ბანკინგისთვის და ყველაფრისთვის, სადაც "ეს მოწყობილობა ახლავე გამოაგდე" მყისიერი უნდა იყოს.
საერთო სესიების საცავი არ არის; ნებისმიერ სერვისს მოთხოვნის შემოწმება მხოლოდ საჯარო გასაღებით შეუძლია. შესანიშნავია API-ებისთვის, მობილურისთვის და მიკროსერვისებისთვის.
გაჟონილი JWT ვადის გასვლამდე ვალიდურია. გამოსავალი: access-ტოკენები ხანმოკლე გახადეთ (წუთები) და დაუწყვილეთ შენახული, გასაუქმებელი refresh-ტოკენი.
სად ინახავთ, უფრო მნიშვნელოვანია, ვიდრე რომელს აირჩევთ. უპირატესობა მიანიჭეთ HttpOnly, Secure, SameSite ქუქის, რომ JavaScript-მა ვერ წაიკითხოს (ეს XSS-ით ტოკენის მოპარვისგან იცავს). JWT-ის localStorage-ში ჩადება კლასიკური შეცდომაა — ნებისმიერ ჩანერგილ სკრიპტს მისი მოპარვა შეუძლია.
OAuth და OIDC საშიშად ჟღერს, მაგრამ ძირითადი იდეა მარტივია: მომხმარებელს საშუალებას აძლევს, ერთ აპლიკაციას მისცეს შეზღუდული წვდომა მეორეში არსებულ თავის ანგარიშზე — პაროლის ნაცვლად დროებითი გასაღებით. როგორც კი ოთხ როლს დაინახავთ, ნაკადი წინადადებასავით წაიკითხება.
მომხმარებელი, რომელსაც ანგარიში ეკუთვნის და რომელიც წვდომას გასცემს.
აპლიკაცია, რომელსაც წვდომა სურს — მაგალითად, ფოტოების ბეჭდვის საიტი.
შეჰყავს მომხმარებელი და გასცემს ტოკენებს — მაგალითად, Google-ის შესვლა.
ინახავს მონაცემებს და იღებს access-ტოკენს — მაგალითად, Google Photos API.
Authorization Code-ის ნაკადი: აპლიკაცია პაროლს ვერასოდეს ხედავს — მხოლოდ ხანმოკლე კოდს, რომელსაც (თავის საიდუმლოსთან ერთად) ტოკენებზე ცვლის.
შეზღუდული გასაღები, რომელსაც აპლიკაცია რესურსის სერვერს უგზავნის. ის ამბობს, რის უფლება აქვს მფლობელს (scope: photos.read) და არა იმას, ვინ არის ის. შეინახეთ ხანმოკლედ.
JWT, რომელიც აღწერს, ვინ შევიდა — sub, email, name. სწორედ ეს ამუშავებს სოციალურ შესვლას; თქვენი აპლიკაცია მას კითხულობს, რომ ლოკალური ანგარიში შექმნას ან დაამთხვიოს.
როგორც სასტუმრო: რეცეფცია (auth სერვერი) ამოწმებს თქვენს პირადობას და გაძლევთ ნომრის ბარათს (access-ტოკენი), რომელიც ხსნის მხოლოდ თქვენს ნომერსა და დარბაზს — არა სეიფს, არა სხვების ნომრებს — და გამოსვლისას ვადა ეწურება. დამლაგებელს პასპორტს არასოდეს აძლევთ.
ავტორიზაციას მოდელი სჭირდება და არა კოდში მიმოფანტული if-შემოწმებების გროვა. ორი მიდგომა დომინირებს; რეალური სისტემების უმეტესობა პირველით იწყებს და მეორისგან ცოტას ამატებს, როცა წესები ნიუანსური ხდება.
// assign roles to users; permissions to roles user.roles = ["editor"] const can = { editor: ["post.read", "post.write"], admin: ["post.*", "user.manage"], } if (!allows(user, "post.write")) throw new Forbidden()
RBAC: მომხმარებლები → როლები → უფლებები. ერთხელ შეცვალეთ, რისი გაკეთება შეუძლია "რედაქტორს", და ყველა რედაქტორი განახლდება.
photos.read) — რის უფლება აქვს ტოკენს. claim არის მტკიცება მომხმარებლის შესახებ ტოკენის შიგნით (role: admin, email_verified: true) — ფაქტები, რომლებსაც თქვენი ავტორიზაციის ლოგიკა კითხულობს გადაწყვეტილების მისაღებად.ავთენტიფიკაცია გადაწყვეტილი ამოცანაა, ოღონდ ბასრი კიდეებით — საკუთარი ვერსიის წერა ნიშნავს ყველა იმ სისუსტის თავიდან აღმოჩენას, რომელიც ინდუსტრიამ უკვე დახურა. რეალური გადაწყვეტილებაა, რომელ სტანდარტზე ილაპარაკოთ და რომელ ინსტრუმენტს დაეყრდნოთ. აი, ლიდერები და თითოეულის ადგილი.
აირჩიეთ, როცა გჭირდებათ პროტოკოლების ფართო მხარდაჭერა და კორპორაციული ფუნქციონალი და გირჩევნიათ კონფიგურაცია, ვიდრე აგება.
აირჩიეთ, როცა თანამედროვე ვებ-აპლიკაციას აშენებთ და შესვლის ეკრანები, MFA და მომხმარებლების მართვა ერთ შუადღეში გინდათ.
აირჩიეთ, როცა მობილურ აპლიკაციას ან პროტოტიპს უშვებთ და უკვე Firebase/GCP-ში ცხოვრობთ.
აირჩიეთ, როცა მონაცემების ადგილმდებარეობა, ღირებულება მასშტაბზე ან ვენდორზე მიბმის არიდება ოპერაციულ ტვირთს გადაწონის.
აირჩიეთ, როცა მოთხოვნები მარტივი და სტაბილურია, ან შეზღუდვები ჰოსტირებულ პროვაიდერს გამორიცხავს. გამოიყენეთ შემოწმებული ბიბლიოთეკა — არასოდეს ნედლი კრიპტოგრაფია.
მოდი, ყველაფერი ერთმანეთს დავუკავშიროთ: მომხმარებელი შედის სისტემაში, შემდეგ კი პოსტის რედაქტირებას ცდილობს. დააკვირდით, როგორ აკეთებს ორივე კარიბჭე თავის საქმეს — ჯერ ვინაობა, მერე უფლება — სანამ მოთხოვნა გატარდება.
შესვლა ვინაობას ერთხელ ამტკიცებს და ტოკენს გასცემს; ყოველი შემდეგი მოთხოვნა ხელახლა ამოწმებს ტოკენს (AuthN) და პოლიტიკას (AuthZ).
// runs on every protected request function guard(req: Request) { const user = verifyToken(req.cookies.session) if (!user) throw new Unauthorized() // 401 · AuthN const post = load(req.params.id) if (post.ownerId !== user.id && !user.roles.includes("admin")) throw new Forbidden() // 403 · AuthZ }
ორივე შემოწმება სერვერზე ცხოვრობს. ტოკენი პასუხობს, ვინ; მფლობელობის/როლის შემოწმება კი — შეიძლება თუ არა.
HttpOnly cookie-ებში შეინახეთ.ხუთი სწრაფი კითხვა ავთენტიფიკაციაზე, ჰეშირებაზე, ტოკენებზე, OAuth/OIDC-სა და ავტორიზაციაზე — მყისიერი პასუხი, შესვლის გარეშე.
ნავიგაცია ← → ღილაკებით ან სქროლით · უკან ბიბლიოთეკაში