Проброс IP-адреса клиента в http-сервис 1С. Реализация для IIS

Публикация № 1159393

Разработка - Системная интеграция - Интеграция с WEB

Настраиваем веб-сервер IIS для передачи в 1С IP-адреса клиента, вызвавшего http-сервис. Разбираемся с этим же вопросом при использовании фронтэнд вебсервера на примере nginx.

На прошлой неделе была опубликована заметка "Как передать IP адрес, который вызвал HTTP запрос в 1C (для веб-сервера Apache)". Судя по "звездопаду", обрушевшемуся на неё, тема определения в приложении IP-адреса клиента является насущной для сообщества.

В упомянутой статье дан рецепт проброса клиентского IP-адреса в 1С (равно как и в любое другое приложение) с помощью кастомного http-заголовка для веб-сервера Apache.

В комментариях было задано два вопроса, оставшихся без ответа:

1. А как быть если перед сервером стоит какой-нибудь прокси, например фронтенд веб-сервер nginx?

2. Как сделать подобное для веб-сервера IIS, если это вообще возможно?

Постараюсь ответить на первый и предложить свое решение для второго. Развёрнуто и с картинками. Итак: 

Фронтенд веб-сервер

Если впереди стоит фронтенд веб-сервер, например nginx, то задача решается совсем просто. Не понадобится даже использование решения, предлагаемого в вышеупомянутой статье.

Всё, что требуется, это донастроить фронтенд сервер, включив в его настройках заполнение заголовка X-Forwarded-For, который является дефакто-стандартом для передачи реального IP-адреса исходного запроса.

После включения заголовка X-Forwarded-For на фронт-сервере, этот заголовок будет доступен как в рабочем веб-сервере, так и в коде 1С. То есть мы можем обрабатывать его и извлекать необходимый IP-адрес.

Для nginx эта настройка будет выглядеть так:

proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
 
 Выдержка справки nginx

http://nginx.org/ru/docs/http/ngx_http_proxy_module.html

Встроенные переменные

В модуле ngx_http_proxy_module есть встроенные переменные, которые можно использовать для формирования заголовков с помощью директивы proxy_set_header:

$proxy_host
имя и порт проксируемого сервера, как указано в директиве proxy_pass;
$proxy_port
порт проксируемого сервера, как указано в директиве proxy_pass, или стандартный порт протокола;
$proxy_add_x_forwarded_for
поле заголовка запроса клиента “X-Forwarded-For” и добавленная к нему через запятую переменная $remote_addr. Если же поля “X-Forwarded-For” в заголовке запроса клиента нет, то переменная $proxy_add_x_forwarded_for равна переменной $remote_addr.

 

Проброс IP-адреса клиента на веб-сервере IIS

Для того, чтобы реализовать кастомный заголовок, содержащий IP-адрес клиента, на веб-сервере IIS, понадобится установить модуль URL Rewrite. Скачать его можно на официальном сайте: https://www.iis.net/downloads/microsoft/url-rewrite.

Модуль предназначен для версий IIS 7, IIS 7.5, IIS 8, IIS 8.5, IIS 10

Скриншоты примеров сделаны на инсталляции с версией IIS 7.5.

После установки иконка модуля появится в секции IIS при  выделенном в левой панели сайте.


Для создания и заполнения заголовка нам нужно будет создать правило.

Выделяем Default Web Site и в средней панели даблкликом открываем модуль URL Rewrite.

В правой панели жмем ссылку "View Server Variables...".

Там же, в правой панели жмем "Add..." и пишем желаемое название заголовка с префиксом "HTTP_" (обязательно в верхнем регистре). У меня http-заголовок будет называться Client-IP-Address, поэтому моя переменная зовется "HTTP_Client-IP-Address"
Префикс "HTTP_" обеспечит нам создание нового http-заголовка.

После создания переменной, возвращаемся к списку правил, нажав в правой панели на ссылку "Back to rules".

Создаем новое правило нажатием на ссылку "Add Rule(s)..." и выбираем "Blank rule" в категории "Inbound rules"

Даем нашему правилу какое-нибудь содержательное название. У меня это будет "Add Client-IP-Address header".

В секции Match URL выбираем Matches the Pattern, Regular Expressions и указываем выражение, которому должен соответствовать URL для того, чтобы наше правило сработало. Нам нужно, чтобы оно работало для всех URL, поэтому в поле Pattern пишем ".*"

Секция Conditions в этом правиле нам не нужна, пропускаем её.

В секции Server Variables добавляем запись. В форме записи выбираем ранее созданную переменную "HTTP_Client-IP-Address", а в качестве значения указываем "{REMOTE_ADDR}" - серверную переменную, содержащую IP-адрес, с которого поступил запрос.

В секции Action выберем None и сохраним правило, нажав в правой панели ссылку "Apply"
Перезагружать или перезапускать что-либо нет необходимости. Правило начинает действовать сразу после применения.

Проверяем. Для проверки вызываю из браузера HTTP-сервис типовой Бухгалтерии https://<Хост:Порт>/<ОпубликованнаяИБ>/ru_RU/hs/api/v1/kpi/

Ура, работает! Мы получили в 1С созданный нами заголовок "Client-IP-Address" и он содержит IP-адрес, с которого я выполнял проверку.

Вместо выполнения всех вышеописанных интерактивных действий можно разместить в корне файлового расположения дефолтного сайта ("C:\inetpub\wwwroot", если не менялись настройки по умолчанию) файл web.config со следующим содержанием. Или добавить в секцию <system.webServer> файла, если он уже существует.

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <rewrite>
            <rules>
                <rule name="Add Client-IP-Address header">
                    <match url=".*" />
                    <serverVariables>
                        <set name="HTTP_Client-IP-Address" value="{REMOTE_ADDR}" />
                    </serverVariables>
                    <action type="None" />
                </rule>
            </rules>
        </rewrite>
    </system.webServer>
</configuration>

 

Но, пожалуй, это еще не всё.

Используем заголовок X-Forwarded-For

Научим наш веб-сервер заполнять IP-адрес клиента в зависимости от того, есть ли в запросе заголовок  X-Forwarded-For. Этот заголовок мы получим как результат настройки собственного фронтенд-вебсервера, или если запрос прошел через какие-то сторонние прокси-серверы до попадания на наш веб-сервер.

В общем случае, в заголовке X-Forwarded-For может быть список IP-адресов, разделенный запятыми. При прохождении запроса через цепочку прокси-серверов, каждый сервер добавляет в этот заголовок IP-адрес источника. Таким образом, самым первым в списке будет IP-адрес клиента, инициировавшего запрос. Соответственно, нам нужен именно этот первый IP-адрес.

Доработаем правила модуля URL Rewrite на веб-сервере.

В случае, если есть заполненный заголовок X-Forvarded-For, первым IP-адресом из него нужно обновить созданный нами ранее заголовок Client-IP-Address.

Для этого в модуле URL rewrite добавим еще одно правило. Назовем его "X_Forwarded_For to Client-IP-Address header"
Секцию Match URL заполняем так же как и у первого правила. Так же поступаем и с секцией Action.

Раскрываем секцию Conditions. Значение Logical grouping можем оставить любое, т.к. у нас будет только одно условие.
Добавляем условие.
Значение Condition input: "{HTTP_X_Forwarded_For}"
Check if input string: Matches the Pattern
Pattern: "(([0-9]{1,3}\.){3}[0-9]{1,3})"

В данном условии проверяем есть ли в значении заголовка X_Forwarded_For строка, удовлетворяющая шаблону IP-адреса и сохраняем эту строку для дальнейшего использования, обрамляя её скобками.

 
 Регулярное выражение, использованное для получения IP-адреса

Регулярное выражение "(([0-9]{1,3}\.){3}[0-9]{1,3})", использованное мною в примере, не является идеальным для проверки IP-адреса, т.к. вычленит невалидное "934.448.784.432" из строки 4266934.448.784.43254325, и приведено в демонстрационных целях, чтобы не усложнять пример. Оно выделяет содержимое исходя из шаблона "три цифры - точка - три цифры - точка - три цифры - точка - три цифры"
Принимая во внимание, что вряд ли в этом заголовке будут присутствовать строки, не являющиеся IP-адресами, такое выражение вполне можно использовать. 
Сторонникам перфекционизма могу предложить такой вариант регулярного выражения, учитывающий что числа в IP-адресе не могут превышать 255:
\b((?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))\b


Переходим к секции Server Variables и добавляем новую строку.
Выбираем ту же переменную "HTTP_Client-IP-Address", что добавляли для первого условия.
В поле Value пишем "{C:0}", что означает использование первого совпадения из секции Conditions, т.е. полученный из заголовка IP-адрес.

В итоге получаем следующий алгоритм:

Правила срабатывают в порядке их размещения.
Первым правилом наш заголовок заполняется значением серверной переменной REMOTE_ADDR, содержащей IP-адрес клиента, от которого получен запрос.
Затем второе правило, при существовании заголовка X_Forwarded_For и условии что в его содержимом находятся удовлетворяющие выражению данные, т.е. IP-адрес, обновляет наш кастомный  заголовок.

У меня сейчас нет инсталляции с фронтенд-сервером, на которой можно было бы организовать реальную проверку, поэтому я буду использовать расширение для Chrome, позволяющее добавить к запросам такой заголовок с произвольным заполнением https://chrome.google.com/webstore/detail/x-forwarded-for-header/hkghghbnihliadkabmlcmcgmffllglin.

Для проверки вызываю из браузера тот же самый HTTP-сервис типовой Бухгалтерии https://<Хост:Порт>/<ОпубликованнаяИБ>/ru_RU/hs/api/v1/kpi/
Но теперь в http-заголовках присутствует X_Forwarded_For, заполненный значением "40.112.72.205,78.129.196.11".

Как видим, в нашем кастомном заголовке Client-IP-Address оказался первый IP-адрес из цепочки присутствующих в X-Forwarded-For.
 

Содержимое файла web.config после настройки второго правила будет иметь следующий вид:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <rewrite>
            <rules>
                <rule name="REMOTE_ADDR to Client-IP-Address header">
                    <match url=".*" />
                    <serverVariables>
                        <set name="HTTP_Client-IP-Address" value="{REMOTE_ADDR}" />
                    </serverVariables>
                    <action type="None" />
                    <conditions logicalGrouping="MatchAny">
                    </conditions>
                </rule>
                <rule name="X_Forwarded_For to Client-IP-Address header">
                    <match url=".*" />
                    <conditions logicalGrouping="MatchAny">
                        <add input="{HTTP_X_Forwarded_For}" pattern="(([0-9]{1,3}\.){3}[0-9]{1,3})" />
                    </conditions>
                    <serverVariables>
                        <set name="HTTP_Client-IP-Address" value="{C:0}" />
                    </serverVariables>
                    <action type="None" />
                </rule>
            </rules>
        </rewrite>
    </system.webServer>
</configuration>

 

Пара слов о синтаксисе URL Rewrite

На официальном сайте с документацией приведено немало примеров, но найти информацию об используемом синтаксисе оказалось непросто. Поэтому позволю себе продублировать некоторые моменты здесь.

Секция Server Variables (элемент <serverVariables>) предназначена для определения серверных переменных и http-заголовков, которые требуется установить или изменить. Действие будет произведено только если запрос отвечает шаблону, установленному в секции Match URL и выполняются условия, назначенные в секции Conditions.

В поле Value можно использовать как простую строку, так и "ссылки" на серверные переменные, http-заголовки, и обратные ссылки на результаты регулярных выражений, использованных в других секциях.

Для использования "ссылки" необходимо обрамить имя переменной, заголовка или обратной ссылки в фигурные кавычки.

Имя серверной переменной указывается "как есть". В приведенном примере использовались указание серверной переменной REMOTE_ADDR - {REMOTE_ADDR}.

Для указания http-заголовка используется префикс HTTP_ 

Для указания заголовка http-ответа используется префикс RESPONSE_

Обратные ссылки на результаты работы регулярных выражений секции Conditions обозначаются {C:n}, секции Match URL - {R:n}

Более подробно - в документации: URL Rewrite Module 2.0 Configuration Reference (english).

 

Специальные предложения

Комментарии
Избранное Подписка Сортировка: Древо развёрнутое
Свернуть все
1. Steelvan 01.12.19 17:43 Сейчас в теме
Плюсую за слово "насущной", вместо "актуальной".
Минусую за слово "кастомного", вместо "самодельного"
:)
2. -vito- 450 01.12.19 17:53 Сейчас в теме
(1) Игорь,
Вы вероятно не поверите, но сначала в черновиках было "самодельный", потом оно смешалось с "кастомным", в конце осталось только то что осталось :)
Я еще с десяток ошибок нашел после отправки статьи на модерацию (ой, а можно такое использовать?) . :)
3. sergvagner2018 01.12.19 21:14 Сейчас в теме
(2) в данном случае содержание статьи никак не пострадало.

Звезда отправлена!
maxopik2; -vito-; +2 Ответить
4. Sibars 280 02.12.19 06:52 Сейчас в теме
Спасибо за дополнение, однозначно, плюс)
5. Cyberhawk 118 12.12.19 09:21 Сейчас в теме
6. Luisor 24.05.20 07:26 Сейчас в теме
Спасибо за ссылку на модуль URL Rewrite
Оставьте свое сообщение

См. также

daСклонение: склонение ФИО, должностей, чисел, прилагательных, существительных на языке 1С + ТестЦентр Промо

Универсальные функции v8 1cv8.cf Абонемент ($m)

Функция предназначена для склонения выражений, которые часто требуется при формировании печатных форм договоров и прочих печатных форм. Функция склоняет по падежам ФИО, должности, числительные, валюты, единицы измерения, предметы. Также функция склоняет глаголы и прилагательные по числам и родам и существительные по числам. Имеется режим определения рода переданного выражения. Поддержка форматной строки для вывода результата. Функция не использует внешние библиотеки и веб-сервисы, написана на чистом языке 1С, и поэтому легко встраивается в любую конфигурацию или внешнюю обработку. Правила склонения оформлены в виде таблицы и могут быть легко изменены при необходимости.

1 стартмани

14.02.2015    99032    96    daMaster    88    

Сравнение реального дохода со средним доходом из API.HH.RU

Зарплата Управленческие v8 v8::СПР ЗУП3.x УУ Абонемент ($m)

Внешняя обработка на управляемой форме для 1С:Предприятие 8.3 по интеграции с HH.RU используя HH REST API. Ключевые функции: получение списка вакансий по должностям (Ключ для работы не нужен); расчет среднего дохода; Тестирование проводилось на платформе 1С:Предприятие 8.3 (8.3.13.1513) Зарплата и управление персоналом, редакция 3.1 (3.1.11.68) совместно с API.HH.RU.

1 стартмани

11.11.2019    3643    4    solaru    2    

Конфигурация для рекламного агентства

Управление услугами и сервисом Управление взаимоотношениями с клиентами (СRM) Производство готовой продукции (работ, услуг) Управление взаимоотношениями с клиентами (СRM) Производство готовой продукции (работ, услуг) v8 Реклама, PR и маркетинг УУ Абонемент ($m)

Данная конфигурация выполнена для решения тестового задания: Цель задания: 1) Понять, на каком из клиентов сколько мы заработали;  2) Понять, по какому виду СМИ сколько мы заработали;  3) Проследить по каждой услуге: у кого за сколько купили и кому за сколько продали, с возможностью перейти в соответствующий документ. Реализовано с помощью: 1. Справочники - контрагенты, номенклатура 2. Документы - Поступление услуг, реализация услуг 3. Отчеты - отчет по контрагентам, номенклатуре и движений.

1 стартмани

21.05.2019    3917    0    solaru    0    

Загрузка номенклатуры в УТ 10.3 из Excel файла с генерацией штрихкодов

Загрузка и выгрузка в Excel Обработка справочников Оптовая торговля Розничная торговля Учет ТМЦ Оптовая торговля Розничная торговля Учет ТМЦ v8 УТ10 Россия Абонемент ($m)

Обработка позволяет генерировать новые номенклатурные позиции на основе данных из файла Excel с последующей генерацией штрихкодов (ШК). Может быть полезна при больших поступлениях товаров на склад, где ручное создание и присваивание штрихкода  (ШК) может занимать много времени.

1 стартмани

24.03.2017    7523    6    solaru    0    

Под капотом управляемых форм

Практика программирования v8 1cv8.cf Бесплатно (free)

Управляемые формы уже давно и плотно вошли в жизнь 1С-разработчика. Однако, судя по недавним публикациям на Инфостарте, многие до сих пор мало знакомы с ними. Предлагаю разобраться с тем, что же это такое.

26.08.2013    260382    0    Evil Beaver    266    

[NotaBene] Универсальный отчет по таблице значений

Практика программирования v77::ОУ v77::БУ v77::Расчет 1cv7.md Россия Абонемент ($m)

1C v.7.7 Готовое решение. Не требует настройки. Не требует допрограммирования. Данная обработка решает часто встречающуюся задачу вывода в "красивом" виде таблицы значений (полученной, например, из запроса). Поддерживается произвольное группирование данных, отключение/включение группировок, в т.ч и создание "шахматок" (типа "продажи понедельно"). Обработка может использоваться как и в отладочных целях (для нормального просмотра ТЗ), так и в составе вполне рабочих отчетов. По крайней мере, я неоднократно клиентам данную обработку ставил вместо того, чтобы каждый раз писать замороченные выводы данных. И клиенты довольны, и мне - проще...

2 стартмани

07.05.2007    27908    1    CheBurator    61