Щоб користувач не обирав файл ключа й не вводив пароль щоразу, ключ можна
зберегти у віджеті. Далі операція виконується без вибору файла й пароля до
контейнера — а з ttlMinutes і взагалі без жодної взаємодії.
Типовий сценарій: підписати 50 накладних поспіль, працювати цілий день у кабінеті бухгалтера, масовий підпис у ERP.
Режим доступний для трьох віджетів, що працюють із ключем:
| Віджет | Поведінка зі збереженим ключем |
|---|---|
sign — підпис |
тихо, без модалки (за ttlMinutes) |
decrypt — розшифрування |
тихо, без модалки (за ttlMinutes) |
auth — вхід за КЕП |
напівавтоматично: файл і пароль не потрібні, але користувач завжди тисне «Увійти» |
Чому вхід за КЕП не автоматизується повністю: підтвердження особи — це згода користувача. Ми економимо йому файл і пароль, але не саму згоду, щоб сторінка не могла «увійти» від його імені без відома.
Спочатку — увімкніть функцію
Автоматичний режим вимкнено за замовчуванням: віджет поводиться як звичайно (ключ і пароль щоразу), і жодного UI збереження користувач не бачить. Умикає його інтегратор — явним параметром:
const signer = await embed('sign', { session: true }); // ← увімкнути збереження ключа
// так само для інших віджетів, що працюють із ключем:
const dec = await embed('decrypt', { session: true });
const auth = await embed('auth', { session: true });
Значення session |
Поведінка |
|---|---|
| не задано | функція вимкнена: ключ і пароль щоразу (за замовчуванням) |
true |
ключ зберігається; PIN питається щоразу, файл і пароль до контейнера — ні |
{ ttlMinutes: 60 } |
PIN не питати 60 хв у межах вкладки — підпис іде без взаємодії |
{ noPin: true } |
показати користувачу галочку «Не використовувати PIN» (за замовчуванням її немає) |
Крок 1. Завантажити ключ наперед
Окремий крок, без жодного підпису: відкривається вікно лише з полями ключа, користувач обирає файл, вводить пароль до контейнера і придумує короткий PIN-код швидкого доступу.
const signer = await embed('sign');
// «Завантажити ключ» — окремою кнопкою у вашому інтерфейсі
const st = await signer.session.setup();
// st = { saved: true, unlocked: true, needsPin: true, label: 'key.p12', … }
Ключ зберігається в нашому origin (dstucrypt.com.ua) у зашифрованому
вигляді, окремим записом для вашого домену.
Крок 2. Далі — без файла й пароля
// той самий виклик; що побачить користувач — залежить від налаштування:
const { signature } = await signer.sign(doc, { format: 'CAdES-T', digest: 'gost-34311' });
session: true(за замовчуванням) — відкриється компактне вікно з одним полем PIN. Ні файла, ні пароля до контейнера.session: { ttlMinutes: N }— перші N хвилин після введення PIN модалка взагалі не відкривається: підпис виконується тихо. Режим для масових операцій (підписати 50 накладних поспіль).
ttlMinutes— це компроміс: що довший інтервал, то зручніше користувачу і то більше вікно, у якому скомпрометована сторінка могла б підписати щось без його відома.
Ключ можна зберегти й «попутно»: у звичайному вікні підпису є галочка «Запам'ятати ключ на цьому сайті» з полем PIN.
session.setup()— це той самий механізм, але окремим кроком, коли зручніше налаштувати все наперед (наприклад, кнопка «Підключити ключ» у налаштуваннях кабінету).
Керування сесією з вашої сторінки
await signer.session.setup(); // завантажити/замінити ключ
const st = await signer.session.status();
// { saved: true, unlocked: false, needsPin: true, label: 'key.p12', unlockedUntil: … }
if (st.saved && !st.unlocked) {
await signer.session.unlock({ pin: userPin }); // свій PIN-екран у вашому UI
}
await signer.session.lock(); // заблокувати (ключ лишається збереженим)
await signer.session.forget(); // прибрати ключ з браузера зовсім
Поле status() |
Що означає |
|---|---|
saved |
для цього домену збережено ключ |
unlocked |
сесія активна — підпис піде без взаємодії |
needsPin |
ключ захищено PIN-кодом (режим за замовчуванням) |
label |
ім'я файла ключа (для показу користувачу) |
unlockedUntil |
час, до якого сесія лишається розблокованою |
Якщо unlocked: false, а ви просто викличете sign() — віджет відкриє модалку
й попросить PIN. Тобто робочий код не ламається в жодному стані.
Де і як зберігається ключ
- Сховище —
localStorageнашого origin. Ваш сайт не має до нього доступу (Same-Origin Policy), інші сайти — теж. - Запис прив'язаний до вашого домену. Наш
localStorageспільний для всіх сайтів, що вбудовують віджет, тому кожен запис зберігається окремо під origin хоста й віддається лише йому: ключ, збережений наsite-a.com, недоступний дляsite-b.com. - У сховищі лежить шифротекст. Контейнер і його пароль запаковані в конверт AES-GCM-256, ключ шифрування — PBKDF2-SHA256 (310 000 ітерацій) з PIN-коду. Сам PIN ніде не зберігається.
- Після введення PIN розшифрований конверт живе лише в пам'яті поточного
екземпляра віджета — нова модалка попросить PIN знову. Якщо задано
ttlMinutes, він переживає модалки в межах вкладки (sessionStorage) і гине разом із нею. - Термін зберігання ключа за замовчуванням — 30 днів, після чого запис видаляється сам.
Режим без PIN — і чому ми не радимо
Опцію треба спершу дозволити інтегратором (session: { noPin: true }) — лише
тоді у віджеті з'явиться галочка «Не використовувати PIN». Якщо користувач її
позначить, підпис іде одразу, без жодного введення. Віджет прямо попереджає, що
це менш безпечно:
Без PIN ключ у сховищі захищений лише від інших сайтів. Будь-хто з доступом до цього комп'ютера й браузера зможе ним підписувати.
Технічно в цьому режимі конверт шифрується випадковим секретом, що лежить поруч у тому ж сховищі — це обфускація, а не захист. Використовуйте його лише на довірених робочих місцях.
Що варто зважити (чесно)
Автоматичний режим свідомо міняє частину безпеки на зручність:
- Немає підтвердження кожного підпису. Поки сесія розблокована, ваш код може підписати будь-що без участі користувача. Якщо вашу сторінку скомпрометують (XSS), зловмисник зможе підписувати документи від імені користувача, доки триває сесія. Без збереженого ключа він мусив би знати пароль до контейнера.
- Ключ лежить на диску користувача (зашифрований). Для звичайного режиму ключ узагалі не покидає оперативну пам'ять вкладки.
Тому:
- функція вимкнена за замовчуванням — вмикайте свідомо й лише там, де вона справді потрібна;
- не дозволяйте
noPinбез ваговитої причини: PIN — головний захист збереженого ключа; ttlMinutesтримайте помірним (наприклад, тривалість одного сеансу роботи);- для критичних операцій (платежі, договори на великі суми) залишайте звичайний режим із підтвердженням;
- давайте користувачу кнопку «Забути ключ» у своєму інтерфейсі —
signer.session.forget().