Информация о статусе сервера обновлена только что.
Проверить снова
Что делать, если сайт недоступен?
Vologda.k-vrachu.ru не работает сегодня январь 2023?
Узнайте, работает ли Vologda.k-vrachu.ru в нормальном режиме или есть проблемы сегодня
Статус Vologda.k-vrachu.ru : нет сбоя
7 комментариев
Vologda.k-vrachu.ru сбои за последние 24 часа
Не работает Vologda.k-vrachu.ru?
Не открывается, не грузится, не доступен, лежит или глючит?
Самые частые проблемы Vologda.k-vrachu.ru
Что делать, если сайт VOLOGDA.K-VRACHU.RU недоступен?
Если VOLOGDA.K-VRACHU.RU работает, однако вы не можете получить доступ к сайту или отдельной его странице, попробуйте одно из возможных решений:
Кэш браузера.
Чтобы удалить кэш и получить актуальную версию страницы, обновите в браузере страницу с помощью комбинации клавиш Ctrl + F5.
Блокировка доступа к сайту.
Очистите файлы cookie браузера и смените IP-адрес компьютера.
Антивирус и файрвол.
Проверьте, чтобы антивирусные программы (McAfee, Kaspersky Antivirus или аналог) или файрвол, установленные на ваш компьютер — не блокировали доступ к VOLOGDA.K-VRACHU.RU.
DNS-кэш.
Очистите DNS-кэш на вашем компьютере и повторите попытку доступа на сайт.
Смотреть видео-инструкцию ↓
VPN и альтернативные службы DNS.
VPN: например, мы рекомендуем NordVPN.
Альтернативные DNS: OpenDNS или Google Public DNS.
Плагины браузера.
Например, расширение AdBlock вместе с рекламой может блокировать содержимое сайта. Найдите и отключите похожие плагины для исследуемого вами сайта.
Сбой драйвера микрофона
Быстро проверить микрофон: Тест Микрофона.
Форум Vologda.k-vrachu.ru
Подсказки? Разочарования? Обсуждаем проблемы сервиса с другими посетителями сайта:
Чат с регистрацией
идентификация не требуется
комментарии с нецензурной лексикой и оскорблениями удаляются
Ирина
•
319 дней назад
#
18 марта 2022
+
0
—
То же самое! Ошибка формирования подписи для обращения к ЕСИА. , Неверная настройка сервера. А сначала не приходили уведомления о свободной бирке. Пробовала написать в обратную связь — не работает
Гость
•
327 дней назад
#
10 марта 2022
+
0
—
★
☆
☆
☆
☆
Не могу записаться к врачу стоматологу .Это сбой программы или я что-то делаю не правильно?
Наталья.
•
434 дней назад
#
23 ноября 2021
+
0
—
К сожалению, и сегодня всё грустно… Ошибка формирования подписи для обращения к ЕСИА. Неверная настройка сервера.
Владимир
•
435 дней назад
#
22 ноября 2021
+
0
—
Это позор какой-то…
Галина
•
435 дней назад
#
22 ноября 2021
+
0
—
Ошибка таже. Уже третий день
Елена
•
435 дней назад
#
+
-1
—
То же самое! Ошибка формирования подписи для обращения к ЕСИА. , Неверная настройка сервера
Юлия
•
509 дней назад
#
+
0
—
То же самое! Ошибка формирования подписи для обращения к ЕСИА. , Неверная настройка сервера.
Предисловие
Передо мной стояла задача по интеграции нашего сервиса с госуслугами. Казалось ничего сложного не предстоит, но учитывая что наш сервис базируется на технологии ASP.NET всё было не так оптимистично. В начале были поиски.. много поисков, которые привели к множеству разрозненной и чаще всего неактуальной информации. Так же были найдены уже готовые решения, но как заявляли некоторые товарищи на форумах за такое могут и по головке погладить. Поэтому было решено писать самому.
Эта статья скорее больше актуализация и дополнение информации из этой статьи.

Введение
На сайте Минцифр есть методичка максимально раздутая и очень запутанная, но пользоваться ею нам всё равно придётся. Мы будем работать с ЕСИА версии 3.11 (актуальная на момент написания статьи). Кратко наши действия заключаются вот в чем:
-
Регистрация ИС в регистре информационных систем ЕСИА
-
Регистрация ИС в тестовой среде
-
Выполнение доработки системы для взаимодействия с ЕСИА
Звучит довольно просто, но каждый шаг целая отдельная история приключений. Регистрация ИС в ЕСИА приключение для бюрократа. Поэтому в этой статье мы немного посмотрим на второй шаг, и детально распишем реализацию.
Содержание
-
Настройка ИС
-
Сертификаты ИС
-
Получаем client_certificate_hash
-
Формирование client_secret
-
Собираем ссылку для авторизации в Госуслугах
-
Получение токена доступа
-
Проверка токена
-
Получение данных пользователя из ЕСИА
Всё необходимое
Минцифры требуют использование сертифицированного ПО для криптографии. Поэтому мы будем использовать КриптоПРО CSP + КриптоПРО .Net + КриптоПРО .NetSDK. Всё это можно скачать с офф. сайта КриптоПРО. На время разработки лучше использовать триал версию.
Наш инвентарь для путешествия:
-
КриптоПРО CSP
-
КриптоПРО .Net
-
КриптоПРО .NetSDK
-
Контейнер закрытого ключа с сертификатом нашей организации
-
Много терпения
Немного о КриптоПРО CSP + .Net Core 5+
Вот тут и начинаются первые проблемы. На момент написания статьи у КриптоПРО .Net нет поддержки .Net Core 5 и выше. Есть сборка под .Net Core 3.1 но и она выглядит сомнительно. Поэтому было решено поднять сервис для .Net Framework 4.8 который будет использовать средства КриптоПРО CSP для подписания с использованием ЭЦП, а так же проверки ответов от ЕСИА.
Немного о контейнере закрытого ключа и сертификата
Когда мы начинали делать эту задачу у нас была КЭП на токене, но как оказалось на нём был неэкспортируемый контейнер. Скажу сразу, что экспортировать контейнер с такого токена запрещено ФНС. Поэтому необходимо заранее получить токен на имя сотрудника с экспортируемым контейнером. Так как его необходимо будет скопировать на сервер.
Приступаем
Начнём с того, что вы уже отправили заявку регистрации ИС в ЕСИА и её приняли. А так же отправили заявка на тестовую среду. Приступим к этапу настройки ИС в тестовом кабинете электронного правительства. Вот ссылка на тестовую страницу. Логинимся под тестовой учетной записью тестового пользователя 006(все данные лежат в приложении к работе с тестовой средой), так как он имеет доступ к управлением ИС.

Здесь ищем нашу систему по Мнемонике или полному названию, если таковой нет то создаём. Напротив нашей системы есть две кнопки:
Первая кнопка — изменить нашу ИС (информация о ИС, редиректы и тд)
Вторая кнопка — наши сертификаты с помощью которых мы подписываем сообщения в ЕСИА

Настройка ИС
Есть важный момент в настройки ИС. Это URL системы. Тут мы указываем ссылки куда ЕСИА может делать переадресацию при запросе от нашей ИС. На эти точки будет приходить авторизационный код (Если он указан в запросе).

Сертификаты ИС

Здесь мы можем загрузить наш сертификаты или же удалить их. Есть один важный момент, каждая ИС может иметь только один уникальный сертификат. А связи с тем, что на тестовой среде все системы регистрируются под одним пользователем и сертификаты тестовые одни на всех часта такая ситуация, что кто-то удаляет у вас сертификат и загружает к себе. А ваши запросы теперь падают с ошибкой) Но если у вас уже готов ЭЦП на сотудника, то лучше используйте её.
Реализуем
Мы закончили с настройки нашей ИС и можем приступить к реализации. Надеюсь вы уже установили КриптоПРО и всё необходимое для него. Если нет, я подожду…
Устанавливаем сертификаты
Такс~ Всё готово. Качаем сертификаты по ссылке из методички. Специально не буду вставлять, так как может измениться.

Здесь нам интересен сертификат ТЕСИА ГОСТ 2012.cer — это сертификат с помощью которого ЕСИА подписывает сообщения отправляя в нашу ИС. (Соответственно для продуктовой среды свой сертификат). Устанавливаем сертификат как доверенный. Здесь ничего сложного думаю разберётесь.

Теперь устанавливаем тестовый контейнер и сертификат. Для примера будем использовать предоставленные ЕСИА контейнеры, но вы можете использовать свои. Всё это лежит внутри архива.


В архиве лежит папка d1f73ca5.000 — это контейнер нам необходимо его переместить по пути C:UsersUserAppDataLocalCrypto Pro

Теперь открываем КриптоПРО CSP. Выбираем установить личный сертификат и указываем Тестовое ведомство Фамилия006 ИО.cer и нажимаем найти автоматически. Выполняем оставшиеся шаги сами.
Механизм подписания
Пожалуй начинается самая важная и самая запутанная часть всего пути. Здесь мы реализуем сервис для работы с подписью. И так делаю выжимку из методических материалов, чтобы Вам не пришлось читать много текста.
Для получения авторизационный ссылки — ссылка на которую мы будем переадресовывать пользователя для авторизации в ЕСИА. Нам необходимо собрать ссылку из параметров.
-
client_id— наша Мнемоника -
client_secret— Отсоединённая подпись от параметров запроса в кодировке UTF-8 -
redirect_uri— ссылка на которую ЕСИА будет переадресовывать пользователя вместе с авторизационным кодом -
scope— перечень запрашиваемой информации. Напримерfullname birthdate gender -
response_type— тип ответа от ЕСИА, в нашем случае это просто строчкаcode -
state— Идентификатор текущего запроса. Генерируется таким образомGuid.NewGuid().ToString("D"); -
timestamp— время запроса авторизационного кода в формате yyyy.MM.dd HH:mm:ss Z. Генерируется таким образомDateTime.UtcNow.ToString("yyyy.MM.dd HH:mm:ss +0000"); -
client_certificate_hash— это fingerprint сертификата в HEX-формате.
Обозначили наш зоопарк. Самый важный зверь здесь client_secret
Получаем client_certificate_hash
В методическом указании от Минцифр есть ссылка на специальную утилиту с помощью которой мы можем получить этот хэш. Разархивировали архив и видим перед нами sh. Windows пользователи не пугаемся, на самом деле тут же лежит .exe файл. Чтобы вычислить хэш нашего сертификат просто необходимо из cmd запустить вот такой скрипт:
cpverify.exe test.cer -mk -alg GR3411_2012_256 -inverted_halfbytes 0
Формирование client_secret
Такс перед тем как просто получит client_secret нам необходимо сделать:
-
ASP.Net Framework 4.8 WebAPI — тот самый сервис который будет работать с КриптоПРО CSP
Пропустим множество шагов создания этого сервиса и перейдём сразу к его настройки для работы с КриптоПРО CSP.
Настройка сервиса для работы с КриптоПРО CSP
Добавляем ссылки на DLL КриптоПРО.
Переходим по пути C:Program Files (x86)Crypto Pro.NET SDKAssemblies4.0
Выбираем всё что нам нужно. (подробная информация)

Теперь мы имеем доступ к API КриптоПРО CSP из кода .Net Framework
Теперь создаём контроллер:
Код контроллера
Итак нам необходимо получать строку для подписания. Создадим метод
const string CertSerialNumber = "01f290e7008caed0904b967783fd0e4ad6";
const string EsiaCertSerialNumber = "0125657e00a1ae59804d92116214e53466";
[HttpGet]
public string Get(string msg)
{
msg = Base64UrlEncoder.Decode(msg);
var data = Encoding.UTF8.GetBytes(msg);
var client_secret = Sign(data);
return client_secret;
}
Мы заранее укажем константами серийные номера сертификатов.
В методе Get получаем строку в Base64Url формате, чтобы спокойно передавать наши длинные сообщения.
Декодируем строку из Base64Url в текст. После чего переводим текст в байты используя UTF-8. А теперь подписываем.
string Sign(byte[] data)
{
var gost3411 = new Gost3411_2012_256CryptoServiceProvider();
var hashValue = gost3411.ComputeHash(data);
gost3411.Clear();
var signerCert = GetSignerCert();
var SignedHashValue = GostSignHash(hashValue,
signerCert.PrivateKey as Gost3410_2012_256CryptoServiceProvider, "Gost3411_2012_256");
var client_secret = Base64UrlEncoder.Encode(SignedHashValue);
return client_secret;
}
И так что мы тут делаем. С помощью ГОСТ 34.11-2012 мы вычисляем хэш нашего сообщения. И используя полученный сертификат подписываем сообщение.
X509Certificate2 GetSignerCert()
{
var store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);
var certificates = store.Certificates.Find(X509FindType.FindBySerialNumber, CertSerialNumber, false);
if (certificates.Count != 1)
{
return null;
}
var certificate = certificates[0];
if (certificate.PrivateKey == null)
{
return null;
}
return certificate;
}
Здесь мы открываем наш склад с контейнерами и ищем именно тот где лежит наш сертификат. После чего извлекаем из него сертификат.
byte[] GostSignHash(byte[] HashToSign, Gost3410_2012_256CryptoServiceProvider key, string HashAlg)
{
try
{
//Создаем форматтер подписи с закрытым ключом из переданного
//функции криптопровайдера.
var Formatter = new Gost2012_256SignatureFormatter(
(Gost3410_2012_256CryptoServiceProvider) key);
//Устанавливаем хэш-алгоритм.
Formatter.SetHashAlgorithm(HashAlg);
//Создаем подпись для HashValue и возвращаем ее.
return Formatter.CreateSignature(HashToSign);
}
catch (CryptographicException e)
{
Console.WriteLine(e.Message);
return null;
}
}
С помощью этого кода как раз и создаётся наша подпись на хэш строки. Здесь используется ГОСТ 34.10-2012.
Итак контроллер готов. Теперь переходим в наш основной проект на .Net Core
Создаём строку подписания. Просто выполняем конкатенацию параметры без разделителей. Здесь я использую IOptions чтобы брать параметры из appsettings.json.
var msg = $"{esiaSettings.Value.ClientId}{esiaSettings.Value.Scope}{timestamp}{state}{redirectUri}";
Мы получил строку для подписания. Теперь нам необходимо эту строку закодировать в Base64Url и отправляем её на подписание в написанный нами заранее сервис
private string GetClientSecret(string msg){
var client = new HttpClient();
var msgBase64 = Base64UrlEncoder.Encode(msg);
var response = await client.GetAsync($"{cryptoProSettings.Value.BaseUrl}/Get?msg={msgBase64}");
var clientSecret = await response.Content.ReadAsStringAsync();
clientSecret = JsonConvert.DeserializeObject<string>(clientSecret);
return clientSecret;
}
Собираем ссылку для авторизации в Госуслугах
Наконец-то мы получили этот долгожданный секрет. Но вы могли бы подумать это всё, дальше всё просто и ясно. Не тут то было! Дело в том, что ЕСИА требует Base64 Url Safe кодироку. И она немного отличается от Base64Url кодировки доступной из коробки .Net
Итак дело за малым, собираем нашего гомункула из секрета и параметров.
Класс помощник для сборки ссылки
Возможно излишне, но мне понравился метод сбора вот таким способом.
public class RequestBuilder
{
List<RequesItemClass> items = new List<RequesItemClass>();
public void AddParam(string name, string value)
{
items.Add(new RequesItemClass { name = name, value = value });
}
public override string ToString()
{
return string.Join("&", items.Select(a => a.name + "=" + a.value));
}
}
public class RequesItemClass
{
public string name;
public string value;
}
Код сборки ссылки
async Task<string> UrlBuild(string redirectUri)
{
using var client = new HttpClient();
var timestamp = DateTime.UtcNow.ToString("yyyy.MM.dd HH:mm:ss +0000");
var state = Guid.NewGuid().ToString("D");
var msg = $"{esiaSettings.Value.ClientId}{esiaSettings.Value.Scope}{timestamp}{state}{redirectUri}";
var clientSecret = await GetClientSecret(msg);
var builder = new RequestBuilder();
builder.AddParam("client_secret", clientSecret);
builder.AddParam("client_id", esiaSettings.Value.ClientId);
builder.AddParam("scope", esiaSettings.Value.Scope);
builder.AddParam("timestamp", timestamp);
builder.AddParam("state", state);
builder.AddParam("redirect_uri", redirectUri);
builder.AddParam("client_certificate_hash", esiaSettings.Value.ClientCertificateHash);
builder.AddParam("response_type", "code");
builder.AddParam("access_type", "online");
//Вот тут самый важный момент на который было потрачено множество времени. Просто заменяем символы на безопасные
var url = esiaSettings.Value.EsiaAuthUrl + "?" + builder.ToString().Replace("+", "%2B")
.Replace(":", "%3A")
.Replace(" ", "+");
return url;
}
Получаем ссылку на подобии вот такой:
Здесь https://esia-portal1.test.gosuslugi.ru/aas/oauth2/v2/ac ссылка на конечную точку получения авторизационно кода, указана в методическом материале.
https://esia-portal1.test.gosuslugi.ru/aas/oauth2/v2/ac?client_secret=v_c33_-LpkyKJbopTEYqBMbGZrBy9r9u1pzbRmMLNlJPcBnPTJj6Xx5DuxXba3EZZoXdMsb0YIwPDCoF0dfYjQ&client_id=MEMONIKA&scope=fullname+birthdate+gender×tamp=2022.12.23+16%3A37%3A45+%2B0000&state=3a19c4d7-594b-496f-aa6e-970c75a925a4&redirect_uri=https%3A//api.site/users/esia&client_certificate_hash=EED1079A4FF154E117EAA196DCB551930807825DE1DE15EAF7607F354BA47423&response_type=code&access_type=online
Теперь перенаправляем пользователя по этой ссылке и ожидаем пока он авторизуется. После авторизации ЕСИА переадресует его на нашу ссылку и отправит туда в виде аргументов авторизационный код и state.
Получение токена доступа
Теперь время получить токен взамен на авторизационный код.
Метод для получение токена
public async Task<EsiaAuthToken> GetToken(string authorizationCode, string redirectUrl)
{
var timestamp = DateTime.UtcNow.ToString("yyyy.MM.dd HH:mm:ss +0000");
var state = Guid.NewGuid().ToString("D");
var msg =
$"{esiaSettings.Value.ClientId}{esiaSettings.Value.Scope}{timestamp}{state}{redirectUrl}{authorizationCode}";
var clientSecret = await GetClientSecret(msg);
var requestParams = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("client_id", esiaSettings.Value.ClientId),
new KeyValuePair<string, string>("code", authorizationCode), //Здесь мы передаём полученный код
new KeyValuePair<string, string>("grant_type", "authorization_code"), //Просто указываем тип
new KeyValuePair<string, string>("state", state),
new KeyValuePair<string, string>("scope", esiaSettings.Value.Scope),
new KeyValuePair<string, string>("timestamp", timestamp),
new KeyValuePair<string, string>("token_type", "Bearer"), //Какой токен мы хотим получить
new KeyValuePair<string, string>("client_secret", clientSecret),
new KeyValuePair<string, string>("redirect_uri", redirectUrl),
new KeyValuePair<string, string>("client_certificate_hash", esiaSettings.Value.ClientCertificateHash)
};
using var client = new HttpClient();
using var response = await client.PostAsync(esiaSettings.Value.EsiaTokenUrl,
new FormUrlEncodedContent(requestParams));
response.EnsureSuccessStatusCode();
var tokenResponse = await response.Content.ReadAsStringAsync();
var token = JsonConvert.DeserializeObject<EsiaAuthToken>(tokenResponse);
if (!await ValidatingAccessToken(token))
{
throw new Exception("Ошибка проверки маркера индентификации");
}
return token;
}
Тут всё простенько, снова генерируем client_secret указываем остальные параметры и отправляем запрос в ЕСИА на получение токена. Тестовый Uri https://esia-portal1.test.gosuslugi.ru/aas/oauth2/v3/te
Класс токена
public class EsiaAuthToken
{
/// <summary>
/// Токен доступа
/// </summary>
[JsonProperty("access_token")]
public string AccessToken { get; set; }
/// <summary>
/// Идентификатор запроса
/// </summary>
public string State { get; set; }
string[] parts => AccessToken.Split('.');
/// <summary>
/// Хранилище данных в токене
/// </summary>
public EsiaAuthTokenPayload Payload
{
get
{
if (string.IsNullOrEmpty(AccessToken))
{
return null;
}
if (parts.Length < 2)
{
throw new Exception($"При расшифровке токена доступа произошла ошибка. Токен: {AccessToken}");
}
var payload = Encoding.UTF8.GetString(Base64UrlEncoder.DecodeBytes(parts[1]));
return JsonConvert.DeserializeObject<EsiaAuthTokenPayload>(payload);
}
}
/// <summary>
/// Сообщение для проверки подписи
/// </summary>
[Newtonsoft.Json.JsonIgnore]
public string Message
{
get
{
if (string.IsNullOrEmpty(AccessToken))
{
return null;
}
if (parts.Length < 2)
{
throw new Exception($"При расшифровке токена доступа произошла ошибка. Токен: {AccessToken}");
}
return parts[0] + "." + parts[1];
}
}
/// <summary>
/// Сигнатура подписи
/// </summary>
[Newtonsoft.Json.JsonIgnore]
public string Signature
{
get
{
if (string.IsNullOrEmpty(AccessToken))
{
return null;
}
if (parts.Length < 2)
{
throw new Exception($"При расшифровке токена доступа произошла ошибка. Токен: {AccessToken}");
}
return parts[2];
}
}
public class EsiaAuthTokenPayload
{
[JsonConstructor]
public EsiaAuthTokenPayload(string tokenId, string userId, string nbf, string exp, string iat, string iss,
string client_id)
{
TokenId = tokenId;
UserId = userId;
BeginDate = EsiaHelper.DateFromUnixSeconds(double.Parse(nbf));
ExpireDate = EsiaHelper.DateFromUnixSeconds(double.Parse(exp));
CreateDate = EsiaHelper.DateFromUnixSeconds(double.Parse(iat));
Iss = iss;
ClientId = client_id;
}
/// <summary>
/// Идентификатор токена
/// </summary>
[JsonProperty("urn:esia:sid")]
public string TokenId { get; private set; }
/// <summary>
/// Идентификатор пользователя
/// </summary>
[JsonProperty("urn:esia:sbj_id")]
public string UserId { get; private set; }
/// <summary>
/// Время начала действия токена
/// </summary>
[JsonPropertyName("nbf")]
public DateTime BeginDate { get; private set; }
/// <summary>
/// Время окончания действия токена
/// </summary>
[JsonPropertyName("exp")]
public DateTime ExpireDate { get; private set; }
/// <summary>
/// Время выпуска токена
/// </summary>
[JsonPropertyName("iat")]
public DateTime CreateDate { get; private set; }
/// <summary>
/// Организация, выпустившая маркер
/// </summary>
[JsonPropertyName("iss")]
public string Iss { get; private set; }
/// <summary>
/// Адресат маркера
/// </summary>
[JsonPropertyName("client_id")]
public string ClientId { get; private set; }
}
}
public static class EsiaHelper
{
public static DateTime DateFromUnixSeconds(double seconds)
{
var date = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
return date.AddSeconds(seconds).ToLocalTime();
}
}
Проверка токена
Итак помимо того, что нам нужно получить токен, нам так же необходимо проверить его.
Сам токен состоит из 3 частей.
1 часть — заголовок JWT токена
2 часть — payload токена, там вся основная информация о токене
3 часть — RAW подпись в формате UTF-8
Код конечной точки для проверки подписи
[HttpPost]
public bool Verify(VerifyMessage message)
{
try
{
return VerifyRawSignString(message.Message, message.Signature);
}
catch (Exception ex)
{
return false;
}
}
public class VerifyMessage
{
public string Signature { get; set; }
public string Message { get; set; }
}
Код проверки подписи на нашем сервисе
/// <summary>
/// Проверка подписи JWT в формате HEADER.PAYLOAD.SIGNATURE.
/// </summary>
/// <param name="message">HEADER.PAYLOAD в формате Base64url</param>
/// <param name="signature">SIGNATURE в формате Base64url</param>
bool VerifyRawSignString(string message, string signature)
{
var signerCert = GetEsiaSignerCert();
var messageBytes = Encoding.UTF8.GetBytes(message);
var signatureBytes = Base64UrlEncoder.DecodeBytes(signature);
//Переварачиваем байты, так как используется RAW подпись
Array.Reverse(signatureBytes, 0, signatureBytes.Length);
using (var GostHash = new Gost3411_2012_256CryptoServiceProvider())
{
var csp = (Gost3410_2012_256CryptoServiceProvider) signerCert.PublicKey.Key;
//Используем публичный ключ сертификата для проверки
return csp.VerifyData(messageBytes, GostHash, signatureBytes);
}
}
Код получения сертификата ЕСИА
X509Certificate2 GetEsiaSignerCert()
{
var store = new X509Store(StoreName.AddressBook, StoreLocation.CurrentUser);
store.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);
var certificates = store.Certificates.Find(X509FindType.FindBySerialNumber, EsiaCertSerialNumber, false);
var certificate = certificates[0];
return certificate;
}
Здесь используем введённые ранее константы. И Получаем сертификат из доверенных сертификатов.
Отправка токена на проверку
public async Task<bool> ValidatingAccessToken(EsiaAuthToken token)
{
if (token.Payload.ExpireDate <= DateTime.Now ||
token.Payload.BeginDate >= DateTime.Now ||
token.Payload.CreateDate >= DateTime.Now ||
token.Payload.ExpireDate <= token.Payload.BeginDate ||
token.Payload.CreateDate > token.Payload.BeginDate ||
token.Payload.CreateDate > token.Payload.ExpireDate ||
token.Payload.Iss != esiaSettings.Value.ISS ||
token.Payload.ClientId != esiaSettings.Value.ClientId)
{
return false;
}
var client = new HttpClient();
var requestParams = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("signature", token.Signature),
new KeyValuePair<string, string>("message", token.Message)
};
var response = await client.PostAsync($"{cryptoProSettings.Value.BaseUrl}/Verify",
new FormUrlEncodedContent(requestParams));
response.EnsureSuccessStatusCode();
var resultResponse = await response.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<bool>(resultResponse);
return result;
}
Этот код используем в нашем основном сервисе.
Проверяем поля токена на актуальность, чтобы его не могли подделать. А потом уже проверяем подпись токена, как указано в методических указаниях.
Получение данных пользователя из ЕСИА
Имея токен мы может отправить запрос на получение данных о пользователе указанных в scope токена. Пример кода, где мы получаем данные пользователя. Здесь esiaUserId содержится в самом токене, это уникальный идентификатор пользователя ЕСИА. Наш токен указываем в заголовке авторизации.
public async Task<EsiaUser> ExecuteAsync(string esiaUserId, string accessToken)
{
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
var response = await client.GetStringAsync($"{esiaSettings.Value.EsiaRestUrl}/prns/{esiaUserId}");
var user = JsonConvert.DeserializeObject<EsiaUser>(response);
user.Id = user.Id ?? esiaUserId;
return user;
}
}
Код класса EsiaUser
public class EsiaUser
{
/// <summary>
/// Идентификатор
/// </summary>
[JsonProperty("oid")]
public string Id { get; set; }
/// <summary>
/// Фамилия
/// </summary>
[JsonProperty("firstName")]
public string FirstName { get; set; }
/// <summary>
/// Имя
/// </summary>
[JsonProperty("lastName")]
public string LastName { get; set; }
/// <summary>
/// Отчество
/// </summary>
[JsonProperty("middleName")]
public string MiddleName { get; set; }
/// <summary>
/// Дата рождения
/// </summary>
[JsonProperty("birthdate")]
public string Birthdate { get; set; }
/// <summary>
/// Пол
/// </summary>
[JsonProperty("gender")]
public string Gender { get; set; }
/// <summary>
/// Подтвержден ли пользователь
/// </summary>
[JsonProperty("trusted")]
public bool Trusted { get; set; }
}
Заключение
Наконец мы закончили интеграцию с ЕСИА. Это был длинный путь полный странных вещей. Неясных решений и множество потраченного времени. Надеюсь этой статьёй я помог Вам реализовать задачу интеграции гораздо быстрее и легче. Спасибо за потраченное время.
Настраиваем авторизацию сайта через ЕСИА.
Проблема: После перехода по сформированной ссылке с подписью переходим на страницу авторизации, вводим данные, получаем ошибку «Ошибка авторизации», в адресе страницы есть подробности
error_description=ESIA-007005%3A+The+client+is+not+authorized+to+request+an+access+token+using+this+method
Имеется машина с докером.
Установлен докер контейнер https://hub.docker.com/r/required/cryptopro
Установлен корневой сертификат, сертификат клиента, стоит пробный ключ для КриптоПро.
Цепочки сертификатов проверены методом копирования (https://www.altlinux.org/%D0%9A%D1%80%D0%B8%D0%BF%D1%82%D0%BE%D0%9F%D1%80%D0%BE#%D0%9F%D1%80%D0%BE%D0%B2%D0%B5%D1%80%D0%BA%D0%B0_%D1%86%D0%B5%D0%BF%D0%BE%D1%87%D0%BA%D0%B8_%D1%81%D0%B5%D1%80%D1%82%D0%B8%D1%84%D0%B8%D0%BA%D0%B0%D1%82%D0%BE%D0%B2)
cryptcp -copycert -thumbprint "$thumbprint" -df tt.cer
На выходе
Certificate chains are checked
Для ЕСИА требуется подпись в формате PKCS#7 detached signature в кодировке UTF8, затем кодированная в url safe base64
Погуглив, нашел такой вариант:
csptest -sfsign -sign -detached -base64 -add -alg "GOST12_256" -in message -out sig
Файл подписывается, проверяю
csptest -sfsign -verify -detached -base64 -add -alg "GOST12_256" -in message -signature sig
На выходе:
Detached Signature was verified OK
Вопрос — в чем может быть проблема? Куда копать?
UPD: Есть сервис, который умеет подписывать этим же сертификатом, написан на Java и с его подписью ЕСИА авторизует. Сравнив нашу ссылку и ссылку сервиса — нашли отличия только в строке client_secret, то есть в подписи.
Ошибка формирования подписи
Просмотр 6 сообщений — с 1 по 6 (из 6 всего)
-
Автор
Сообщения
-
21.05.2021 в 13:15
#16506
Добрый день. При формировании подписи выдает следующие: Ошибка формирования подписи
Дальнейшее выполнение операций остановлено!
Что это означает и как это исправить24.05.2021 в 10:44
#16519
Проверьте настройки криптопровайдера Крипто-ПРО. Убедитесь, что в системе (панель Сертификаты) у Вашего сертификата не стоит красная метка.
18.03.2022 в 05:56
#20567
Доброе время суток! вчера на ноутбук переносил все свое хозяйство! операционка там стоит Win10pro. Ставлю свою криптопро4, эцп (закрытый и открытый сертификаты), все как положено! открываю Конструктор, подписываю ТП, все нормально, на второй раз выскакивает — «Ошибка формирования подписи», танцы с бубном, настройки ни какие не помогают! сертификат установился корректно, криптопро его видит без красненьких огоньков! Експлорер сертификат тоже видит без замечаниЙ! помогает только переустановка криптопро, и то на один раз (один раз подписывает и опять вышеперечисленное вверху).
Есть подозрение что криптопро4 не корректно работает на win10pro в программе Конструктор! Кто владеет информацией, по данной проблеме либо подобной, проясните пож-та!15.04.2022 в 09:14
#20825
У меня на 10-ке установлен 5-й КриптоПро. Подобных проблем не наблюдал.
11.11.2022 в 21:48
#23600
Точно такая байда. Хоть лопни. Выдаёт «Ошибка формирования подписи.Дальнейшее выполнение операций остановлено!». Переустанавливаешь ПростоПодписать, можешь подписывать, проверять подпись в пределах одного сеанса. Программу закрыл, открыл и всё, больше ничего не подпишешь. Что за хрень? Кто-то решил эту проблему?
13.11.2022 в 13:03
#23611
Программа нестабильно работает с 4-й версией Крипто Про. Для стабильной работы программы используйте Крипто Про 5-й версии.
-
Автор
Сообщения
Просмотр 6 сообщений — с 1 по 6 (из 6 всего)
Для ответа в этой теме необходимо авторизоваться.
Область применения электронной подписи (ЭП или ЭЦП) довольно широка. Например, многие специальные сервисы требуют верификации пользователя с её помощью: Госуслуги, онлайн-сервисы для управления средствами в банке, электронные площадки и другие. Поэтому любые технические неполадки, возникающие при использовании ЭЦП, могут вызвать различные серьёзные: от упущенной выгоды до материальных убытков.
Какие бывают ошибки
Проблемы при использовании ЭП, с которыми пользователи встречаются чаще всего, можно условно разделить на три группы:
- Проблемы с сертификатом. Они появляются, когда сертификат не выбран, не найден или не верен.
- Проблемы с подписанием документа. Ошибки возникают при попытке подписать документ.
- Проблема при авторизации на торговых площадках.
Рассмотрим неполадки подробнее и разберёмся, как их решать.
Сертификат не найден
Иногда при попытке подписать электронный документ с помощью ЭП пользователь может столкнуться с ошибкой «Не удалось найти ни одного сертификата, пригодного для создания подписи».
У подобных ошибок могут быть следующие причины:
- На компьютере не установлены корневые сертификаты Удостоверяющего Центра (УЦ), в котором была получена ЭП. Необходимо установить либо обновить корневой сертификат. Установка корневых сертификатов удостоверяющего центра подробно описана в нашей инструкции.
- На ПК не установлено ни одного личного сертификата ЭП. Для применения ЭП необходимы и личные сертификаты. Об их установке мы писали в другой статье.
- Установленные на компьютере необходимые сертификаты не валидны. Сертификаты отозваны или просрочены. Уточните статус сертификата в УЦ. Ошибка с текстом «Ваш сертификат ключа подписи включён в список отозванных» возникает, если у сертификата закончился срок действия или на ПК нужно обновить список сертификатов. В последней ситуации следует вручную загрузить перечень отозванных сертификатов.
Для установки списка отозванных сертификатов:
- Откройте личный сертификат пользователя в окне Свойства браузера. Чтобы открыть его, наберите «Свойства браузера» в поисковой строке меню Пуск. Перейдите во вкладку Содержание и нажмите кнопку «Сертификаты».
- Во вкладке Состав выберите из списка пункт «Точки распространения списков отзыва».
- В блоке Имя точки распространения скопируйте ссылку на загрузку файла со списком отзыва.
- Скачайте по указанной ссылке файл. Нажмите по нему правой кнопкой мыши и выберите в контекстном меню «Установить список отзыва (CRL)».
- Следуйте указаниям «Мастера импорта сертификатов».


Не виден сертификат на носителе
Как правило, причина такой проблемы — сбой в работе программных компонентов. Для её решения достаточно перезагрузить компьютер. Однако иногда этого бывает недостаточно, поэтому требуется переустановка драйверов или обращение в службу техподдержки.
К наиболее распространённым причинам такой проблемы относятся следующие случаи:
- Драйвер носителя не установлен или установлен некорректно. Для решения проблемы необходимо извлечь носитель электронной подписи из ПК и скачать последнюю версию драйвера носителя с официальных ресурсов. Если переустановка драйвера не помогла, подключите носитель к другому ПК, чтобы убедиться в исправности токена. Если токен определится другой системой, попробуйте удалить на неисправном компьютере драйвер носителя и установить его заново.
- Долгое опознание носителя. Для решения проблемы необходимо дождаться завершения процесса или обновить версию операционной системы.
- Некорректная работа USB-порта. Подключите токен к другому USB-порту, чтобы убедиться, что проблема не в носителе ЭП. Если система определила токен, перезагрузите компьютер. Если это не поможет, следует обратиться службу технической поддержки.
- Неисправность носителя. Если при подключении токена к другому компьютеру или USB-порту система не определяет его, значит, проблема в самом носителе. Устранение неисправности возможно в данном случае лишь одним путём — нужно обратиться в сервисный центр для выпуска нового носителя.
ЭП не подписывает документ
Причин у подобной проблемы множество. Каждый случай требует отдельной проверки. Среди самых распространённых можно выделить следующие неполадки:
- Закрытый ключ на используемом контейнере не соответствует открытому ключу сертификата. Возможно, был выбран не тот контейнер, поэтому следует проверить все закрытые контейнеры на компьютере. Если необходимый контейнер по тем или иным причинам отсутствует, владельцу придётся обращаться в удостоверяющий центр для перевыпуска ЭП.
- Ошибка «Сертификат недействителен» (certificate is not valid). Следует повторно установить сертификат ЭП по инструкциям УЦ в зависимости от используемого криптопровайдера — КриптоПро CSP, ViPNet CSP или другого.
- Сертификат ЭП определяется как непроверенный. В этом случае необходимо переустановить корневой сертификат удостоверяющего центра.
- Истёк срок действия криптопровайдера. Для решения этой проблемы необходим новый лицензионный ключ к программе-криптопровайдеру. Для его получения необходимо обращаться к специалистам УЦ или к ответственным сотрудникам своей организации.
- Подключён носитель с другим сертификатом. Убедитесь, что подключён правильный токен. Проверьте также, не подключены ли носители других сертификатов. Отключите другие носители в случае их обнаружения.
В момент подписания электронных документов или формирования запроса в различных может возникнуть ошибка «Невозможно создание объекта сервером программирования объектов».

В этой ситуации помогает установка и регистрация библиотеки Capicom:
- Скачайте файл архива.
- Распакуйте и переместите файлы capicom.dll и capicom.inf в каталог syswow64, находящийся в корневой папке ОС.
- Откройте командную строку от имени администратора — для этого в меню Пуск наберите «Командная строка», нажмите по найденному приложению правой кнопкой мыши и выберите Запуск от имени администратора.
- Введите «c:windowssyswow64regsvr32.exe capicom.dll» (без кавычек) и нажмите ENTER. Должно появиться уведомление о том, что команда выполнена успешно.


Выбранная подпись не авторизована
Подобная ошибка возникает при попытке авторизации в личном кабинете на электронных торговых площадках. Например, при входе на площадку ZakazRF отображается сообщение «Выбранная ЭЦП не авторизована».

Эта ошибка возникает из-за того, что пользователь не зарегистрирован на площадке, либо не зарегистрирован новый сертификат ключа ЭП. Решением проблемы будет регистрация нового сертификата.
Процесс запроса на авторизацию ЭП на разных торговых площадках может отличаться: часто нужно отправлять запрос оператору системы на авторизацию, иногда рабочее место настраивается автоматически.
Если ошибка сохраняется, возможно, следует отключить защитное ПО или добавить сайт электронной площадки в исключения.
Часто задаваемые вопросы
Почему компьютер не видит ЭЦП?
Причина кроется в несовместимости программного обеспечения и физического носителя ЭЦП. Необходимо проверить версию операционной системы и переустановить её до нужной версии. Если токен повреждён, возможно, понадобится обратиться в удостоверяющий центр для перевыпуска электронной подписи.
О том, что делать, если компьютер не видит ЭЦП и о способах проверки настроек, мы подробно писали в нашей статье.
Почему КриптоПро не отображает ЭЦП?
Если КриптоПро не отображает ЭЦП, следует проверить настройки браузера. Также исправляет ошибку добавление программы в веб-обозреватель и загрузка недостающих сертификатов электронной подписи.
Подробнее ознакомиться, как устранить данную неисправность можно в нашей статье.
Где на компьютере искать сертификаты ЭЦП?
Сертификат ЭЦП позволяет проверить подлинность подписи, содержит в себе срок её действия и информацию о владельце. Он автоматически загружается в папку с системными файлами. В операционной системе Windows от 7 версии и выше ЭЦП хранится по адресу:
C:UsersПОЛЬЗОВАТЕЛЬAppDataRoamingMicrosoftSystemCertificates. Вместо ПОЛЬЗОВАТЕЛЬ требуется указать наименование используемого компьютера.
Что такое сертификат ЭЦП и зачем он нужен мы рассказали в нашей статье.