← Назад к вопросам
Как работает под капотом плагин КриптоПро?
1.8 Middle🔥 111 комментариев
#Soft Skills и рабочие процессы
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
КриптоПро плагин: архитектура и работа
КриптоПро - это российское ПО для работы с электронной подписью и шифрованием. Расскажу как он интегрируется с браузером и как с ним работать на фронтенде.
Что такое КриптоПро
КриптоПро CSP (Cryptography Service Provider) - это криптографический модуль российского производства, основанный на ГОСТ.
// КриптоПро предоставляет:
const cryptoPro = {
// Криптографические функции
hashing: 'SHA256, GOST 34.11-94, GOST 34.11-2012',
// Работа с сертификатами
certificates: 'Хранение, получение, работа с ключами',
// Электронная подпись
digitalSignature: 'Подпись документов, проверка подписей',
// Шифрование
encryption: 'Шифрование данных',
// Работа с ключами
keyManagement: 'Управление ключами в токене/контейнере'
};
Архитектура интеграции
// Слои архитектуры
const architecture = {
// Слой 1: Браузер
browser: {
javascript: 'Ваш код на JavaScript',
api: 'CadespluginAPI или CADESCOM API'
},
// Слой 2: NPAPI плагин (старый подход) или ActiveX (IE)
plugin: {
npapi: 'Netscape Plugin API',
activex: 'Microsoft ActiveX (только IE)'
},
// Слой 3: WebSocket или TCP socket
communication: 'Локальное соединение с демоном КриптоПро',
// Слой 4: КриптоПро демон
daemon: {
service: 'cryptopro.service или cadesplugin.service',
port: 13579, // Порт по умолчанию
functionality: 'Работа с сертификатами, подпись, шифрование'
},
// Слой 5: ОС и аппаратура
os: {
hsm: 'Аппаратные токены (рутокены)',
smartCard: 'Смарт-карты',
storage: 'Локальное хранилище сертификатов'
}
};
Инициализация плагина в браузере
// 1. Проверить доступность плагина
const checkCryptoPro = async () => {
try {
// Способ 1: КриптоПро 4.0+ (современный)
if (window.cadesplugin) {
console.log('Cadesplugin API доступен');
return true;
}
// Способ 2: Старый NPAPI плагин
if (navigator.plugins['CryptoPro']) {
console.log('NPAPI плагин доступен');
return true;
}
// Способ 3: ActiveX (только IE)
if (new ActiveXObject('CadespluginLocalObj.CadesSigner')) {
console.log('ActiveX доступен');
return true;
}
} catch (error) {
console.error('КриптоПро не установлен');
return false;
}
};
// 2. Инициализировать
const initCryptoPro = async () => {
if (!window.cadesplugin) {
console.error('Плагин не загружен');
return;
}
// Активировать плагин
window.cadesplugin.async_spawn((api) => {
// api - асинхронный API
console.log('Плагин инициализирован');
});
};
Получение сертификатов
const getCertificates = async () => {
return new Promise((resolve, reject) => {
// Используем асинхронный API
window.cadesplugin.async_spawn((api) => {
try {
// Получить хранилище сертификатов
const store = api.CreateObject('CAdESCOM.Store');
// Открыть хранилище текущего пользователя
store.Open(
api.CADESCOM_STORE_PROVIDER_TYPE.CADESCOM_PROVIDER_RSA_FULL,
api.CADESCOM_STORE_LOCATION_TYPE.CADESCOM_CURRENT_USER,
api.CADESCOM_STORE_OPEN_MODE.CADESCOM_STORE_OPEN_EXISTING_ONLY
);
// Получить сертификаты
const certs = store.Certificates;
const certArray = [];
for (let i = 1; i <= certs.Count; i++) {
const cert = certs.Item(i);
certArray.push({
thumbprint: cert.Thumbprint,
subjectName: cert.SubjectName,
issuerName: cert.IssuerName,
validFrom: cert.ValidFromDate,
validTo: cert.ValidToDate,
publicKey: cert.PublicKey(),
hasPrivateKey: cert.HasPrivateKey
});
}
resolve(certArray);
} catch (error) {
reject(new Error(`Ошибка получения сертификатов: ${error.message}`));
}
});
});
};
// Использование
const certs = await getCertificates();
certs.forEach(cert => {
console.log(`${cert.subjectName} (до ${cert.validTo})`);
});
Подпись документа
const signDocument = async (data, thumbprint) => {
return new Promise((resolve, reject) => {
window.cadesplugin.async_spawn((api) => {
try {
// 1. Получить сертификат по отпечатку
const store = api.CreateObject('CAdESCOM.Store');
store.Open(
api.CADESCOM_STORE_PROVIDER_TYPE.CADESCOM_PROVIDER_RSA_FULL,
api.CADESCOM_STORE_LOCATION_TYPE.CADESCOM_CURRENT_USER,
api.CADESCOM_STORE_OPEN_MODE.CADESCOM_STORE_OPEN_EXISTING_ONLY
);
const certs = store.Certificates;
let signingCert = null;
for (let i = 1; i <= certs.Count; i++) {
const cert = certs.Item(i);
if (cert.Thumbprint === thumbprint) {
signingCert = cert;
break;
}
}
if (!signingCert) {
reject(new Error('Сертификат не найден'));
return;
}
// 2. Создать объект для подписи
const signer = api.CreateObject('CAdESCOM.CadesSigner');
signer.Certificate = signingCert;
// 3. Установить параметры подписи
signer.TSAAddress = 'http://timestamp.cryptopro.ru'; // Временная метка
signer.SigningAlgorithm = api.CADESCOM_ENCRYPTION_ALGORITHM.CADESCOM_ENCRYPTION_ALGORITHM_RSA_PSS;
signer.HashAlgorithm = api.CADESCOM_HASH_ALGORITHM.CADESCOM_HASH_ALGORITHM_SHA256;
// 4. Подписать данные
const cadesSignedData = api.CreateObject('CAdESCOM.CadesSignedData');
cadesSignedData.ContentEncoding = api.CADESCOM_BASE64_TO_BINARY;
cadesSignedData.Content = data; // Base64 строка данных
// CAdES-BES формат (Basic Electronic Signature)
const signature = cadesSignedData.SignCades(
signer,
api.CADESCOM_CADES_TYPE.CADESCOM_CADES_BES
);
resolve(signature);
} catch (error) {
reject(new Error(`Ошибка подписи: ${error.message}`));
}
});
});
};
// Использование
const documentData = btoa('Hello World'); // Base64 encoded
const selectedCertThumbprint = 'ABC123...';
const signature = await signDocument(documentData, selectedCertThumbprint);
console.log('Подпись:', signature);
Проверка подписи
const verifySignature = async (signature) => {
return new Promise((resolve, reject) => {
window.cadesplugin.async_spawn((api) => {
try {
const cadesSignedData = api.CreateObject('CAdESCOM.CadesSignedData');
cadesSignedData.ContentEncoding = api.CADESCOM_BASE64_TO_BINARY;
cadesSignedData.Content = signature;
// Проверить подпись
const signers = cadesSignedData.Signers;
if (signers.Count === 0) {
reject(new Error('В подписи нет подписантов'));
return;
}
const signer = signers.Item(1);
const cert = signer.Certificate;
// Проверить сертификат
const isValid = cadesSignedData.VerifyCades(
signature,
api.CADESCOM_CADES_TYPE.CADESCOM_CADES_BES,
true // checkChain
);
resolve({
isValid: isValid,
signerName: cert.SubjectName,
signingTime: signer.SigningTime
});
} catch (error) {
reject(new Error(`Ошибка проверки: ${error.message}`));
}
});
});
};
Обработка ошибок и статусы
const cryptoProStatuses = {
NOT_INSTALLED: 'КриптоПро не установлен',
NOT_RUNNING: 'Демон КриптоПро не запущен',
NO_CERTIFICATES: 'Сертификаты не установлены',
PLUGIN_ERROR: 'Ошибка плагина',
NO_PIN_CODE: 'Необходимо ввести PIN-код (для токена)',
USER_CANCELLED: 'Пользователь отменил операцию',
INVALID_SIGNATURE: 'Подпись невалидна',
EXPIRED_CERTIFICATE: 'Сертификат истёк'
};
// Обработка ошибок
const safeSignDocument = async (data, thumbprint) => {
try {
const signature = await signDocument(data, thumbprint);
return { success: true, signature };
} catch (error) {
const errorMessage = error.message;
if (errorMessage.includes('plugin is not available')) {
return { success: false, error: cryptoProStatuses.NOT_INSTALLED };
} else if (errorMessage.includes('pin')) {
return { success: false, error: cryptoProStatuses.NO_PIN_CODE };
} else {
return { success: false, error: errorMessage };
}
}
};
Интеграция в веб-приложение
// React компонент для подписи
function DocumentSigner({ document }) {
const [certificates, setCertificates] = useState([]);
const [selectedCert, setSelectedCert] = useState(null);
const [signature, setSignature] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
useEffect(() => {
const loadCerts = async () => {
try {
setLoading(true);
const certs = await getCertificates();
setCertificates(certs);
} catch (err) {
setError('Не удалось загрузить сертификаты: ' + err.message);
} finally {
setLoading(false);
}
};
loadCerts();
}, []);
const handleSign = async () => {
if (!selectedCert) {
setError('Выберите сертификат');
return;
}
try {
setLoading(true);
const docBase64 = btoa(JSON.stringify(document));
const sig = await signDocument(docBase64, selectedCert.thumbprint);
setSignature(sig);
setError(null);
} catch (err) {
setError('Ошибка подписи: ' + err.message);
} finally {
setLoading(false);
}
};
return (
<div>
<select onChange={(e) => setSelectedCert(
certificates.find(c => c.thumbprint === e.target.value)
)}>
<option>Выберите сертификат</option>
{certificates.map(cert => (
<option key={cert.thumbprint} value={cert.thumbprint}>
{cert.subjectName}
</option>
))}
</select>
<button onClick={handleSign} disabled={loading || !selectedCert}>
{loading ? 'Подписание...' : 'Подписать'}
</button>
{error && <div className="error">{error}</div>}
{signature && <div className="signature">Подпись получена</div>}
</div>
);
}
Выводы
- Архитектура: браузер -> плагин -> демон КриптоПро -> ОС
- API: используй cadesplugin.async_spawn для асинхронных операций
- Сертификаты: хранятся локально, плагин предоставляет доступ
- Подпись: CAdES-BES формат с временной меткой
- Безопасность: приватный ключ никогда не покидает локальное хранилище
- Совместимость: нужно проверять наличие плагина перед использованием
- Ошибки: обработать случаи когда плагин не установлен или демон не запущен