12
This commit is contained in:
@@ -1,166 +0,0 @@
|
||||
# chestny-znak-web-app — План реализации тестового web-приложения для API Честного знака
|
||||
|
||||
**Статус:** Активен
|
||||
|
||||
## Описание задачи
|
||||
|
||||
Проанализировать API «Честный знак» (ГИС МТ, True API) и создать план реализации тестового web-приложения, которое позволяет:
|
||||
1. Авторизоваться в системе (подписать тестовый набор данных УКЭП)
|
||||
2. Получить информацию о QR-кодах (КМ) из УПД — актуальны или нет
|
||||
|
||||
## Результаты анализа API
|
||||
|
||||
### Документация True API
|
||||
|
||||
| Параметр | Значение |
|
||||
|----------|----------|
|
||||
| Официальная документация | https://docs.crpt.ru/gismt/True_API/ |
|
||||
| Тестовый контур (sandbox) | `https://markirovka.sandbox.crptech.ru/api/v3/true-api` |
|
||||
| Промышленный контур | `https://markirovka.crpt.ru/api/v3/true-api` |
|
||||
| Версия API | v3/v4 |
|
||||
| Формат | REST, JSON |
|
||||
| Аутентификация | УКЭП (ГОСТ, CAdES-BES) → Bearer token |
|
||||
|
||||
### Процесс аутентификации (Единая аутентификация)
|
||||
|
||||
```
|
||||
Шаг 1: GET /auth/key → { uuid, data }
|
||||
(получаем UUID и случайную строку для подписи)
|
||||
|
||||
Шаг 2: Подписать data УКЭП (CAdES-BES, присоединённая подпись, base64)
|
||||
(требуется КриптоПро или совместимое СКЗИ)
|
||||
|
||||
Шаг 3: POST /auth/simpleSignIn → { token, uuidToken?, expireDate? }
|
||||
Body: { uuid: "<uuid>", data: "<base64 signature>" }
|
||||
```
|
||||
|
||||
- Срок действия токена: **не более 10 часов**
|
||||
- Форматы токена: JWT (по умолчанию) или UUID (параметр `unitedToken: true`)
|
||||
- Поддержка JWT — до марта 2026 года, UUID — основной формат
|
||||
|
||||
### Ключевые методы для задачи
|
||||
|
||||
| Метод | Endpoint | Описание |
|
||||
|-------|----------|----------|
|
||||
| Получение информации о КМ | `POST /api/v3/true-api/cises/info` | Статус, производитель, собственник, GTIN |
|
||||
| Проверка кодов (розница) | `POST /api/v4/true-api/codes/check` | Проверка перед продажей |
|
||||
| Публичная проверка | `GET https://mobile.api.crpt.ru/mobile/check?code=<код>` | Без авторизации (недокументированный эндпоинт моб. приложения) |
|
||||
| Поиск КМ | `POST /api/v4/true-api/cises/search` | Поиск по фильтрам |
|
||||
|
||||
### Пример публичного API (без авторизации)
|
||||
|
||||
Запрос:
|
||||
```
|
||||
GET https://mobile.api.crpt.ru/mobile/check?code=0104640507713421215TxdVFoOB.zFF
|
||||
```
|
||||
|
||||
Ответ (JSON):
|
||||
```json
|
||||
{
|
||||
"code": "0104640507713421215TxdVFoOB.zFF",
|
||||
"found": true,
|
||||
"valid": true,
|
||||
"status": "INTRODUCED"
|
||||
}
|
||||
```
|
||||
|
||||
**Ограничения публичного API:**
|
||||
- Не требует аутентификации — можно использовать для быстрой проверки единичных кодов
|
||||
- Возвращает минимум данных: только статус и флаг валидности
|
||||
- Не подходит для пакетной проверки (по одному коду за запрос)
|
||||
- Не документирован официально (эндпоинт мобильного приложения)
|
||||
|
||||
**Для полноценной проверки КМ из УПД рекомендуется использовать авторизованный метод** `POST /api/v3/true-api/cises/info`, который возвращает полную информацию: GTIN, наименование товара, производителя, владельца, дату ввода в оборот и т.д.
|
||||
|
||||
### Структура ответа /cises/info
|
||||
|
||||
```json
|
||||
{
|
||||
"cisInfo": [{
|
||||
"requestedCis": "0104600702028445...",
|
||||
"cis": "0104600702028445...",
|
||||
"gtin": "04600702028445",
|
||||
"status": "INTRODUCED",
|
||||
"productName": "Молоко 3.2%",
|
||||
"productGroup": "Молочная продукция",
|
||||
"producerName": "АО \"Данон Россия\"",
|
||||
"ownerName": "ООО Магнит",
|
||||
"ownerBin": "2309085638",
|
||||
"producedDate": "2025-01-15T10:00:00.000Z",
|
||||
"packageType": "UNIT"
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
**Статусы КМ:** `EMITTED` (эмитирован), `APPLIED` (нанесён), `INTRODUCED` (в обороте), `RETIRED` (выбыл), `WRITTEN_OFF` (списан), `DISAGGREGATION` (расформирован), `CANCELLED` (аннулирован)
|
||||
|
||||
### Работа с УПД
|
||||
|
||||
- Коды маркировки в XML УПД (формат Приказа №970 ФНС) находятся в элементе `Документ/ТаблСчФакт/СведТов/ДопСведТов/НомСредИдентТов`
|
||||
- При проверке QR-кодов из УПД необходимо:
|
||||
1. Загрузить XML УПД (формат 970 приказа)
|
||||
2. Распарсить XML по XPath: `//Документ/ТаблСчФакт/СведТов/ДопСведТов/НомСредИдентТов`
|
||||
3. Извлечь все коды маркировки
|
||||
4. Отправить запрос в `/cises/info` (с авторизацией)
|
||||
5. Отобразить статус каждого кода
|
||||
|
||||
---
|
||||
|
||||
## Шаги
|
||||
|
||||
- [ ] 1. **Инициализация проекта** — создать Fastify/Express backend + React frontend. Оба сервиса запускаются через `docker-compose`
|
||||
- [ ] 2. **Backend: модуль аутентификации**
|
||||
- 2.1. Реализовать `GET /auth/key` — получение UUID + data от True API
|
||||
- 2.2. Реализовать подпись data через КриптоПро с помощью `@vgoma/crypto-pro` (Node.js binding для КриптоПро CSP)
|
||||
- 2.3. Реализовать `POST /auth/simpleSignIn` — получение токена
|
||||
- 2.4. Кеширование и auto-refresh токена (раз в 10 часов)
|
||||
- [ ] 3. **Backend: модуль проверки КМ**
|
||||
- 3.1. Реализовать `POST /api/check-codes` — принимает массив кодов маркировки
|
||||
- 3.2. Вызов `POST /api/v3/true-api/cises/info` для каждого кода (батчами до 1000)
|
||||
- 3.3. Возврат статуса: актуален / неактуален / не найден / ошибка
|
||||
- [ ] 4. **Backend: модуль обработки УПД**
|
||||
- 4.1. Приём XML-файла УПД через `POST /api/upload-upd`
|
||||
- 4.2. Парсинг XML, извлечение кодов маркировки из `НомСредИдентТов`
|
||||
- 4.3. Передача кодов в модуль проверки КМ (шаг 3)
|
||||
- [ ] 5. **Frontend: страница авторизации**
|
||||
- 5.1. Форма ввода/загрузки сертификата УКЭП
|
||||
- 5.2. Отображение статуса авторизации и срока действия токена
|
||||
- [ ] 6. **Frontend: страница проверки QR-кодов**
|
||||
- 6.1. **Проверка одного кода** — поле ввода + две кнопки:
|
||||
- «Проверить без авторизации» — через публичный API (`mobile.api.crpt.ru/mobile/check`), минимум данных
|
||||
- «Проверить с авторизацией» — через `POST /cises/info`, полная информация: GTIN, наименование, производитель, владелец, статус
|
||||
- 6.2. **Загрузка XML УПД (формат 970 приказа)** — drag & drop / file picker, парсинг на backend, пакетная проверка через `/cises/info`
|
||||
- 6.3. Таблица результатов: код, GTIN, наименование, статус, производитель, владелец
|
||||
- 6.4. Цветовая индикация: зелёный (актуален / в обороте), красный (выбыл / списан), жёлтый (предупреждение)
|
||||
- [ ] 7. **Тестирование на sandbox**
|
||||
- 7.1. Получение тестового УКЭП через testca2012.cryptopro.ru
|
||||
- 7.2. Регистрация в sandbox (markirovka.sandbox.crptech.ru)
|
||||
- 7.3. Интеграционные тесты: авторизация → проверка кодов
|
||||
- [ ] 8. **Docker-сборка**
|
||||
- 8.1. `Dockerfile.backend` — backend-образ с Node.js + установленным КриптоПро CSP (`crypto-pro`)
|
||||
- 8.2. `Dockerfile.frontend` — nginx-образ со статикой React-приложения
|
||||
- 8.3. `docker-compose.yml` — сервисы `backend`, `frontend`, общая сеть
|
||||
- 8.4. README с инструкцией по запуску (`docker-compose up --build`)
|
||||
|
||||
- [x] 9. **Переключение контура (sandbox/prod) из UI**
|
||||
- 9.1. Backend: два набора URL (`envUrls`) в `config.ts`, per-env кеш токенов
|
||||
- 9.2. Backend: все сервисы и роуты принимают `?env=sandbox|prod`
|
||||
- 9.3. Frontend: `<select>` в хедере, `getEnv()`/`setEnv()` в модуле API
|
||||
- 9.4. QA-доработки:
|
||||
- `onUnauthorized` передаёт env — логаут правильного контура при 401
|
||||
- `window.confirm` при переключении на промышленный контур
|
||||
- `setPage('auth')` при смене env
|
||||
- `getAuthStatus` при переключении — восстановление `authenticated` если токен жив
|
||||
- `uploadUpd` через общий `request()` (устранено дублирование)
|
||||
|
||||
## Затрагиваемые сервисы
|
||||
|
||||
- `backend/` — Fastify/Express backend с модулями:
|
||||
- `auth-service` — получение и менеджмент токена True API
|
||||
- `crypto-service` — подпись данных через `@vgoma/crypto-pro` (КриптоПро CSP)
|
||||
- `cises-service` — проверка статусов кодов маркировки через `/cises/info`
|
||||
- `upd-parser` — парсинг XML УПД и извлечение кодов
|
||||
- `frontend/` — React (Next.js) SPA:
|
||||
- Страница авторизации
|
||||
- Страница проверки кодов
|
||||
- Компонент загрузки УПД
|
||||
@@ -1,85 +0,0 @@
|
||||
# connect-sandbox — Подключение к песочнице API Честного знака
|
||||
|
||||
**Статус:** Активен
|
||||
|
||||
## Описание
|
||||
|
||||
План действий для подключения к тестовому контуру (sandbox) API Честного знака (True API) и выполнения первого успешного запроса. Код приложения уже реализован — требуется выполнить шаги регистрации, получения тестового УКЭП и запуска.
|
||||
|
||||
## Шаги
|
||||
|
||||
### 1. Регистрация в sandbox Честного знака
|
||||
|
||||
- [ ] 1.1. Перейти на портал sandbox: https://markirovka.sandbox.crptech.ru/
|
||||
- [ ] 1.2. Зарегистрировать участника (юридическое лицо или ИП)
|
||||
- [ ] 1.3. Создать тестовую учётную запись организации
|
||||
- [ ] 1.4. Убедиться, что организация активна в sandbox
|
||||
|
||||
### 2. Получение тестового УКЭП
|
||||
|
||||
- [ ] 2.1. Перейти на testca2012.cryptopro.ru
|
||||
- [ ] 2.2. Скачать тестовый сертификат для физического лица (или сгенерировать через КриптоПро CSP)
|
||||
- [ ] 2.3. Установить сертификат в личное хранилище (Настройки → КриптоПро CSP → Сертификаты)
|
||||
- [ ] 2.4. Убедиться, что сертификат имеет статус «Действителен»
|
||||
- [ ] 2.5. Связать тестовый сертификат с зарегистрированной организацией в sandbox (если требуется)
|
||||
|
||||
### 3. Установка КриптоПро Browser Plugin
|
||||
|
||||
- [ ] 3.1. Скачать КриптоПро Browser Plugin: https://cryptopro.ru/products/cades/plugin
|
||||
- [ ] 3.2. Установить плагин в браузер (поддерживаются Chrome, Firefox, Edge, Chromium)
|
||||
- [ ] 3.3. Перезапустить браузер
|
||||
- [ ] 3.4. Проверить установку: открыть `chrome://plugins/` (или `about:addons`) — плагин должен быть активен
|
||||
|
||||
### 4. Настройка и запуск приложения
|
||||
|
||||
- [ ] 4.1. Склонировать репозиторий (если ещё не):
|
||||
```bash
|
||||
git clone <url>
|
||||
cd chestno-api
|
||||
```
|
||||
- [ ] 4.2. Проверить конфигурацию `backend/.env`:
|
||||
```env
|
||||
TRUE_API_URL=https://markirovka.sandbox.crptech.ru/api/v3/true-api
|
||||
PUBLIC_CHECK_URL=https://mobile.api.crpt.ru/mobile/check
|
||||
```
|
||||
- [ ] 4.3. Запустить приложение:
|
||||
```bash
|
||||
docker-compose up --build
|
||||
```
|
||||
- [ ] 4.4. Проверить, что сервисы запущены:
|
||||
- Backend: http://localhost:3002/health
|
||||
- Frontend: http://localhost:3003
|
||||
|
||||
### 5. Авторизация в sandbox через приложение
|
||||
|
||||
- [ ] 5.1. Открыть http://localhost:3003
|
||||
- [ ] 5.2. Убедиться, что страница авторизации показывает «КриптоПро Browser Plugin: Обнаружен»
|
||||
- [ ] 5.3. Выбрать тестовый сертификат из списка
|
||||
- [ ] 5.4. Нажать «Подписать и войти»
|
||||
- [ ] 5.5. Проверить, что получен токен и отображается статус «Авторизован» с TTL
|
||||
|
||||
### 6. Проверка работоспособности
|
||||
|
||||
- [ ] 6.1. Ввести тестовый КМ на странице проверки кодов
|
||||
- [ ] 6.2. Нажать «Проверить с авторизацией»
|
||||
- [ ] 6.3. Убедиться, что возвращается полная информация о КМ (GTIN, статус, производитель, владелец)
|
||||
- [ ] 6.4. Проверить публичную проверку (без авторизации) — должна работать всегда
|
||||
|
||||
## Затрагиваемые сервисы
|
||||
|
||||
- `backend/.env` — проверка/корректировка `TRUE_API_URL` на sandbox (уже установлен по умолчанию)
|
||||
- Внешние:
|
||||
- **testca2012.cryptopro.ru** — тестовый УЦ для получения сертификата
|
||||
- **markirovka.sandbox.crptech.ru** — sandbox API Честного знака
|
||||
- **КриптоПро Browser Plugin** — расширение для браузера (CAdES)
|
||||
- **КриптоПро CSP** — если требуется для установки сертификата
|
||||
|
||||
## Примечания
|
||||
|
||||
- Sandbox URL по умолчанию уже настроен в `backend/.env` — код менять не нужно
|
||||
- В sandbox доступны только тестовые коды маркировки (их можно получить в личном кабинете sandbox)
|
||||
- JWT-токены отключены с марта 2026 — приложение использует UUID-токены (`unitedToken: true`)
|
||||
- Для промышленного контура потребуется:
|
||||
1. Реальный УКЭП юридического лица (ФНС/УЦ)
|
||||
2. Регистрация в ГИС МТ как участник
|
||||
3. Смена `TRUE_API_URL` на `https://markirovka.crpt.ru/api/v3/true-api`
|
||||
@@ -1,476 +0,0 @@
|
||||
# service-ukep — Выпуск и подключение обезличенной УКЭП (служебной учётной записи) для True API
|
||||
|
||||
**Статус:** Активен
|
||||
|
||||
## Предпосылки
|
||||
|
||||
В текущей архитектуре приложения аутентификация в True API выполняется через УКЭП **физического лица** (сотрудника) с помощью КриптоПро Browser Plugin на стороне клиента. Это означает, что:
|
||||
- Для каждого сеанса нужен человек с токеном
|
||||
- Нельзя организовать полностью автоматический обмен (сервер-сервер)
|
||||
- При увольнении сотрудника доступ теряется
|
||||
|
||||
Для автоматической интеграции требуется **обезличенная УКЭП (ОУКЭП)** — сертификат на организацию, без привязки к физлицу.
|
||||
|
||||
---
|
||||
|
||||
## 1. Юридические основания
|
||||
|
||||
| Нормативный акт | Описание |
|
||||
|-----------------|----------|
|
||||
| **63-ФЗ ст. 5 п. 2** | Допускается УКЭП, в сертификате которой не указано физлицо (обезличенная), для автоматического создания/проверки ЭП |
|
||||
| **Приказ ФНС от 08.06.2021 № ЕД-7-24/538@** | Порядок выдачи обезличенных сертификатов УЦ ФНС |
|
||||
| **443-ФЗ от 01.09.2024** | КЭП оформляется только на директора (без доверенности); для автоматизации — только ОУКЭП |
|
||||
|
||||
ОУКЭП применяется для электронных документов, **автоматически формируемых и представляемых** в ГИС МТ, за исключением:
|
||||
- Заявления о регистрации участника
|
||||
- Заявки на тестирование
|
||||
- Заявки на доступ к устройству регистрации эмиссии
|
||||
|
||||
---
|
||||
|
||||
## 2. Сравнение вариантов
|
||||
|
||||
| Характеристика | ОУКЭП (обезличенная) | КЭП физлица + МЧД | API-ключ (x-api-key) |
|
||||
|----------------|----------------------|--------------------|---------------------|
|
||||
| **Кому выдаётся** | Организации (без физлица) | Физлицу | Организации (в ЛК) |
|
||||
| **Без человека** | ✅ Да — полный автомат | ❌ Нет — нужен человек с токеном | ✅ Да |
|
||||
| **Срок** | 15 месяцев | 12-15 месяцев | до 01.07.2026 (продление?) |
|
||||
| **Доступ к True API** | ✅ Полный | ✅ Полный | ❌ Только касса (розн. режим) |
|
||||
| **Стоимость** | 0 ₽ (УЦ ФНС) / 3–10 тыс. ₽ (коммерч.) | ~3 000 ₽/год | 0 ₽ |
|
||||
| **Риски** | Низкие | Увольнение сотрудника | Ограниченный функционал |
|
||||
|
||||
**Вывод:** для серверной интеграции с True API требуется именно ОУКЭП.
|
||||
|
||||
---
|
||||
|
||||
## 3. Порядок выпуска ОУКЭП через УЦ ФНС (бесплатно)
|
||||
|
||||
### 3.1. Подготовка документов
|
||||
|
||||
| № | Документ | Примечание |
|
||||
|---|----------|------------|
|
||||
| 1 | **Письмо-заявление** на официальном бланке организации | С обоснованием: «для автоматического обмена с ГИС МТ через True API» |
|
||||
| 2 | **Копия распорядительного документа** о создании информационной системы | Приказ о вводе в эксплуатацию информационной системы, осуществляющей автоматический обмен |
|
||||
| 3 | **Паспорт руководителя** (оригинал) | Личная явка в УЦ ФНС |
|
||||
| 4 | **СНИЛС руководителя** | |
|
||||
| 5 | **ИНН организации + ИНН руководителя** | |
|
||||
| 6 | **Выписка из ЕГРЮЛ** | Свежая (не старше 1 мес.) |
|
||||
| 7 | **Решение о назначении руководителя** | Протокол / приказ |
|
||||
| 8 | **USB-токен** | Рутокен ЭЦП 3.0 или JaCarta-2 ГОСТ (см. п. 3.2) |
|
||||
|
||||
**Образцы документов:**
|
||||
- Письмо-заявление: https://github.com/romangorbenko/OUKEP/blob/main/letter.docx
|
||||
- Приказ о создании ИС: https://github.com/romangorbenko/OUKEP/blob/main/order.docx
|
||||
- Приказ о назначении ответственного: https://github.com/romangorbenko/OUKEP/blob/main/ResponsibleAppointment.docx
|
||||
|
||||
### 3.2. Требования к носителю (2026 год)
|
||||
|
||||
С 1 апреля 2026 все КЭП — только по новым ГОСТ 34.12-2018 / 34.13-2018.
|
||||
|
||||
| Носитель | Статус |
|
||||
|----------|--------|
|
||||
| **Рутокен ЭЦП 3.0** | ✅ Работает |
|
||||
| **JaCarta-2 ГОСТ** | ✅ Работает |
|
||||
| **JaCarta-3** | ✅ Работает |
|
||||
| Рутокен ЭЦП 2.0 | ❌ Устарел (не принимается) |
|
||||
| Рутокен Lite | ❌ Не сертифицирован |
|
||||
| eToken (старые) | ❌ Не сертифицированы |
|
||||
|
||||
### 3.3. Процесс получения
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[Подготовить документы] --> B[Записаться в УЦ ФНС]
|
||||
B --> C[Личная явка руководителя с паспортом + токеном]
|
||||
C --> D[Выпуск сертификата на носитель]
|
||||
D --> E[Установка КриптоПро CSP 5.0+]
|
||||
E --> F[Импорт сертификата в хранилище]
|
||||
```
|
||||
|
||||
1. Записаться в ближайшую ИФНС, оказывающую услуги УЦ (перечень на nalog.gov.ru)
|
||||
2. Явиться лично с комплектом документов и USB-токеном
|
||||
3. Сотрудник УЦ проверяет документы, идентифицирует личность, выпускает сертификат
|
||||
4. Получить носитель с записанным сертификатом
|
||||
5. **Срок:** от 1 часа до 3 рабочих дней
|
||||
6. **Срок действия:** 15 месяцев
|
||||
|
||||
### 3.4. Альтернатива — коммерческий УЦ
|
||||
|
||||
| УЦ | Ориентировочная стоимость | Примечание |
|
||||
|----|---------------------------|------------|
|
||||
| Контур (ca.kontur.ru) | ~5 000–8 000 ₽/год | Удалённо, курьер |
|
||||
| Такском (taxcom.ru) | ~4 000–7 000 ₽/год | Удалённо |
|
||||
| СБИС (sbis.ru) | ~5 000–10 000 ₽/год | Удалённо |
|
||||
| Астрал (astral.ru) | ~3 000–6 000 ₽/год | Удалённо |
|
||||
|
||||
**Плюсы:** не нужна личная явка в ФНС, быстрее, сопровождение.
|
||||
**Минусы:** платно.
|
||||
|
||||
---
|
||||
|
||||
## 4. Техническая подготовка к автоматической подписи (сервер)
|
||||
|
||||
### 4.1. Схема работы
|
||||
|
||||
```
|
||||
Сервер (Linux)
|
||||
├── КриптоПро CSP 5.0 R2+ ← подпись УКЭП
|
||||
├── Носитель с ОУКЭП
|
||||
│ ├── Физический USB (Рутокен) → через USB-over-IP (NIO-EUSB / Digi AnywhereUSB)
|
||||
│ └── Или виртуальный (копия ключа, если разрешено политикой)
|
||||
├── Наше приложение (backend)
|
||||
│ ├── got → True API (auth/key, simpleSignIn)
|
||||
│ └── crypto-pro (или КриптоПро CLI) → подпись data
|
||||
└── Хранилище сертификатов (/var/opt/cprocsp/...)
|
||||
```
|
||||
|
||||
### 4.2. Требования к серверу
|
||||
|
||||
| Компонент | Версия | Назначение |
|
||||
|-----------|--------|------------|
|
||||
| **ОС** | Linux (x86_64) | Рекомендуется Ubuntu 22.04+/Debian 12+/Astra Linux |
|
||||
| **КриптоПро CSP** | 5.0.12000+ (5.0 R2) | Криптопровайдер |
|
||||
| **КриптоПро CLI (cryptcp)** | из состава CSP | Генерация запросов, подпись |
|
||||
| **lsb-cprocsp-devel** | из состава CSP | Разработка |
|
||||
| **USB-токен** | Рутокен ЭЦП 3.0 / JaCarta-2 ГОСТ | Носитель ключа |
|
||||
| **pcscd** | любая | Демон для работы с USB-токенами |
|
||||
| **Node.js** | 20+ | Наше приложение |
|
||||
|
||||
### 4.3. Установка КриптоПро CSP на сервер
|
||||
|
||||
```bash
|
||||
# 1. Скачать дистрибутив с cryptopro.ru (требуется авторизация)
|
||||
# linux-amd64_deb.tgz
|
||||
|
||||
# 2. Установить
|
||||
tar -xzf linux-amd64_deb.tgz
|
||||
cd linux-amd64_deb
|
||||
./install.sh
|
||||
|
||||
# 3. Проверить установку
|
||||
/opt/cprocsp/sbin/cryptopro -v
|
||||
|
||||
# 4. Установить лицензию
|
||||
/opt/cprocsp/bin/cryptopro -setkey <license-key>
|
||||
|
||||
# 5. Подключить токен (через USB или USB-over-IP)
|
||||
# Убедиться, что pcscd запущен
|
||||
systemctl start pcscd
|
||||
|
||||
# 6. Проверить видимость токена
|
||||
/opt/cprocsp/bin/cryptopro -list
|
||||
```
|
||||
|
||||
### 4.4. Генерация запроса на сертификат (PKCS#10)
|
||||
|
||||
Если ОУКЭП выпускается через УЦ ФНС **впервые** (без готового носителя), нужно сгенерировать запрос на сервере и передать его в УЦ.
|
||||
|
||||
**Сгенерировать контейнер и запрос:**
|
||||
|
||||
```bash
|
||||
/opt/cprocsp/bin/cryptcp -createrqst /tmp/request.req \
|
||||
-rdn "CN=\"ООО \"\"РОМАШКА\"\"\", E=admin@company.ru, C=RU, S=\"77 г. Москва\", L=\"Москва\", STREET=\"ул. Ленина д.1\", O=\"ООО \"\"РОМАШКА\"\"\", 1.2.643.100.4=7700123456, 1.2.643.100.1=1234567890123" \
|
||||
-pin "" \
|
||||
-provtype 80 \
|
||||
-provname "Crypto-Pro GOST R 34.10-2012 Cryptographic Service Provider" \
|
||||
-certusage 1.3.6.1.5.5.7.3.2 \
|
||||
-ext RemoteCertificate.ext
|
||||
```
|
||||
|
||||
Где:
|
||||
- `1.2.643.100.4` — ИНН организации (10 цифр)
|
||||
- `1.2.643.100.1` — ОГРН (13 цифр или 15 для ИП)
|
||||
- `RemoteCertificate.ext` — файл с OID для удалённого выпуска (без личной явки) — [скачать шаблон](https://raw.githubusercontent.com/romangorbenko/OUKEP/main/RemoteCertificate.ext)
|
||||
|
||||
Файл `request.req` передаётся в УЦ ФНС (на USB-флешке, вместе с пакетом документов из п. 3.1).
|
||||
|
||||
### 4.5. Установка полученного сертификата на сервер
|
||||
|
||||
```bash
|
||||
# Установить сертификат в контейнер
|
||||
/opt/cprocsp/bin/cryptcp -inst \
|
||||
-cont "\\.\A-<идентификатор контейнера>" \
|
||||
-cert /tmp/certificate.cer
|
||||
|
||||
# Проверить
|
||||
/opt/cprocsp/bin/cryptopro -list
|
||||
```
|
||||
|
||||
### 4.6. Подпись данных (автоматическая)
|
||||
|
||||
**Вариант A — через CLI (cryptcp):**
|
||||
|
||||
```bash
|
||||
echo -n "$DATA" | base64 -d > /tmp/data_to_sign.bin
|
||||
/opt/cprocsp/bin/cryptcp -sign \
|
||||
-detached \
|
||||
-thumbprint <THUMBPRINT> \
|
||||
/tmp/data_to_sign.bin /tmp/signature.sig
|
||||
cat /tmp/signature.sig | base64 -w0
|
||||
```
|
||||
|
||||
**Вариант B — через Node.js binding (`@vgoma/crypto-pro`):**
|
||||
|
||||
Пакет `@vgoma/crypto-pro` умеет работать с КриптоПро CSP на сервере (не только в браузере). Требует установленного CSP и библиотеки `lsb-cprocsp-devel`.
|
||||
|
||||
```typescript
|
||||
import { createAttachedSignature } from '@vgoma/crypto-pro'
|
||||
|
||||
const signature = await createAttachedSignature(thumbprint, base64data)
|
||||
```
|
||||
|
||||
**Вариант C — через REST-сервис КриптоПро (CryptoPro DSS):**
|
||||
|
||||
КриптоПро предоставляет DSS (Digital Signature Service) — REST API для подписи. Устанавливается как отдельный сервис.
|
||||
|
||||
### 4.7. Дооснащение backend-контейнера (`backend/Dockerfile`)
|
||||
|
||||
Текущий Dockerfile использует `node:20-alpine`. Для работы с КриптоПро потребуется:
|
||||
|
||||
```dockerfile
|
||||
# Вариант: переход на образ с КриптоПро CSP
|
||||
FROM node:20-bookworm AS builder
|
||||
WORKDIR /app
|
||||
COPY package.json package-lock.json ./
|
||||
RUN npm ci
|
||||
COPY src/ ./src/
|
||||
RUN npm run build
|
||||
|
||||
FROM node:20-bookworm AS runner
|
||||
WORKDIR /app
|
||||
|
||||
# Установка КриптоПро CSP
|
||||
COPY cprocsp/*.deb /tmp/
|
||||
RUN dpkg -i /tmp/*.deb || true
|
||||
RUN apt-get install -f -y && \
|
||||
/opt/cprocsp/sbin/cryptopro -setkey <license>
|
||||
|
||||
# Установка НЦА (сертификаты УЦ)
|
||||
RUN /opt/cprocsp/sbin/cpverify -install ...
|
||||
|
||||
# USB-over-IP клиент (если токен не локальный)
|
||||
COPY nio-eusb-client /usr/local/bin/
|
||||
|
||||
COPY --from=builder /app/dist ./dist
|
||||
COPY --from=builder /app/node_modules ./node_modules
|
||||
|
||||
EXPOSE 3001
|
||||
CMD ["node", "dist/index.js"]
|
||||
```
|
||||
|
||||
**Или проще:** использовать готовый образ от КриптоПро или развернуть сервис подписи на отдельной ВМ, а наш backend будет вызывать его по REST.
|
||||
|
||||
---
|
||||
|
||||
## 5. Регистрация ОУКЭП в личном кабинете Честного знака
|
||||
|
||||
### 5.1. Для True API (ГИС МТ)
|
||||
|
||||
После получения сертификата его нужно зарегистрировать в ГИС МТ:
|
||||
|
||||
1. Войти в ЛК Честного знака: https://markirovka.crpt.ru (с УКЭП руководителя)
|
||||
2. Перейти: **Профиль → Администрирование → Учётные системы**
|
||||
3. Нажать **«Добавить учётную систему»**
|
||||
4. Указать наименование (например, «Сервер интеграции API»)
|
||||
5. В карточке учётной системы нажать **«Добавить сертификат»**
|
||||
6. Загрузить **открытую часть сертификата** (файл .cer)
|
||||
|
||||
**Важно:** для каждого контура (sandbox / prod) регистрация выполняется отдельно.
|
||||
|
||||
### 5.2. Внутренний распорядительный акт (обязательно)
|
||||
|
||||
Требование 63-ФЗ: издать приказ о назначении **ответственного лица** за автоматическое создание/проверку ЭП в информационной системе.
|
||||
|
||||
Документ должен содержать:
|
||||
- ФИО сотрудника, ответственного за автоматическую подпись
|
||||
- Регламент работы информационной системы
|
||||
- Порядок действий при компрометации ключа
|
||||
|
||||
Без этого акта использование ОУКЭП юридически недействительно.
|
||||
|
||||
---
|
||||
|
||||
## 6. Техническая интеграция — изменения в приложении
|
||||
|
||||
### 6.1. Изменение архитектуры
|
||||
|
||||
Сейчас подпись выполняется **на клиенте** (в браузере через CadesPlugin). После внедрения ОУКЭП:
|
||||
|
||||
```
|
||||
Схема А: только серверная подпись (рекомендуется)
|
||||
─────────────────────────────────────
|
||||
Frontend (браузер) Backend (наш сервер) True API
|
||||
│ │ │
|
||||
│ GET /auth/key │ │
|
||||
│───────────────────────────────>│ │
|
||||
│ │ GET /auth/key │
|
||||
│ │──────────────────────────────>│
|
||||
│ │<────────────────────────────── │
|
||||
│ { uuid, data } │ │
|
||||
│<───────────────────────────────│ │
|
||||
│ │ │
|
||||
│ POST /auth/simpleSignIn │ (подпись на сервере) │
|
||||
│ { uuid } │ через КриптоПро CSP │
|
||||
│───────────────────────────────>│ │
|
||||
│ │ POST /auth/simpleSignIn │
|
||||
│ │ { uuid, data: <sign> } │
|
||||
│ │──────────────────────────────>│
|
||||
│ │<────────────────────────────── │
|
||||
│ { token } │ │
|
||||
│<───────────────────────────────│ │
|
||||
```
|
||||
|
||||
**Изменения:**
|
||||
- Frontend отправляет только `{ uuid }` (без data)
|
||||
- Backend сам подписывает data через установленный КриптоПро CSP
|
||||
- Browser Plugin на стороне клиента больше **не нужен** для авторизации
|
||||
- Весь процесс аутентификации — на backend
|
||||
|
||||
### 6.2. Модификация backend-сервисов
|
||||
|
||||
**`auth-service.ts`:**
|
||||
|
||||
```typescript
|
||||
import { execSync } from 'child_process'
|
||||
|
||||
function signData(dataBase64: string): string {
|
||||
const thumbprint = process.env.CERT_THUMBPRINT
|
||||
// Вариант 1: через CLI cryptcp
|
||||
const result = execSync(
|
||||
`/opt/cprocsp/bin/cryptcp -sign -detached -thumbprint ${thumbprint} /dev/stdin /dev/stdout`,
|
||||
{ input: Buffer.from(dataBase64, 'base64') }
|
||||
)
|
||||
return result.toString('base64')
|
||||
|
||||
// Вариант 2: через @vgoma/crypto-pro (асинхронно)
|
||||
// return createAttachedSignature(thumbprint, dataBase64)
|
||||
}
|
||||
|
||||
export async function getAuthKey(env: TrueApiEnv): Promise<AuthKeyResponse> {
|
||||
// ... без изменений
|
||||
}
|
||||
|
||||
export async function serverSignIn(env: TrueApiEnv): Promise<AuthSignInResponse> {
|
||||
const { uuid, data } = await getAuthKey(env)
|
||||
const signature = signData(data)
|
||||
return signIn(env, { uuid, data: signature })
|
||||
}
|
||||
```
|
||||
|
||||
**Новый endpoint:**
|
||||
|
||||
```typescript
|
||||
// POST /auth/server-login — полная авторизация на backend
|
||||
app.post('/auth/server-login', async (request, reply) => {
|
||||
const env = parseEnv(request.query)
|
||||
try {
|
||||
const result = await serverSignIn(env)
|
||||
return result
|
||||
} catch (err) {
|
||||
// обработка ошибок
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### 6.3. Необходимые файлы
|
||||
|
||||
| Файл | Назначение |
|
||||
|------|------------|
|
||||
| `backend/certs/certificate.cer` | Открытая часть сертификата ОУКЭП |
|
||||
| `backend/Dockerfile` | Установка КриптоПро CSP + импорт сертификата |
|
||||
| `backend/src/services/crypto-service.ts` | Сервис подписи через КриптоПро |
|
||||
| `.env` / secrets | `CERT_THUMBPRINT`, лицензия КриптоПро |
|
||||
|
||||
### 6.4. Переменные окружения (добавить в .env)
|
||||
|
||||
```env
|
||||
# Режим аутентификации: client (через браузер) или server (через ОУКЭП)
|
||||
AUTH_MODE=server
|
||||
|
||||
# Отпечаток сертификата ОУКЭП
|
||||
CERT_THUMBPRINT=<sha1-thumbprint>
|
||||
|
||||
# Только для AUTH_MODE=server:
|
||||
# Путь к файлу открытой части сертификата (для валидации)
|
||||
CERT_FILE=/app/certs/certificate.cer
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Пошаговый план действий
|
||||
|
||||
### Этап 1. Подготовка документов
|
||||
|
||||
- [ ] 1.1. Подготовить письмо-заявление на бланке организации
|
||||
- [ ] 1.2. Подготовить приказ о создании информационной системы
|
||||
- [ ] 1.3. Подготовить приказ о назначении ответственного за автоматическую подпись
|
||||
- [ ] 1.4. Собрать остальные документы (паспорт, СНИЛС, ИНН, выписка ЕГРЮЛ)
|
||||
- [ ] 1.5. Приобрести Рутокен ЭЦП 3.0 или JaCarta-2 ГОСТ
|
||||
|
||||
### Этап 2. Получение ОУКЭП
|
||||
|
||||
- [ ] 2.1. Записаться в УЦ ФНС (или выбрать коммерческий УЦ)
|
||||
- [ ] 2.2. Явиться лично с документами и носителем
|
||||
- [ ] 2.3. Получить сертификат на носитель
|
||||
- [ ] 2.4. Скопировать открытую часть сертификата (.cer)
|
||||
|
||||
### Этап 3. Регистрация в Честном знаке
|
||||
|
||||
- [ ] 3.1. Войти в ЛК Честного знака
|
||||
- [ ] 3.2. Создать учётную систему в разделе Администрирование
|
||||
- [ ] 3.3. Загрузить сертификат в учётную систему
|
||||
- [ ] 3.4. Повторить для sandbox-контура (при необходимости)
|
||||
|
||||
### Этап 4. Настройка сервера
|
||||
|
||||
- [ ] 4.1. Установить КриптоПро CSP 5.0 R2 на сервер
|
||||
- [ ] 4.2. Подключить токен с ОУКЭП (локально или через USB-over-IP)
|
||||
- [ ] 4.3. Импортировать сертификат, проверить видимость
|
||||
- [ ] 4.4. Установить корневые сертификаты Минцифры и УЦ ФНС
|
||||
- [ ] 4.5. Проверить подпись через CLI: `cryptcp -sign`
|
||||
|
||||
### Этап 5. Доработка приложения
|
||||
|
||||
- [ ] 5.1. Реализовать `crypto-service.ts` — подпись через КриптоПро CSP
|
||||
- [ ] 5.2. Добавить endpoint `POST /auth/server-login`
|
||||
- [ ] 5.3. Добавить переменные окружения (`AUTH_MODE`, `CERT_THUMBPRINT`)
|
||||
- [ ] 5.4. Обновить `Dockerfile` — установка КриптоПро CSP
|
||||
- [ ] 5.5. Обновить `docker-compose.yml` — проброс USB-токена (если локальный)
|
||||
- [ ] 5.6. Обновить frontend — кнопка «Авторизация сервера» (для режима server)
|
||||
|
||||
### Этап 6. Тестирование
|
||||
|
||||
- [ ] 6.1. Проверить авторизацию в sandbox через серверную подпись
|
||||
- [ ] 6.2. Проверить получение токена
|
||||
- [ ] 6.3. Проверить проверку КМ с новым токеном
|
||||
- [ ] 6.4. Проверить auto-refresh токена (каждые 10 часов)
|
||||
- [ ] 6.5. Проверить обработку ошибок (невалидная подпись, просрочка сертификата)
|
||||
|
||||
---
|
||||
|
||||
## 8. Ссылки
|
||||
|
||||
| Ресурс | URL |
|
||||
|--------|-----|
|
||||
| Официальная документация True API | https://docs.crpt.ru/gismt/True_API/ |
|
||||
| Статья на Хабре (подробный гайд) | https://habr.com/ru/articles/838390/ |
|
||||
| Образцы документов (Github) | https://github.com/romangorbenko/OUKEP |
|
||||
| Письмо-заявление (шаблон) | https://github.com/romangorbenko/OUKEP/blob/main/letter.docx |
|
||||
| Приказ о создании ИС (шаблон) | https://github.com/romangorbenko/OUKEP/blob/main/order.docx |
|
||||
| КриптоПро CSP | https://cryptopro.ru/products/csp |
|
||||
| База знаний Честного знака (ОУКЭП) | https://markirovka.ru/knowledge/tovarnye-gruppy/obschie-voprosy-gis/ispolzovanie-obezlichennykh-ukep |
|
||||
| Добавление ОУКЭП в учётную систему | https://markirovka.ru/knowledge/lekarstva/api-mdlp/upravlenie-obezlichennymi-ukep-dobavlenie-obezlichennoy-ukep |
|
||||
| Реестр аккредитованных УЦ Минцифры | https://digital.gov.ru/ru/activity/469/ |
|
||||
|
||||
---
|
||||
|
||||
## Затрагиваемые сервисы
|
||||
|
||||
- `backend/Dockerfile` — установка КриптоПро CSP 5.0, импорт сертификатов
|
||||
- `backend/docker-compose.yml` — возможно, проброс USB-устройства
|
||||
- `backend/src/services/crypto-service.ts` — **новый файл**, сервис подписи данных
|
||||
- `backend/src/services/auth-service.ts` — добавление `serverSignIn()`
|
||||
- `backend/src/routes/auth.ts` — новый endpoint `POST /auth/server-login`
|
||||
- `backend/.env` — новые переменные `AUTH_MODE`, `CERT_THUMBPRINT`
|
||||
- `backend/certs/` — **новая директория** с открытой частью сертификата
|
||||
- `frontend/src/pages/AuthPage.tsx` — кнопка «Авторизация сервера» (опционально)
|
||||
Reference in New Issue
Block a user