Зламай мене, якщо зможеш: топ-3 технічні вразливості онлайн-платежів
Я досить довго не публікував нові матеріали, хоча розповісти було про що. Головна причина – неможливість бути в ресурсі для всього і одразу. Блогінг та словесні потоки не є моєю сильною стороною, а ось потоки платежів зовсім інша історія. Мене звуть Денис Михайлюк і наразі в команді bill_line я займаю позицію Architect, а тому мені особливо цікаво говорити саме про стратегічні питання безпеки та навантаженості систем, що здійснюють обробку транзакцій. І сьогодні я хочу навести три найбільші експлойти у юзерфлоу онлайн-платежів, з якими я стикався особисто або ж дізнався від колег.
Як має виглядати безпечний платіж
Коли ви поповнюєте мобільний чи переказуєте гроші, процес здається вам простим, майже миттєвим. Що ж, це приємно, значить роки моєї роботи та моїх колег мають свої плоди: сервери швидкі, код написаний грамотно та регулярно оновлюється, а дизайнер з проєкт-менеджером зробили якісний userflow, в якому немає зайвих екранів.
Однак з точки зору створення безпечної програмної реалізації процес проходу транзакції є складним процесом, який досі має купу проблем у всіх, від великих банків та psp (платіжного сервіс-провайдера), до нових гравців на ринку, які періодично зʼявляються з офферами, в яких точно буде щось на кшталт «простого та зручного API» та інтеграцією за 5-10 хвилин. Відкрию великий секрет – у спрощень є своя «стеля». Комплаєнс потребує часу, а у бізнесу з процесами, які є складнішими за простий рітейл, є свої унікальні вимоги чи нюанси, які не лягають у заготовлені сценарії.
Отже, як же виглядає типовий процес прийому платежу? Для початку розглянемо поточну реалізацію токенізованого платежу, коли ви (customer) намагаєтеся щось оплатити, наприклад через Apple Pay\Google Pay:
- Вебсайт/застосунок мерчанта дає реквест на API-сервер його psp;
- Вам не треба вводити платіжні дані, бо їх в вигляді зашифрованого токена сервер передає назад, таким чином пропускаючи вас на етап оплати;
- Якщо б ви робили це через 24Pay\monopay на сайті, то вам треба було б якось проавторизуватися, але у прийнятому сценарії цього не треба. Ви лише підтверджуєте платіж біометрією (відбиток або обличчя);
- Так само токенізовані дані про замовлення знову летять на API-сервер, після чого повертаються назад, підтверджуючи або скасовуючи можливість оплати (наприклад, недостатня кількість коштів на дебетовій картці);
- Ви бачите екран успіху або помилки.
Перед вами проста та зрозуміла схема оплати (на цьому моменті всі випадкові читачі посміялися та закрили вкладку), у якій врахована і безпека, і максимальна бесшовність транзакції. Жодні параметри платежу не передаються явно, натомість використовуються токени, що вже є стандартом. Саме завдяки ним ви можете мати рекурентні платежі та сплачувати в один клік. Сервер платіжної системи не надсилає результати на якусь URL самостійно: замість цього вебсайт/застосунок, з якого ви платите, робить самостійні реквести та обробляє відповідь.
Окей, що ж може піти не так?
Якщо коротко – диявол завжди в деталях. Деталях, які не врахувала команда розробки, які зафакапили окремі члени команди чи з простого бажання знайти компроміс між зручністю та безпекою не на користь останньої.
#3 Вразливість OTP-коду
Це тема трохи застаріла, тому актуальна більше для декстоп-версій, користування якими падає з кожним роком. Однак проблема все ще актуальна. Завжди використовуйте механізм OTP-кодів (one-time password) для всіх важливих операцій у вашому проєкті. Одноразові паролі повинні “жити” не більше 2 хвилин та бути прив’язані чітко до виконуваної операції за допомогою додаткового випадкового параметра, що відповідає ідентифікатору операції. Це ж правило можна застосувати і до біометрії у додатках: запитуйте перевірки на основних операціях кінцевого споживача. Зрозуміло, що останній не буде задоволений постійною необхідністю вводити код з смс чи показувати обличчя, однак саме так ви переконаєтеся, що будь-яку операцію здійснює саме власник рахунку.
#2 Відсутність механізму HSTS для підключення та відсутність захисту cookie маркерами Secure та SameSite
У сучасних браузерах є ряд механізмів, що допомагають захищати дані від перехоплення, і HSTS один з них.
Розшифровується він як HTTP Strict Transport Security і являє собою механізм примусового з’єднання за допомогою HTTPS-протоколу. За активацію механізму відповідає заголовок Strict-Transport-Security в HTTP-відповіді сервера.
Які ще “закляття” можна проказати:
- HPKP (HTTP Public Key Pinning) – технологія прив’язки публічного ключа, яка забороняє підключатися до веб-сервера, якщо хтось підмінив SSL сертифікат. За активацію відповідає заголовок Public-Key-Pins;
- CSP (Content Security Policy) – тул, спрямований на захист від атак із впровадженням контенту, наприклад, від «Міжсайтового виконання сценаріїв». Магія запускається заголовком Content-Security-Policy;
- X-Content-Type-Options – хедлайн, призначений для захисту браузера юзера від атак з використанням заміни типу переданого контенту MIME;
- X-Frame-Options – хедлайн проти Clickjacking-у.
А тепер про вищезгадані маркери. Secure зобовʼязує передавати cookie лише за HTTPS. Відсутність цього маркера створює загрозу перехоплення cookie. Як вирішити? Просто: встановлюємо значення true для властивості requireSSL.
А от використання атрибуту SameSite у режимі Strict не дозволить передавати cookie на сторонні ресурси та забезпечить захист від атак типу «Підробка міжсайтового запиту».
#1 Десеріалізація недовірених даних
Не можна використовувати серіалізовані об’єкти під час передачі у параметрах, які можуть бути легко підроблені зловмисником. Найпростіший спосіб уникнути цього – використовувати цифровий підпис таких об’єктів з перевіркою на стороні серверу.
Неврахування такої помилки веде як до критично небезпечних вразливостей типу «Виконання довільного коду» або «Десеріалізація недовірених даних», так і до менш очевидних речей. Наприклад, колеги під час роботи на сервері онлайн-банку виявили інтерфейс з адресою внутрішньої мережі банку. Якщо знати цю адресу, хакер може робити атаки на всю корпоративну інфраструктуру і поставити під загрозу процесинг.