Коротка відповідь. Вхід за КЕП — це схема challenge–response: ваш бекенд бере в DSTUcrypt одноразовий challenge (POST /api/auth/challenge), користувач підписує його своїм ключем в auth-віджеті прямо у браузері, а бекенд віддає підпис на серверну перевірку (POST /api/auth/verify). У відповідь приходить криптографічно підтверджена особа: ПІБ, РНОКПП, ЄДРПОУ, дані сертифіката й ознака qualified — що це саме вхід за КЕП. Підпис неможливо підробити чи використати повторно, а ключ користувача ніколи не покидає його браузер.
Навіщо взагалі вхід за КЕП
Класична авторизація — логін, пароль, СМС-код — доводить лише те, що людина знає пароль або тримає в руках телефон. Вона нічого не каже про те, хто ця людина юридично. Для багатьох українських сервісів цього замало: особистих кабінетів із документами, фінансових сервісів, B2B-порталів, систем електронного документообігу, послуг для бізнесу й держпослуг.
Вхід за електронним підписом розв'язує обидві задачі одразу. Користувачу не треба реєструватися, вигадувати пароль і чекати СМС — він просто підтверджує особу ключем, який у нього вже є. А ви отримуєте не «якийсь email», а ідентифікацію рівня КЕП: повне ім'я, РНОКПП і код ЄДРПОУ з кваліфікованого сертифіката, перевіреного криптографічно. Це той самий рівень довіри, на якому будуються державні сервіси, — тепер доступний вашому продукту через один віджет і два серверні виклики.
Як це працює технічно: чотири кроки
В основі — схема challenge–response, яка унеможливлює і підробку, і повторне використання підпису:
- Бекенд бере одноразовий challenge. Ваш сервер робить
POST https://dstucrypt.com.ua/api/auth/challengeі отримує{ challenge, expiresIn }. Challenge живе 5 хвилин і згорає після першої перевірки — це захист від повторного використання. - Користувач підписує challenge ключем у віджеті. На вашій сторінці auth-віджет DSTUcrypt відкриває модалку, користувач обирає свій ключ, вводить пароль — і підписує challenge. Уся криптографія виконується в браузері (WebAssembly) всередині iframe на нашому origin: ключ і пароль не бачить ні ваша сторінка, ні будь-який сервер.
- Сторінка передає підпис на ваш бекенд. Фронтенд надсилає пару
{ challenge, signature }на ваш власний endpoint входу. - Бекенд віддає підпис на серверну криптоперевірку. Ваш сервер викликає
POST https://dstucrypt.com.ua/api/auth/verify— і нативне криптоядро на сервері DSTUcrypt перевіряє підпис, цілісність, збіг вмісту з challenge і чинність сертифіката. У відповідь —{ ok, subject{…} }з підтвердженою особою.
Технічна деталь: підпис, який формує auth-віджет, — це attached CAdES над challenge, за замовчуванням із гешем ДСТУ ГОСТ 34.311-95 (криптоядро підтримує й сучасну «Купину» за ДСТУ 7564:2014 — що це за геш-функція, ми детально розбирали в окремій статті).
Чому перевірку не можна робити в браузері
Спокуса зрозуміла: взяти JS-бібліотеку, перевірити підпис прямо на фронтенді й «зекономити» серверний виклик. Для авторизації це не production-безпечне рішення з двох причин.
Перша — принципова. Результат перевірки формується на боці клієнта, а браузер повністю контролює той, хто в ньому сидить. Атакуючому не потрібен жоден ключ: досить відкрити DevTools і підмінити «підпис дійсний» — і ваш фронтенд радісно повідомить бекенду, що вхід успішний. Рішення про допуск, ухвалене в браузері, за визначенням не варте нічого.
Друга — практична. У відкритих чисто-JS реалізаціях ДСТУ відомі цілі класи вразливостей: timing-атаки (криптографія без константного часу виконання) і слабка генерація випадкового k, що уможливлює відновлення приватного ключа з підписів. Ми розбирали ці атаки детально в статті про небезпеку чисто-JS криптографії.
Як це закриває DSTUcrypt. Підпис формується в ізольованому iframe на нашому origin (WASM, константний час), а перевірка виконується на нашому сервері нативним криптоядром — перевіреною C/C++-бібліотекою, що роками працює в українській PKI. Результат серверної перевірки неможливо підробити на клієнті: браузеру не довіряється нічого, крім самого підпису. У відповідь ви отримуєте підтверджену особу — ПІБ, РНОКПП, ЄДРПОУ, — а ключ користувача при цьому ніколи не покидає його браузер.
Код інтеграції auth-віджета
Серверна частина — два виклики. Спершу бекенд бере challenge (server-to-server, не з браузера), наприкінці — віддає підпис на перевірку:
бекенд: challenge і серверна перевірка
# 1) одноразовий challenge (живе 5 хвилин, згорає після першої перевірки)
curl -X POST https://dstucrypt.com.ua/api/auth/challenge
# → { "challenge": "dstucrypt-login-v1:…", "expiresIn": 300 }
# 4) серверна криптоперевірка підпису
curl -X POST https://dstucrypt.com.ua/api/auth/verify \
-H "Content-Type: application/json" \
-d '{ "challenge": "dstucrypt-login-v1:…", "signature": "<base64>" }'
На сторінці — auth-віджет: користувач підписує challenge, а підпис іде на ваш бекенд:
фронтенд: auth-віджет підписує challenge
import { embed } from 'https://dstucrypt.io/embed/dstucrypt-embed.mjs';
const auth = await embed('auth', { mount: 'modal' });
const { signature, subject, accredited } = await auth.login({ challenge });
// subject/accredited тут — ЛИШЕ для UX (показати «Вітаємо, Іване!» / попередити,
// що ключ не КЕП); довіряти можна тільки відповіді /api/auth/verify (крок 4)
await fetch('/api/my-backend/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ challenge, signature }), // signature — base64-рядок
});
Успішна відповідь /api/auth/verify містить ok: true, об'єкт subject, а також signatureFormat, signingTime, status (наприклад, TOTAL-VALID) і дві ключові ознаки: accredited — сертифікат від акредитованого надавача, та qualified — це вхід саме за КЕП (акредитований + дійсний). Що всередині subject:
| Поле | Що містить |
|---|---|
| fullName | ПІБ підписанта («Іваненко Іван Іванович») |
| taxId | РНОКПП — стабільний ідентифікатор особи |
| orgCode | код ЄДРПОУ організації |
| issuer | АЦСК, що видав сертифікат |
| certSerial | серійний номер сертифіката |
| validFrom / validTo | строк дії сертифіката |
Відмови теж передбачувані:
| HTTP | reason | Причина |
|---|---|---|
| 401 | challenge_invalid_or_used | challenge невідомий, прострочений або вже використаний |
| 200 | signature_invalid ( ok:false ) | підпис не пройшов криптоперевірку, вміст ≠ challenge, або сертифікат нечинний |
| 400 | bad_request / bad_signature_encoding | некоректне тіло запиту |
Що робити з отриманою особою
Після ok: true ви створюєте власну сесію — свій cookie, JWT чи що завгодно: DSTUcrypt не керує вашими сесіями, він лише авторитетно відповідає «хто це».
- Ідентифікатор акаунта — subject.taxId (РНОКПП). Це стабільний ідентифікатор особи: він не змінюється при перевипуску ключа, зміні надавача чи прізвища. Якщо акаунт із таким РНОКПП уже є — це повторний вхід; якщо ні — створюєте новий акаунт із заповненим ПІБ.
- Для B2B — matching по orgCode (ЄДРПОУ). Якщо користувач входить ключем співробітника організації, ЄДРПОУ дозволяє автоматично прив'язати його до компанії у вашій системі — наприклад, пустити в кабінет контрагента без ручного підтвердження менеджером.
- Вимагаєте саме КЕП — перевіряйте qualified .
qualified: trueозначає вхід за КЕП; якщо для вашого сценарію потрібен лише КЕП — відхиляйтеqualified: false.
І головне правило довіри: рішення про вхід ухвалюється тільки за відповіддю /api/auth/verify (server-to-server). Поля subject і accredited, які повертає віджет на фронтенді, — best-effort дані виключно для UX: привітати користувача на ім'я чи одразу попередити, що його ключ не КЕП.
Безпека і приватність
Найчастіше питання від служб безпеки: «а куди подорожує ключ користувача?» Відповідь — нікуди. Ключ і пароль вводяться всередині iframe, що завантажується з origin dstucrypt.io: за Same-Origin Policy до них не має доступу навіть код вашої сторінки (у т.ч. при XSS), не кажучи вже про сервери. Уся криптографія виконується локально у браузері (WebAssembly), і назовні виходить лише результат — підпис challenge.
Сам протокол додає ще два рівні захисту. По-перше, challenge одноразовий і короткоживучий: перехоплений підпис не можна «переграти» — повторна перевірка поверне 401 challenge_invalid_or_used. По-друге, перевірка серверна: навіть повністю скомпрометований браузер користувача не може переконати ваш бекенд, що недійсний підпис — дійсний.
Типові сценарії
- Особистий кабінет без реєстрації. Перший вхід за КЕП одразу створює акаунт із перевіреним ПІБ і РНОКПП — жодних форм, email-підтверджень і паролів.
- Фінансові сервіси й страхування. Ідентифікація клієнта рівня КЕП перед доступом до договорів, виплат чи персональних даних.
- B2B-портали й кабінети контрагентів. Автоматична прив'язка користувача до компанії за ЄДРПОУ з сертифіката — постачальник входить у портал закупівель без листування з адміністратором.
- Документообіг. Той самий ключ, яким користувач входить, підписує й документи — вхід і підпис живуть в одній інтеграції DSTUcrypt.
- Крок підтвердження критичних дій. Схему challenge–response можна використати не лише для входу, а й як «підпишіть, щоб підтвердити» перед чутливою операцією.
Поширені запитання
Чи бачить DSTUcrypt чи мій сервер ключ користувача під час входу?
Ні. Ключ і пароль вводяться всередині iframe-віджета на origin dstucrypt.io, а вся криптографія виконується у браузері (WebAssembly). Назовні виходить лише підпис challenge — ключ і пароль не потрапляють ні на ваш сервер, ні на сервери DSTUcrypt.
Чи можна використати перехоплений підпис для повторного входу?
Ні. Challenge одноразовий: він живе 5 хвилин і згорає після першої перевірки. Повторний запит із тим самим challenge отримає відмову 401 із reason challenge_invalid_or_used — тому перехоплений підпис не дає зловмиснику нічого.
Що означає qualified: false у відповіді перевірки?
Це означає, що вхід виконано дійсним підписом, але не КЕП: сертифікат не від акредитованого надавача або не пройшов усі перевірки. Якщо для вашого сценарію потрібен саме вхід за КЕП — відхиляйте відповіді з qualified: false.
За яким полем створювати акаунт користувача?
За subject.taxId — це РНОКПП, стабільний ідентифікатор особи, який не змінюється при перевипуску ключа чи зміні надавача. Для сценаріїв від імені організації додатково використовуйте subject.orgCode (ЄДРПОУ).
Чому не можна перевіряти підпис JS-бібліотекою в браузері?
Бо результат перевірки формується на боці клієнта: атакуючий контролює браузер і може підмінити «підпис дійсний» без жодного ключа. Крім того, у відкритих чисто-JS реалізаціях ДСТУ відомі класи вразливостей — timing-атаки та слабка генерація випадкового k, що уможливлює відновлення приватного ключа з підписів. Тому DSTUcrypt виконує перевірку на сервері нативним криптоядром.
Читайте також
Вхід за КЕП на вашому сайті — за один вечір
Готовий auth-віджет плюс два серверні виклики — і ваш бекенд отримує підтверджену особу: ПІБ, РНОКПП, ЄДРПОУ. Ключ і пароль не покидають браузер користувача. На кожному новому домені — 7 днів безкоштовно.
Живе демоЯк підключити