Чому тестування скидання пароля нехтують
Скидання пароля — один із найчастіше атакованих сценаріїв у будь-якому застосунку і, як не парадоксально, один із найгірше протестованих. Причина проста: під час розробки розробники використовують власну адресу. Після третього-четвертого прогону ваша скринька завалена однаковими листами «Скиньте пароль». Теми листів злипаються в один ланцюжок, ви плутаєте, яке посилання з якого прогону, і зрештою тестування стає надто дратівливим, щоб робити його ретельно. Ви починаєте покладатися на припущення, що все працює, бо працювало минулого разу. Саме така самовпевненість і пропускає серйозні баги в продакшен.
Ставки високі. Скидання пароля — основний механізм, за допомогою якого користувачі відновлюють акаунти, і через який зловмисники намагаються їх захопити. Токен, що не має терміну дії, посилання, яке можна використати повторно, чи endpoint скидання без обмеження частоти запитів можуть перетворити дрібний витік облікових даних на повне захоплення акаунта. За даними, проіндексованими Have I Been Pwned, мільярди облікових даних зі старих витоків активно обертаються в мережі, і зловмисники регулярно пробують скидати паролі акаунтів, які знаходять. Якщо у вашому сценарії скидання є слабкі місця, їх знайдуть.
Що насправді треба тестувати у скиданні пароля
Базового smoke-тесту «чи надсилається лист» недостатньо. OWASP Authentication Cheat Sheet описує повний набір вимог до безпечного скидання пароля, і кожна з них заслуговує на окремий тест. Ось повний список того, що вам справді слід перевіряти:
- Доставка листа — чи надходить лист для скидання і чи надходить він швидко? Лист, який іде 10 хвилин, збиває користувачів з пантелику й породжує звернення в підтримку.
- Правильність посилання — чи веде посилання в листі на правильну сторінку з правильним токеном в URL чи тілі запиту?
- Термін дії токена — якщо зачекати 25 годин і потім клікнути посилання, чи правильно застосунок відхиляє прострочений токен? Перевірте це на практиці, а не в теорії.
- Одноразовість — чи можна клікнути те саме посилання двічі? Після успішної зміни пароля токен має бути анульовано. Це обов’язкова вимога OWASP, і її часто пропускають.
- Анулювання при повторному запиті — якщо користувач запросив скидання, а через дві хвилини запросив ще раз, чи анулюється перший токен? Два одночасно дійсні токени — це вада безпеки.
- Акаунти з SSO — що відбувається, коли користувач, який зареєструвався через Google, GitHub чи іншого OAuth-провайдера, запитує скидання пароля? Цей сценарій часто зламаний, бо в акаунта немає локального пароля, який можна скинути.
- Обов’язковий HTTPS — чи використовує посилання для скидання HTTPS? Посилання через звичайний HTTP відкриває токен для перехоплення в мережі.
- Якість повідомлень про помилки — коли посилання прострочене, чи показує застосунок зрозуміле, корисне повідомлення, чи загальну помилку 500? Досвід користувача тут має значення.
- Обмеження частоти запитів — що буде, якщо хтось надішле 10 запитів на скидання для тієї самої адреси за одну хвилину? Має бути розумний ліміт, який запобігає перебору й зловживанням.
- Захист від перебору адрес — чи відрізняється відповідь залежно від того, чи існує адреса в системі? Різна відповідь — це витік інформації, який дає змогу зловмисникам перебрати дійсні акаунти.
Підхід із тимчасовою поштою — покроково
Найчистіше розв’язання всіх цих проблем — свіжа адреса тимчасової пошти для кожного прогону. Ось як саме це працює на практиці.
Відкрийте тимчасову скриньку, скопіюйте адресу вгорі й перейдіть у свій застосунок. Зареєструйте новий тестовий акаунт із цією адресою — та сама відправна точка, що й тоді, коли ви тестуєте лист підтвердження реєстрації. Перейдіть на сторінку входу й натисніть «Забули пароль?». Введіть адресу й надішліть запит. Поверніться до тимчасової скриньки — лист для скидання надходить у реальному часі, зазвичай за кілька секунд. Ви бачите весь лист, можете перевірити тему й відправника, клікнути посилання, переконатися, що воно веде на правильну сторінку, задати новий пароль і перевірити, що вхід працює. Загальний час від початку до кінця — менше двох хвилин. Коли потрібно протестувати другий сценарій, відкрийте нову вкладку браузера — ви отримаєте повністю незалежну скриньку з іншою адресою. Жодного прибирання, жодної плутанини з ланцюжками листів, жодного ризику випадково клікнути не те посилання з попереднього прогону.
Реальний приклад: тестування перед релізом
Ми готували SaaS-застосунок до невеликого релізу, який містив оновлення бібліотеки автентифікації. Скидання пароля явно не змінювали, але оновлення auth-бібліотек мають звичку непомітно ламати генерацію токенів у листах. Ось повна послідовність, яку ми пройшли.
Ми відкрили п’ять вкладок браузера, кожну з незалежною тимчасовою скринькою. Вкладка перша: щасливий сценарій — реєстрація, запит на скидання, перехід за посиланням протягом двох хвилин, перевірка входу. Вкладка друга: прострочений токен — реєстрація, запит на скидання, очікування листа, пауза на 25 годин (ми повернулися до нього наступного дня), потім спроба перейти за посиланням. Застосунок правильно його відхилив. Вкладка третя: подвійне скидання — реєстрація, запит на скидання, одразу повторний запит, потім спроба обох посилань. Перше посилання мало бути анульоване; так і було. Вкладка четверта: повторне використання — реєстрація, запит на скидання, успішна зміна пароля за посиланням, потім спроба використати те саме посилання вдруге. Правильно відхилено. Вкладка п’ята: обмеження частоти — швидка серія запитів на скидання, щоб переконатися, що ліміт працює.
Кожен сценарій використовував чисту, незалежну скриньку. Не було жодної неясності, який лист належить до якого тесту. Оновлення auth-бібліотеки нічого не зламало, і ми мали задокументований доказ. Увесь прогін зайняв близько 30 хвилин, не рахуючи нічної перевірки простроченого токена.
Тестування граничних випадків із кількома тимчасовими скриньками одночасно
Кожна вкладка браузера в сервісі тимчасової пошти — незалежна скринька з власною унікальною адресою. Завдяки цьому паралельне тестування стає простим. Відкрийте три вкладки — і у вас три унікальні адреси. Зареєструйте три тестові акаунти, одночасно запустіть скидання пароля для всіх трьох і перевірте, що кожен акаунт отримує лише свій токен, а не чужий. Цей тест на перехресне забруднення ловить особливо неприємний баг, коли погано реалізована система скидання надсилає всі токени на адресу, зареєстровану першою, або на жорстко прописану адресу в неправильно налаштованому середовищі.
Також можна перевірити, що відбувається, коли користувач запитує скидання, уже ввійшовши в систему, або коли скидання запитують для адреси, якої в системі немає. Кожен такий граничний випадок отримує власну чисту скриньку, власний чистий стан і дає однозначні результати.
Чек-лист безпеки токенів
Токени скидання пароля — одна з найпоширеніших поверхонь атаки у вебзастосунках. OWASP чітко описує, чого вимагає безпечна реалізація, і планка вища, ніж уявляють багато команд. Кожен пункт цього списку має перевірятися вашими тестами:
- Щонайменше 32 символи, криптографічно випадкові — короткі чи передбачувані токени можна підібрати перебором. Використовуйте криптографічно стійкий генератор випадкових чисел вашої платформи, а не Math.random() чи його аналоги.
- Термін дії до 24 годин, в ідеалі 1 година — токен без терміну дії — це постійна поверхня атаки. Для більшості застосунків рекомендований максимум — одна година.
- Лише одноразове використання — токен має анулюватися в момент використання. Багаторазовий токен скидання — критична вразливість.
- Анулювання при новому запиті — якщо користувач знову запитує скидання, усі попередні невикористані токени для цього акаунта мають стати недійсними.
- Обмеження частоти для кожної адреси — запобігайте автоматизованому перебору й зловживанням, обмежуючи кількість запитів на скидання для однієї адреси за певний проміжок часу.
- Ніколи не логувати відкритим текстом — якщо ваша система логування записує параметри запитів, переконайтеся, що токени скидання виключаються або хешуються перед записом.
Яким має бути сам лист для скидання
Зміст і вигляд листа для скидання важать більше, ніж думає більшість команд. Добре складений лист простий і функціональний: зрозуміла тема («Скидання пароля»), одна помітна кнопка чи посилання, чітка вказівка терміну дії («Посилання дійсне 1 годину») і примітка, що якщо користувач цього не запитував, лист можна просто проігнорувати. Жодного маркетингового тексту, жодних іконок соцмереж, жодного футера з розсилкою. Транзакційний лист має виглядати як транзакційний.
Важать і дані відправника. Ім’я відправника має чітко відповідати вашому бренду, а адреса — бути належно автентифікованою. Лист із невідповідним іменем відправника або такий, що потрапляє в спам через погано налаштовану автентифікацію, спричинить реальну плутанину в користувачів і навантаження на підтримку. Перевірте налаштування SPF, DKIM і DMARC свого домену за допомогою інструмента на кшталт MXToolbox і прочитайте посібник з автентифікації пошти, якщо якісь із цих термінів вам незнайомі.
Технічну специфікацію пошти — що є, а що не є коректним листом і як працює доставка від початку до кінця — описано в RFC 5321. Читати її непросто, але оглядові розділи дають корисний контекст, щоб зрозуміти, що насправді робить ваша поштова інфраструктура, коли надсилає лист для скидання.
Чому ваша справжня скринька — не той інструмент
Використання особистої чи робочої адреси для тестових акаунтів створює проблеми, які виходять за межі незручності. Ваша адреса опиняється в базі даних вашого ж застосунку як тестовий запис. Вона може з’являтися в логах застосунку, в історії надісланих листів поштового сервера, в експортах staging-середовища, а іноді й у дампах бази, які передають підрядникам чи зовнішнім QA-командам. Staging-середовища часто мають слабший контроль доступу, ніж продакшен. Electronic Frontier Foundation відстоює мінімізацію даних як базовий принцип приватності — і тримати свою справжню адресу подалі від систем розробки й тестування означає безпосередньо застосовувати цей принцип. Тимчасова скринька зникає сама, ніколи не пов’язана з вашою особою й не залишає слідів.
Додайте скидання пароля до регресійного набору
Скидання пароля — це сценарій, який тихо ламається, коли оновлюються бібліотеки автентифікації, змінюються поштові провайдери чи оновлюються API-ключі. Для нього рідко є окремі автотести, бо більшість команд вважають його суто інтеграційним UI-тестом, який важко автоматизувати. Таку логіку можна зрозуміти, але вона небезпечна.
Як мінімум, подумайте про базовий наскрізний тест, що охоплює весь шлях реєстрації, у staging- чи CI-середовищі: програмно створіть тестовий акаунт зі згенерованою адресою, запустіть запит на скидання, перехопіть або перегляньте вихідний лист безпосередньо через API вашого поштового сервісу, витягніть токен, спробуйте його використати й перевірте підсумковий стан. Це не мусить бути складним. Навіть одна автоматична перевірка, яка після кожного деплою підтверджує, що скидання працює, зловить найпоширеніший клас регресій: зміни в auth-залежностях, які непомітно ламають генерацію токенів.
Додаткові ресурси з безпечної автентифікації
Щоб ширше зрозуміти, чому безпечна робота з паролями важлива на практиці, почитайте Troy Hunt — він доступно й добре аргументовано розбирає реальні витоки. Його матеріали про credential stuffing і захоплення акаунтів безпосередньо пояснюють, чому сценарій скидання заслуговує на серйозну увагу. OWASP Authentication Cheat Sheet залишається найповнішим єдиним довідником про все, що має робити ваша система автентифікації. Ці два ресурси плюс дисципліноване тестування зі свіжою скринькою на кожен прогін — основа системи автентифікації, яка витримає перевірку реальним світом.