Реализация электронного подписания документов
Недавно к нам обратился 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 день |
Оценка точной стоимости и сроков — индивидуально после аудита текущей архитектуры. Получите консультацию по выбору типа подписи для вашего бизнеса — свяжитесь с нами.
Почему стоит заказать реализацию у нас
За 7 лет мы реализовали ЭП для 20+ проектов — от финтех-стартапов до госпорталов. Гарантируем юридическую чистоту и соответствие 63-ФЗ, 149-ФЗ и 152-ФЗ. Передаём полную документацию и доступ к исходному коду. Опыт работы с сертифицированными УЦ (СБИС, КриптоПро, Контур) подтверждён сертификатами.
Закажите аудит текущей системы подписания — мы найдём уязвимости и предложим оптимальное решение.







