Пытаюсь реализовать взаимодействие с ЕСИА. Вроде бы всё работает нормально, но напрягает то, что взаимодействие происходит с доступным веб-серверу файлом приватного ключа.
Есть подозрение, что у OpenSSL есть своё закрытое хранилище ключей, тем более, что она умеет использовать аппаратные ключи для шифрования где приватный ключ и вовсе недоступен программно.
Есть ли возможность скрыть приватный ключ от веб-сервера?
Для примера, реализация функции для подписи PKCS7:
private function signPKCS7($message) {
$this->checkFilesExists();
$certContent = file_get_contents($this->certPath);
$keyContent = file_get_contents($this->privateKeyPath);
$cert = openssl_x509_read($certContent);
if ($cert === false) {
throw new Exception('Ошибка чтения сертификата '.$this->certPath);
}
#$this->writeLog('Cert: ' . print_r($cert, true));
$privateKey = openssl_pkey_get_private($keyContent, $this->privateKeyPassword);
if ($privateKey === false) {
throw new Exception('Ошибка чтения приватного ключа '.$this->privateKeyPath);
}
$messageFile=TMP_PATH.DIRECTORY_SEPARATOR.uniqid();
$signFile=TMP_PATH.DIRECTORY_SEPARATOR.uniqid();
try {
file_put_contents($messageFile, $message);
$signResult = openssl_pkcs7_sign(
$messageFile,
$signFile,
$cert,
$privateKey,
[]
);
if (!$signResult) {
throw new SignFailException('SSH error: ' . openssl_error_string());
}
$signed = file_get_contents($signFile);
$signed = explode("\n\n", $signed);
$sign = str_replace("\n", "", $this->urlSafe($signed[3]));
} finally {
unlink($signFile);
unlink($messageFile);
}
return $sign;
}
$this->certPath - путь к сертификату
$this->privateKeyPath - путь к закрытому ключу (приходится давать полный путь к файлу)
$this->privateKeyPassword - пароль закрытого ключа
В случае получения доступа к веб-серверу злоумышленик без проблем сможет скопировать файл с ключом.