Реалізація електронного підпису документів
Нещодавно до нас звернувся fintech-стартап: їх система підписання договорів із клієнтами складалася з простого SMS-коду без угоди про ЕП. Після аудиту з'ясувалося, що юридична сила таких підписів — нульова, а всі договори під загрозою нікчемності. Ми оперативно впровадили повний цикл: від SMS-коду до КЕП через СБІС. Розповідаємо, як уникнути подібних помилок і реалізувати юридично значущий електронний підпис на сайті.
Розрізняють три типи ЕП: простий (ПЕП — логін/пароль/SMS-код), посилений некваліфікований (НЕП — криптографія, сертифікат ключа перевірки), кваліфікований (КЕП — лише через засвідчувальний центр, прирівнюється до власноручного). Вибір залежить від вимог до юридичної значущості та бюджету. Порівняємо їх ключові характеристики:
| Тип ЕП | Юридична сила | Складність реалізації | Вартість | Термін впровадження |
|---|---|---|---|---|
| ПЕП | Потребує угоди | Низька | Низька | 1–2 дні |
| НЕП | Середня (з сертифікатом) | Середня | Середня | 3–5 днів |
| КЕП | Найвища (дорівнює власноручному) | Висока | Висока | 5–10 днів |
Чому простий ЕП без угоди — це пастка?
Без окремої угоди про використання простого ЕП (оферти або договору приєднання) підпис не має юридичної сили. Згідно з 63-ФЗ, простий ЕП визнається рівнозначним власноручному підпису лише за наявності угоди між сторонами. Ми завжди фіксуємо факт акцепту угоди через окремий чекбокс і зберігаємо аудит-лог. Інакше навіть при успішному SMS-підтвердженні документ можна оскаржити в суді.
Коли без кваліфікованого підпису не обійтися?
КЕП обов'язковий для держзакупівель (44-ФЗ, 223-ФЗ), звітності в ФНС, Росреєстр та угод з нерухомістю. Юридична сила КЕП у сотні разів вища, ніж у простого ЕП — вона підтверджується сертифікатом УЦ та ключем ФСБ. Помилка при виборі може призвести до штрафів до 500 000 рублів і визнання угод недійсними.
Як працює простий ЕП: SMS-підписання договору
Найпоширеніший підхід для B2C: користувач отримує код по SMS, вводить його, ми фіксуємо відмітку часу, IP, fingerprint та хеш документа. Юридично значущий як простий ЕП лише за наявності окремої угоди про використання ЕП. Без нього — просто підтвердження дії.
// Модель документа з аудитом підписання
class Document extends Model
{
protected $casts = [
'signing_metadata' => 'array',
'signed_at' => 'datetime',
];
}
// Сервіс підписання
class DocumentSigningService
{
public function initiateSignin(Document $document, User $user): void
{
// Генерація та відправка коду
$code = str_pad(random_int(0, 999999), 6, '0', STR_PAD_LEFT);
Cache::put("signing_code:{$document->id}:{$user->id}", bcrypt($code), now()->addMinutes(15));
$user->notify(new DocumentSigningCodeNotification($code, $document));
}
public function confirmSigning(Document $document, User $user, string $code, Request $request): void
{
$cached = Cache::get("signing_code:{$document->id}:{$user->id}");
if (!$cached || !Hash::check($code, $cached)) {
throw new InvalidSigningCodeException('Невірний або прострочений код підтвердження');
}
// Створити хеш поточної версії документа
$documentHash = hash('sha256', Storage::disk('s3')->get($document->path));
$document->update([
'status' => 'signed',
'signed_at' => now(),
'signed_by' => $user->id,
'document_hash' => $documentHash,
'signing_metadata' => [
'ip' => $request->ip(),
'user_agent' => $request->userAgent(),
'fingerprint' => $request->header('X-Client-Fingerprint'),
'method' => 'sms_code',
'phone_last4' => substr($user->phone, -4),
'code_sent_at' => Cache::get("signing_code_sent_at:{$document->id}:{$user->id}"),
'signed_at_iso' => now()->toIso8601String(),
'timezone' => $request->header('X-Timezone', 'UTC'),
],
]);
// Зафіксувати підпис в аудит-лозі
AuditLog::create([
'action' => 'document.signed',
'user_id' => $user->id,
'document_id' => $document->id,
'metadata' => $document->signing_metadata,
]);
Cache::forget("signing_code:{$document->id}:{$user->id}");
// Відправити підписану копію на email
$user->notify(new DocumentSignedNotification($document));
}
}
Як вбудувати візуальний підпис у PDF і не втратити юридичну силу?
Для інтерфейсів, де користувач малює підпис стилусом або мишею, підключаємо бібліотеку react-signature-canvas (Canvas API). Важливо: сама по собі растрова підпис не має юридичної сили — її потрібно прив'язати до документа через хеш та метадані. Ми використовуємо два кроки: спочатку зберігаємо зображення підпису та ініціюємо сесію, потім підтверджуємо SMS-кодом.
import SignatureCanvas from 'react-signature-canvas';
import { useRef, useState } from 'react';
function DocumentSigner({ documentId }: { documentId: number }) {
const sigCanvas = useRef<SignatureCanvas>(null);
const [step, setStep] = useState<'draw' | 'confirm' | 'sms'>('draw');
const [smsCode, setSmsCode] = useState('');
const handleDrawComplete = async () => {
if (sigCanvas.current?.isEmpty()) return;
const signatureData = sigCanvas.current!.toDataURL('image/png');
// Зберегти зображення підпису, перейти до SMS-підтвердження
await api.post(`/documents/${documentId}/initiate`, { signature_image: signatureData });
setStep('sms');
};
const handleSmsConfirm = async () => {
await api.post(`/documents/${documentId}/confirm`, { code: smsCode });
setStep('confirm');
};
return (
<div>
{step === 'draw' && (
<>
<p>Намалюйте ваш підпис:</p>
<div style={{ border: '1px solid #e5e7eb', borderRadius: 8 }}>
<SignatureCanvas
ref={sigCanvas}
penColor="#1a1a1a"
canvasProps={{ width: 500, height: 200, className: 'signature-canvas' }}
/>
</div>
<button onClick={() => sigCanvas.current?.clear()}>Очистити</button>
<button onClick={handleDrawComplete}>Далі</button>
</>
)}
{step === 'sms' && (
<>
<p>Введіть код із SMS для підтвердження підпису:</p>
<input
type="text" inputMode="numeric"
maxLength={6} value={smsCode}
onChange={e => setSmsCode(e.target.value)}
/>
<button onClick={handleSmsConfirm}>Підписати</button>
</>
)}
{step === 'confirm' && (
<p>Документ успішно підписано. Копію надіслано на ваш email.</p>
)}
</div>
);
}
КЕП через СБІС / КриптоПро: максимальна юридична сила
Для B2B та держзамовлення впроваджуємо кваліфікований електронний підпис. Підключення до СБІС або КриптоПро займає 5–7 днів. Підписання відбувається на стороні УЦ — ми лише передаємо документ і отримуємо підпис.
// Інтеграція зі СБІС API (підписання на стороні УЦ)
class SbisSigningService
{
public function sign(string $documentBase64, int $signatoryId): string
{
$response = Http::withToken($this->getToken())
->post('https://online.sbis.ru/service/sbis.Signature.Sign', [
'jsonrpc' => '2.0',
'method' => 'СБІС.ПідписатиДокумент',
'params' => [
'Документ' => $documentBase64,
'Підписувач' => $signatoryId,
],
]);
return $response->json('result.Підпис');
}
}
Зберігання та перевірка підписаних документів
// Верифікація підпису — перевірити, що документ не змінено після підписання
public function verify(Document $document): bool
{
$currentHash = hash('sha256', Storage::disk('s3')->get($document->path));
return hash_equals($document->document_hash, $currentHash);
}
Підписані документи зберігаємо з незмінними правами (S3 Object Lock) — це запобігає фальсифікації навіть при компрометації акаунта. Додатково налаштовуємо retention policy на 5 років (строк позовної давності).
Що потрібно для юридичної значущості простого ЕП?
Для надання юридичної сили простому ЕП необхідно: - Укласти угоду про використання ПЕП (оферта або договір приєднання) - Фіксувати час підписання, IP, User-Agent - Зберігати аудит-лог усіх дій (хто, коли, що підписав) - Використовувати одноразові SMS-коди з обмеженим строком дії - Зберігати SHA-256 хеш документа в момент підписанняЩо входить у реалізацію під ключ
| Етап | Склад робіт | Тривалість |
|---|---|---|
| Аналітика | Вибір типу ЕП, узгодження юридичної схеми | 1 день |
| Проектування | Розробка архітектури, UX підписання | 1–2 дні |
| Реалізація ПЕП | SMS-код, хеш, аудит-лог, сповіщення | 3–4 дні |
| Canvas + PDF-штамп | Візуальний підпис, вбудовування в PDF | +2–3 дні |
| КЕП (СБІС/КриптоПро) | Інтеграція з УЦ, реєстрація підписантів | 5–7 днів |
| Сховище | S3 Object Lock, retention, верифікація | 1–2 дні |
| Документація та передача | API-специфікація, інструкція, навчання | 1 день |
Оцінка точної вартості та термінів — індивідуально після аудиту поточної архітектури. Отримайте консультацію з вибору типу підпису для вашого бізнесу — зв'яжіться з нами.
Чому варто замовити реалізацію у нас
Ми реалізували ЕП для понад 20 проєктів — від fintech-стартапів до держпорталів. Гарантуємо юридичну чистоту та відповідність 63-ФЗ, 149-ФЗ та 152-ФЗ. Передаємо повну документацію та доступ до вихідного коду. Досвід роботи з сертифікованими УЦ (СБІС, КриптоПро, Контур) підтверджено сертифікатами.
Замовте аудит поточної системи підписання — ми знайдемо вразливості та запропонуємо оптимальне рішення.







