Автентифікація. Схеми з паролем.
Термінологія
Перш за все, слід внести певну зрозумілість у зміст слів Авторизація і Автентифікація, які дуже часто з'являються поспіль і деколи вживаются одне замість іншого, проте, значення у них дещо відрізняються. Автентифікація - це перевірка того, що користувач є тим, за кого себе видає. Як правило, це процедура перевірки логіну та паролю користувача. У разі успіху такої перевірки користувач допускається до контенту з обмеженим доступом. Інформація з обмеженим доступом (також відома скороченням ІзОД) - це певні дані у системі, доступ до яких мають не всі. Процедура перевірки того, чи може користувач отримати доступ до ІзОД називається Авторизацією.
Наприклад, у деякій системі користувачі поділяються на адміністраторів та модераторів. Адміністратори мають права створювати новий контент, у той час як модератори - вносити зміни у наявний. Для того щоб адміністратори не відміняли дії модераторів, для них внесення змін буде унеможливлене - тільки створення нових дописів. Коли користувач входить до системи, він вводить логін та пароль і, якщо він це зробив правильно, потрапляє до неї. Це означає, що він пройшов автентифікацію. Далі користувач намагається відредагувати певний допис і в цей час здійснюється авторизація - перевірка можливості даного користувача виконати цю дію. Зверніть увагу, користувач може успішно автентифікуватись (тобто увійти у систему), але отримати відмову в авторизації (доступу до певних її функцій). Технічно можливе і зворотнє - авторизація проходить лише для неавтентифікованих користувачів. Таке буває украй рідко, але приклад навести можна: нехай коментарі до публікації можуть залишати лише гості - користувачі, які не увійшли до системи. Для тих, хто увійшов, доступні значно ширші функції обговорення, а для гостей - лише коментарі. У такому разі авторизація є, а автентифікації - немає.
Зазвичай авторизація є значно простішою процедурою, ніж автентифікація. Якщо користувач увійшов до системи, то системі стає відома його роль (адміністратор, модератор, відвідувач, тощо), і за цією роллю система може обмежувати доступи до власних ресурсів. Зовсім інша справа з автентифікацією. Головна проблема з нею полягає у тому, що автентифікаційні дані (логін та пароль) можуть бути викрадені чи підроблені, унаслідок чого вхід до системи буде надано зовсім не тому користувачу, який був зареєстрований. За термінологією така ситуація називається помилка другого роду - надання доступу до системи незареєстрованому користувачеві. Як очевидно слідує з назви, має існувати помилка першого роду. Так, вона існує і полягає у тому, що зареєстрований користувач отримує відмову у вході до системи. Боротьба з помилками другого роду призводить до ускладнення процедури автентифікації, введення альтернативних каналів (багатофакторна автентифікація) або виключно персональних даних (біометрична автентифікація). Але всі ці ускладнення якраз і призводять до збільшення помилок першого роду, коли у користувача немає під рукою альтернативного пристрою (смартфону), або через зміни умов освітлення фотографія його обличчя не сприймається як автентичне.
Надмірне ускладнення схем автентифікації лише задля того, щоб її покращити, зазвичай має протилежний ефект. Користувачу стає складніше увійти до системи, а програмісту - реалізувати алгоритми автентифікації. Усі ці складнощі грають на руку зловмисникам, які тільки й шукають недоліки у системі. А чим вона складніша, тим таких недоліків виявляється більше. Десь має існувати межа адекватної доцільності, після якої додаткові заходи покращення призводять також і до погіршення. Така межа існує і відома під криптографічним Принципом Керкгоффза. Цей принцип дуже старий і виник для військової техніки, але, сучасною мовою, він стверджує те, що вся надійність системи має вміщуватись у надійності паролю. Іншими словами, якщо пароль ненадійний або ненадійно зберігається, то жодне ускладнення системи не покращить її захищеність. І навпаки, якщо пароль надійний, як і надійна схема його передачі, то навіть нескладні алгоритми будуть мати достатню якість для наших задач. Це не значить, що підійде будь-який ненадійний алгоритм автентифікації, але найпростішого з надійних буде цілком удосталь.
Додати солі та перемішати
У схемах автентифікації з паролем є два найбільш вразливі аспекти: передача пароля між користувачем і сервером та зберігання паролю на сервері. Вразливість при передачі полягає у тому, що протокол НТТР передбачає повну відкритість, тобто жодну з його частин неможна приховати. Це ж стосується і паролю, що передається від користувача до системи у складі НТТР пакету. Частково дану проблему вирішує шифрований протокол HTTPS, але щодо надійності такого захисту існує багато суперечок. Детальніше цю проблему ми обговоримо у іншому розділі. Тут зосередимось на проблемі зберігання паролю на сервері системи.
Навіщо система зберігає пароль? Відповідь здається очевидною - для автентифікації, порівняння паролю, який надсилає користувач, з тим паролем, що був закладений у систему при реєстрації. Які ж проблеми це створює? Перш за все, проблему витоку даних. Якщо систему зламають, то зловмисники отримають доступ до даних серверу, а відтак і до паролів користувачів. По-друге, проблему несанкціонованого доступу. Адміністратори системи, що мають доступ до її даних, можуть отримати відомості про будь-який пароль. Його використання обмежене лише моральними якостями адміністратора та осіб, які можуть випадково стати свідками його роботи. Очевидно, що така надійність не є припустимою.
Першим етапом вирішення проблеми збереження паролів є їх гешування. Криптографічним гешем (англ. - hash) називається таке перетворення, яке з довільного об'єкту одержує відбиток однакового розміру. Тобто на вході перетворення є об'єкт будь-якого розміру: хоч порожній об'єкт, хоч рядок "Привіт, Світе!", хоч число 42, хоч файл з фільмом - будь що у цифровому вигляді. Після перетворення (гешування) буде отримано об'єкт фіксованого розміру. Як правило, цей розмір визначається у бітах (наприклад, 128 біт), і подається у вигляді шістьнадцяткового числа на кшталт B6C628CC2810707ABB825098C3E9F5CC. Геш-перетворення повинно бути однозначним: якщо вхідні об'єкти однакові, то і їх геши повинні збігатись. Також до крипто-гешів додається вимога "перемішування" або "крипто-дифузії", суть якої полягає у тому, що геш об'єкту повинен суттєво змінюватися при малих змінах у вхідному об'єкті. Іншими словами, маючи вхідними об'єктами два числа "123" та "124", які відрізняються лише на одиницю, необхідно отримувати геш-образи цих двох чисел, які матимуть між собою значно більше відмінностей. Ще однією вимогою до гешів є їх незворотність. Не повинно існувати жодної можливості відновити вхідний об'єкт, якщо відомий лише його геш. Саме ця остання вимога спонукає нас на вживання геш-функцій для збереження паролів.
Існує багато різних реалізацій геш-функцій. Широко відомими є, наприклад, алгоритми MD5 (Message Digest - 5) та SHA (Secure Hash Algorithm). Менш відомий, але не менш надійний - наш, український, стандарт "Купина" (ДСТУ 7564:2014). Можна присвятити багато часу на проведення порівняльного аналізу різних геш-алгоритмів, проте, по-перше, для задач збереження паролів вони усі добре придатні та, по-друге, наявність нашого стандарту рекомендує вживання саме його (хочеться сказати, що він є найкращий, але не хочеться нікого ображати). Унікальна можливість Купини - генерувати геші довільної довжини (від 8 до 1024 біт), наприклад, 100 біт. Більшість інших алгоритмів мають обмежений перелік довжин (128 - 256 - 512 біт). Реалізації алгоритму Купина можна подивитись на нашому репозиторії https://github.com/sodes-studio/Kupina
Хоча гешування паролів значно покращує надійність їх збереження, залишається один недолік, пов'язаний з однозначністю геш-перетворення. Це означає, що однакові паролі матимуть однаковий геш. Зламавши один з паролів зловмисник також зламує всі ті, що є однаковими за гешем. Більш того, можна обрахувати геші найбільш поширених паролів і шукати збіги з ними у базі даних системи. З метою ускладнення таких дій вживається прийом криптографічної солі. Сіллю називають довільну інформацію, що додається до паролю перед обчисленням його гешу. Зазвичай це випадкове число, різне для кожного з паролів. Особливості використання солі регулюються стандартом RFC 2898 Password-Based Cryptography. Якщо спрощено, то для кожного паролю генерується сіль, вона додається до паролю (як рядок - конкатенацією) і після цього результат гешується. Виходить, що для двох однакових паролів вийдуть різні геші через те, що для них було додано різну сіль. Слід зауважити, що сіль не захищає пароль від зламу через перебирання різних варіантів, вона лише змушує повторювати цю процедуру для кожного з паролів. Вимога до надійності паролю залишається актуальною.
Нікому нічого не скажу або схеми без розголошень
Повернемось до питання передачі паролю від комп'ютера користувача до серверу системи. Оскільки протокол НТТР є відкритим, ми маємо передбачати ситуацію, за якої пакет на запит автентифікації може бути перехоплений зловмисником. Якщо цей пакет містить пароль, то зловмисник матиме змогу його звідти вилучити. Інколи пропонується гешувати пароль при передачі, але це не покращує надійність, оскільки в такому разі зловмиснику не буде потрібен сам пароль, а достатньо буде його гешу, так як саме він бере участь у автентифікації.
Постає цікаве питання - як можна передати відомості про пароль, але в той же час не передавати сам пароль? Насправді існує досить багато різних протоколів, які мають покращені показники безпеки, про більшість з них можна дізнатись з книги Брюса Шнайєра "Прикладна криптографія. Протоколи, алгоритми і вихідний код на C". Серед них особливе місце займають протоколи без розголошення (або протоколи з нульовим розголошенням - Zero Knowledge Protocols). Якщо спрощено, то сутність таких протоколів полягає у тому, що сервер формує певні питання, відповідь на які можна дати тільки знаючи пароль. У той же час відомості про сам пароль не розголошуються.
Як вже стає зрозуміло з попереднього розділу, у якості таких питань можно використовувати сіль та перемішування (геш-перетворення). Сервер генерує сіль та надсилає її користувачеві. Користувач додає сіль до паролю та гешує результат. Цей результат надсилається до сервера, на якому виконується та ж сама процедура зі збереженим паролем. Якщо результати збігаються, значить пароль було введено правильно. На новий запит буде надіслано нову сіль, тому попередні дані вже не є валідними і якщо зловмисник перехопив один з пакетів, другий раз він йому не допоможе.
Більш доскональна схема може бути створена з використанням принципу електронного цифрового підпису (ЕЦП). Її зміст дуже близький до наведеної вище ідеї, проте вживаються більш складні і надійні алгоритми "перемішування". Сервер так само генерує випадкову сіль та передає її користувачеві. Користувач підписує цю сіль, вживаючи свій пароль як закритий ключ підпису. Відкритий ключ, згенерований при реєстрації з того ж паролю, зберігається на сервері замість гешу паролю і бере участь у перевірці підпису.
Залишити коментар
Ім'я (відображається)E-mail (не відображається)
Дуже цікаво, дякую!
Важко!