Реалізація кваліфікованого електронного підпису (КЕП) на сайті
Кваліфікований електронний підпис (КЕП) — єдиний вид ЕП, рівнозначний собственноручній підписі за російським законодавством (ФЗ-63). Це не візуальна підпис і не проста ЕП: КЕП створюється за допомогою кваліфікованого сертифіката (виданого акредитованими УЦ) та криптографічного програмного забезпечення (SKZI).
Технічний стек
CryptoPro CSP — найбільш розповсюджена SKZI в Росії. Встановлюється на комп'ютер користувача. Для роботи з браузера використовується CryptoPro ECP Browser Plugin (NPAPI/COM-компонент) або CryptoPro CSP Web.
Альтернативи:
- Rutoken ECP — токен з вбудованою криптографією GOST, плагін Rutoken Web
- VipNet CSP — альтернативна SKZI
- CryptoARM GOST — десктопна програма з API
Для SaaS без вимоги встановлення SKZI — хмарна КЕП через DSS (Directory Services of Signing): користувач отримує SMS-підтвердження, підпис створюється на сервері в довіреному середовищі. Провайдери: CryptoPro DSS, Kontur.Krypto, Trusted Environment.
Архітектура підписування через CryptoPro Browser Plugin
// Перевірка наявності плагіна
async function checkCryptoProPlugin() {
try {
const plugin = await cadesplugin; // cadesplugin - глобальний об'єкт після завантаження плагіна
return true;
} catch (e) {
return false;
}
}
// Отримання списку сертифікатів користувача
async function getUserCertificates() {
const plugin = await cadesplugin;
const store = await plugin.CreateObjectAsync('CAdESCOM.Store');
await store.Open(
plugin.CADESCOM_CONTAINER_STORE, // З зберігання контейнерів
plugin.CAPICOM_MY_STORE, // "Особисті" сертифікати
plugin.CAPICOM_STORE_OPEN_MAXIMUM_ALLOWED
);
const certs = await store.Certificates;
const validCerts = await certs.Find(plugin.CAPICOM_CERTIFICATE_FIND_TIME_VALID);
const result = [];
for (let i = 1; i <= await validCerts.Count; i++) {
const cert = await validCerts.Item(i);
const subjectName = await cert.SubjectName;
const validTo = await cert.ValidToDate;
result.push({ index: i, subjectName, validTo, cert });
}
await store.Close();
return result;
}
// Створення підпису CAdES-BES (приєднана)
async function signDocumentCAdES(documentBase64, certificateItem) {
const plugin = await cadesplugin;
const signer = await plugin.CreateObjectAsync('CAdESCOM.CPSigner');
await signer.propset_Certificate(certificateItem.cert);
await signer.propset_CheckCertificate(true);
const signedData = await plugin.CreateObjectAsync('CAdESCOM.CadesSignedData');
await signedData.propset_ContentEncoding(plugin.CADESCOM_BASE64_TO_BINARY);
await signedData.propset_Content(documentBase64);
const signature = await signedData.SignCades(
signer,
plugin.CADESCOM_CADES_BES, // BES = без мітки часу
true // detached = відділена підпись
);
return signature;
}
Формати підпису
| Формат | Опис | Застосування |
|---|---|---|
| CAdES-BES | Базовий, без мітки часу | Більшість документів |
| CAdES-T | + мітка часу | Коли потрібна фіксація часу |
| CAdES-XL | + перевірка відзиву сертифіката | Архівне зберігання |
| XAdES | XML документи | ЕДІ, податкова |
| PAdES | Підписування PDF за ETSI |
Хмарна КЕП через CryptoPro DSS
Не вимагає встановлення SKZI на комп'ютер користувача:
// Ініціалізація підписування через DSS API
async function initDssSignature(documentHash, userPhone) {
const response = await fetch('https://dss.cryptopro.ru/SignServer/rest/api/CreateTransactionHash', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.DSS_ACCESS_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
Signature: {
Parameters: {
CadesType: 1, // CAdES-BES
HashAlgorithm: 'GOST3411-2012-256',
},
Content: { IsDetached: true, HashValue: documentHash },
},
OperationID: crypto.randomUUID(),
}),
});
const { TransactionID } = await response.json();
// Відправити SMS з кодом підтвердження
await sendConfirmationSms(userPhone, TransactionID);
return TransactionID;
}
// Підтвердження SMS-кодом
async function confirmDssSignature(transactionId, smsCode) {
const response = await fetch('https://dss.cryptopro.ru/SignServer/rest/api/ConfirmSignature', {
method: 'POST',
body: JSON.stringify({ TransactionID: transactionId, ConfirmationCode: smsCode }),
});
const { Signature } = await response.json();
return Signature; // base64 підпис
}
Верифікація підпису
// Перевірка через CryptoPro WebService
async function verifySignature(documentBytes, signatureBase64) {
const plugin = await cadesplugin;
const signedData = await plugin.CreateObjectAsync('CAdESCOM.CadesSignedData');
await signedData.propset_ContentEncoding(plugin.CADESCOM_BASE64_TO_BINARY);
await signedData.propset_Content(Buffer.from(documentBytes).toString('base64'));
await signedData.VerifyCades(signatureBase64, plugin.CADESCOM_CADES_BES, true);
const signers = await signedData.Signers;
const signer = await signers.Item(1);
const cert = await signer.Certificate;
const certInfo = await cert.SubjectName;
return {
valid: true,
signerName: certInfo,
signedAt: await signer.SigningTime,
};
}
Юридичні вимоги
- Сертифікат повинен бути виданий акредитованим УЦ (реєстр на сайті Міністерства цифрового розвитку)
- SKZI повинна бути сертифікована ФСБ
- Для угод з нерухомістю, нотаріальних дій — додаткові вимоги
- Зберігання документів з КЕП — не менше строку позовної давності (3–10 років)
Терміни
Інтеграція з CryptoPro Browser Plugin: UI, список сертифікатів, підписування CAdES-BES — 7–10 днів. Хмарна КЕП через CryptoPro DSS з SMS-підтвердженням — 7–10 днів. Верифікація підписів з перевіркою сертифіката — 3–5 днів.







