Типичная ситуация: вы заключаете договор с контрагентом через электронный документооборот, но он сомневается в подлинности подписи. Или вам нужно предоставить клиентам возможность проверить подписанный документ онлайн. Мы решаем эту задачу: от интеграции простой ЭП до криптографической верификации КЭП через КриптоПро.
Какие проблемы решает система верификации?
Разные типы подписей — разная логика проверки. Простая электронная подпись (рисованная подпись, SMS-код) не несёт криптографической защиты. Единственный способ проверить её подлинность — убедиться, что документ не изменялся после подписания. Для этого мы храним хэш документа (SHA-256) в момент подписания и сравниваем его при верификации. Если хэши не совпадают — документ был изменён, подпись недействительна.
Квалифицированная электронная подпись (КЭП) требует гораздо более сложной проверки. Нужно расшифровать подпись, проверить сертификат, цепочку доверия, срок действия, статус отзыва. Это включает работу с криптопровайдерами (КриптоПро), плагинами браузера или серверными SOAP-вызовами.
Совместимость с браузерами и устройствами. Клиентская верификация КЭП требует установки Browser Plugin, что не всегда возможно (мобильные устройства, корпоративные ограничения). Поэтому мы предлагаем серверную верификацию через КриптоПро Web Service — пользователь просто загружает документ и подпись, а вся криптография выполняется на сервере. Это универсальное решение.
Безопасность и логирование. Важно не только проверить подпись, но и сохранить доказательства проверки. Мы логируем каждую попытку: IP, User-Agent, временную метку, результат. Это защищает от атак повторного воспроизведения и даёт аудиторский след.
Как мы это делаем?
Архитектура решения
- Frontend: React 18 (Next.js 14) для публичной страницы верификации, TypeScript, Tailwind.
- Backend: Laravel 11 (PHP 8.3) или Node.js (Express) для API и серверной верификации.
- База данных: PostgreSQL для хранения хэшей и логов, Redis для кэширования статусов сертификатов.
- Криптография: КриптоПро CSP (серверная верификация через SOAP) и CryptoPro Browser Plugin (клиентская).
Код клиентской верификации КЭП через плагин уже готов и используется в проектах:
async function verifyCadesSignature(documentBase64, 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(documentBase64);
try {
await signedData.VerifyCades(
signatureBase64,
plugin.CADESCOM_CADES_BES,
true
);
} catch (e) {
return { valid: false, error: e.message };
}
const signers = await signedData.Signers;
const signer = await signers.Item(1);
const cert = await signer.Certificate;
return {
valid: true,
signer: {
name: await cert.GetInfo(plugin.CAPICOM_CERT_INFO_SUBJECT_SIMPLE_NAME),
issuer: await cert.GetInfo(plugin.CAPICOM_CERT_INFO_ISSUER_SIMPLE_NAME),
validFrom: await cert.ValidFromDate,
validTo: await cert.ValidToDate,
thumbprint: await cert.Thumbprint,
},
signedAt: await signer.SigningTime,
certValid: await cert.IsValid().Result,
};
}
Серверная верификация через КриптоПро Web Service — пример на PHP:
class CryptoProVerificationService {
public function verifySignature(string $documentBase64, string $signatureBase64): array {
$client = new SoapClient('https://www.cryptopro.ru/ocsp/ocsp.php?wsdl');
$result = $client->VerifyHash([
'Signature' => $signatureBase64,
'Content' => $documentBase64,
'Type' => 'CAdES-BES',
'IsDetached' => true,
]);
return [
'valid' => $result->IsValid,
'signerName' => $result->SignerName,
'signedAt' => $result->SigningTime,
'certSerial' => $result->CertSerialNumber,
];
}
}
Почему серверная верификация лучше для пользователя?
Серверная верификация не требует установки плагинов, работает на любых устройствах и браузерах. Проверка занимает 2-3 секунды — в 2 раза быстрее, чем установка и настройка плагина. Это снижает количество обращений в поддержку и повышает конверсию верификации.
Как публичная страница и QR-код упрощают проверку?
Для внешних пользователей (контрагент проверяет договор) мы создаём страницу без авторизации. Пример компонента на React:
async function VerificationPage({ params }) {
const result = await verifyDocumentSignature(params.documentId, params.signatureId);
return (
<div className="max-w-2xl mx-auto p-8">
<div className={`rounded-xl p-6 ${result.valid ? 'bg-green-50' : 'bg-red-50'}`}>
<div className="flex items-center gap-3">
{result.valid ? <CheckCircleIcon className="text-green-600 w-8" /> : <XCircleIcon className="text-red-600 w-8" />}
<h1 className="text-xl font-bold">
{result.valid ? 'Подпись действительна' : 'Подпись недействительна'}
</h1>
</div>
{result.valid && (
<dl className="mt-4 grid grid-cols-2 gap-4 text-sm">
<div><dt className="text-gray-500">Подписант</dt><dd>{result.signerName}</dd></div>
<div><dt className="text-gray-500">Дата подписания</dt><dd>{formatDate(result.signedAt)}</dd></div>
<div><dt className="text-gray-500">Документ не изменён</dt><dd>Да</dd></div>
<div><dt className="text-gray-500">Сертификат</dt><dd>{result.certSerial}</dd></div>
</dl>
)}
</div>
</div>
);
}
QR-код, размещённый на подписанном документе, ведёт на страницу верификации:
import QRCode from 'qrcode';
const verificationUrl = `${process.env.APP_URL}/verify/${documentId}/${signatureId}`;
const qrDataUrl = await QRCode.toDataURL(verificationUrl, {
width: 100,
margin: 1,
errorCorrectionLevel: 'M',
});
Сравнение методов верификации
| Метод | Скорость проверки | Требования к клиенту | Безопасность | Тип подписи |
|---|---|---|---|---|
| По хэшу документа | Мгновенно | Любой браузер | Средняя (защита от изменений) | Простая ЭП |
| КЭП через плагин | ~1 сек | Установка CryptoPro Browser Plugin | Высокая (криптография) | КЭП |
| КЭП серверная | ~2-3 сек | Нет (SOAP на сервере) | Высокая (криптография) | КЭП |
Процесс работы
- Аналитика — выявляем типы подписей, требования к безопасности, поток пользователей.
- Проектирование — выбираем архитектуру (клиентская/серверная верификация), стек, протоколы.
- Разработка — реализуем API, публичную страницу, QR-код, интеграцию с вашей CRM/ERP.
- Тестирование — проверяем на разных браузерах, с реальными сертификатами, нагрузочное тестирование.
- Деплой — настраиваем CI/CD, мониторинг, кэширование.
- Обучение и поддержка — передаём документацию, доступы, проводим обучение сотрудников. Предоставляем 1 месяц бесплатной поддержки.
Что входит в работу
- Исходный код системы верификации.
- Документация API (OpenAPI/Swagger).
- Инструкция по эксплуатации для администраторов.
- Доступы к репозиторию и серверу.
- 1 месяц поддержки после запуска.
Типичные ошибки при внедрении
- Не проверяется срок действия сертификата — подпись может быть создана просроченным сертификатом. Мы всегда проверяем ValidFrom/ValidTo.
- Отсутствует логирование попыток верификации — сложно доказать, что проверка была выполнена. Мы логируем каждую попытку.
- QR-код ведёт на HTTP, а не HTTPS — данные подписи передаются в открытом виде. Мы используем только HTTPS с HSTS.
- Не настроен CORS — публичная страница не загружается из-за ограничений браузера. Мы правильно конфигурируем заголовки.
Сроки
Верификация по хэшу с публичной страницей и QR-кодом — 2–3 дня. Верификация КЭП через браузерный плагин — 3–4 дня. Серверная верификация через КриптоПро Web Service — 3–5 дней. Точную оценку дадим после аудита вашего проекта.
Свяжитесь с нами, чтобы обсудить детали. Закажите разработку системы верификации подписи — оценим проект в течение одного рабочего дня.







