Как получить IP-адрес отправителя в HTTP-сервисе 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке собственных HTTP-сервисов на платформе 1С программисты часто сталкиваются с необходимостью идентификации клиента по его IP-адресу. Это может быть нужно для логирования, ограничения доступа по белому списку или привязки запроса к конкретному рабочему месту в локальной сети. Однако штатные средства встроенного языка 1С не предоставляют прямой функции вроде ПолучитьIPАдресЗапроса(). Это связано с архитектурными особенностями: 1С работает не напрямую с сетевым сокетом, а через прослойку в виде веб-сервера (Apache или IIS) и модуля расширения веб-сервера.

В этой статье мы подробно рассмотрим, как обойти это ограничение, правильно настроить веб-сервер и извлечь заветный IP-адрес из структуры запроса.

Почему 1С "не видит" IP-адрес напрямую?

Давайте проанализируем путь прохождения запроса. Когда внешнее устройство отправляет HTTP-пакет, его первым встречает веб-сервер. Веб-сервер обрабатывает запрос и передает его модулю расширения 1С (wsap24.dll для Apache или isapi_1c.dll для IIS). Для 1С "клиентом" технически является сам веб-сервер или локальный процесс. Именно поэтому стандартные методы получения соединений часто возвращают 127.0.0.1 или адрес сервера приложений.

Чтобы решить задачу, нам нужно заставить веб-сервер "пробросить" адрес реального клиента внутрь 1С в виде HTTP-заголовка.

Способ 1. Настройка веб-сервера Apache

Если ваша публикация работает под управлением Apache, мы можем использовать модуль преобразования ссылок mod_rewrite для создания пользовательского заголовка. Рассмотрим по шагам, как это сделать в конфигурационном файле httpd.conf или в файле описания публикации .htaccess.

Нам необходимо проверить, не пришел ли запрос через прокси-сервер (в таком случае адрес будет в заголовке X-Forwarded-For), и если нет — взять системную переменную REMOTE_ADDR. Проанализируем пример настройки:


# Включаем механизм преобразования
RewriteEngine On

# Если заголовок X-Forwarded-For пуст, создаем переменную RA со значением IP-клиента
RewriteCond %{HTTP:X-Forwarded-For} =""
RewriteRule .* - [E=RA:%{REMOTE_ADDR}]

# Если X-Forwarded-For не пуст, вырезаем из него первый IP (самый первый клиент в цепочке)
RewriteCond %{HTTP:X-Forwarded-For} !=""
RewriteCond %{HTTP:X-Forwarded-For} "(([0-9]{1,3}\.){3}[0-9]{1,3})"
RewriteRule .* - [E=RA:%1]

# Устанавливаем итоговый заголовок, который будет виден в 1С
RequestHeader set X-Custom-Remote-Addr "%{RA}e" env=RA

После такой настройки в коде 1С мы сможем легко получить значение этого заголовка. Рассмотрим этот процесс далее.

Способ 2. Настройка IIS (Internet Information Services)

Для веб-сервера IIS ситуация аналогична. Нам потребуется установленный модуль URL Rewrite. Рассмотрим алгоритм действий:

  1. Откроем диспетчер служб IIS и выберем нашу опубликованную базу.
  2. Перейдем в раздел URL Rewrite.
  3. В правой панели выберем View Server Variables и добавим переменную HTTP_X_REAL_IP.
  4. Создадим правило (Inbound Rule), которое для всех входящих запросов будет устанавливать значение этой переменной из системной переменной {REMOTE_ADDR}.

В результате IIS начнет добавлять к каждому запросу заголовок X-Real-IP, который станет доступен внутри платформы 1С.

Способ 3. Получение IP-адреса в коде 1С

Когда веб-сервер настроен, нам остается только корректно прочитать данные в методе-обработчике HTTP-сервиса. Объект HTTPСервисЗапрос содержит свойство Заголовки, которое представляет собой соответствие (ключ-значение).

Разберем пример кода на стороне 1С:


Функция ЛюбойМетодГет(Запрос)
    
    // Пытаемся получить адрес из разных возможных заголовков
    IPАдрес = Запрос.Заголовки.Получить("X-Custom-Remote-Addr");
    
    Если IPАдрес = Неопределено Тогда
        // Проверяем стандартный заголовок для прокси-серверов (Nginx и др.)
        IPАдрес = Запрос.Заголовки.Получить("X-Forwarded-For");
    КонецЕсли;
    
    Если IPАдрес = Неопределено Тогда
        // Проверяем еще один распространенный вариант
        IPАдрес = Запрос.Заголовки.Получить("X-Real-IP");
    КонецЕсли;
    
    Если IPАдрес <> Неопределено Тогда
        // Если в заголовке список IP через запятую, берем первый
        ПозицияЗапятой = Найти(IPАдрес, ",");
        Если ПозицияЗапятой > 0 Тогда
            IPАдрес = СокрЛП(Лев(IPАдрес, ПозицияЗапятой - 1));
        КонецЕсли;
        ЗаписьЖурналаРегистрации("HTTP.Запрос", УровеньЖурналаРегистрации.Информация, , , "Запрос от IP: " + IPАдрес);
    Иначе
        ЗаписьЖурналаРегистрации("HTTP.Запрос", УровеньЖурналаРегистрации.Предупреждение, , , "Не удалось определить IP отправителя");
    КонецЕсли;

    // Далее логика обработки запроса...
    Ответ = Новый HTTPСервисОтвет(200);
    Возврат Ответ;
    
КонецФункции

Способ 4. Передача IP-адреса со стороны клиента

Если у нас нет доступа к настройкам веб-сервера (например, при использовании облачного хостинга), мы можем использовать "клиентский" подход. В этом случае устройство, отправляющее запрос, должно само определить свой IP и передать его в параметрах или теле запроса.

Рассмотрим ситуацию, когда клиентом выступает другая база 1С. Мы можем программно узнать внешний IP клиента, используя публичные API-сервисы (например, 2ip.ua). Проанализируем функцию получения внешнего IP:


Функция ПолучитьВнешнийIP() Экспорт
    Результат = "";
    Попытка
        Соединение = Новый HTTPСоединение("api.2ip.ua",,,,,,Новый ЗащищенноеСоединениеOpenSSL);
        Запрос = Новый HTTPЗапрос("/provider.json?ip=");
        Ответ = Соединение.Получить(Запрос);
        
        Если Ответ.КодСостояния = 200 Тогда
            ТекстJSON = Ответ.ПолучитьТелоКакСтроку();
            // Парсим простейшим способом или через ЧтениеJSON
            Чтение = Новый ЧтениеJSON;
            Чтение.УстановитьСтроку(ТекстJSON);
            Данные = ПрочитатьJSON(Чтение);
            Результат = Данные.ip;
            Чтение.Закрыть();
        КонецЕсли;
    Исключение
        // Обработка ошибки доступа к интернету
    КонецПопытки;
    Возврат Результат;
КонецФункции

После получения этого адреса клиент добавляет его к своему основному запросу:


МойIP = ПолучитьВнешнийIP();
ЗапросКСервису = Новый HTTPЗапрос("/hs/MyService/v1/data?clientIP=" + МойIP);
// Отправка...

Важные замечания по безопасности

Проанализируем риски использования заголовка X-Forwarded-For. Важно понимать, что любой пользователь может вручную подставить этот заголовок в свой запрос (так называемый IP Spoofing). Если ваша логика безопасности строится на проверке IP, никогда не доверяйте этим данным безусловно, если запрос пришел из открытой сети.

Рекомендация: На стороне 1С проверяйте IP-адрес только в том случае, если вы уверены, что ваш веб-сервер или прокси-сервер (например, Nginx) жестко перезаписывает эти заголовки, удаляя те, что прислал клиент.

Резюме

Мы рассмотрели несколько подходов к решению задачи. Выясним, какой из них лучше:

  1. Настройка веб-сервера (Apache/IIS) — самый правильный и надежный метод. Он не требует изменения кода клиентов и работает автоматически для всех входящих соединений.
  2. Передача параметра в запросе — подходит для работы в закрытых сетях или когда нет возможности администрировать веб-сервер.
  3. Использование внешних сервисов — полезно для определения внешнего (белого) IP-адреса клиента перед отправкой данных на сервер.

Используя приведенные выше инструкции и примеры кода, вы сможете эффективно реализовать механизм определения местоположения и идентификации отправителей в ваших HTTP-сервисах на платформе 1С.

← На главную