Публикация сайта через туннель и предоставление пользователям доступа к VPN — это две разные схемы, которые делят один кабель. В первой публичный обратный прокси принимает запрос посетителя и передаёт его через туннель к источнику, до которого никто не может добраться напрямую. Во второй пользователь должен подключиться к VPN, прежде чем приложение вообще станет доступным. Смешение этих двух описаний — это путь, которым частный бэкенд в итоге оказывается публично выставленным.

Две модели, которые на схеме выглядят одинаково

Нарисуйте стрелки, прежде чем что-то выбирать. Модель публичной публикации идёт от браузера к прокси по HTTPS, затем от прокси к источнику через туннель, и источник никогда не принимает соединение из интернета. Модель только с VPN идёт от клиента к шлюзу, и приложение доступно только изнутри этого пути. Ноутбук пользователя находится в той же сети, что и приложение, и в этом весь смысл той модели.

Модели различаются тем, кто выполняет аутентификацию и где. В первой прокси — это публичный вход, и он передаёт любой приходящий запрос, включая враждебный, согласно настроенной на нём политике. Во второй самими воротами является доступность, и это грубый, но настоящий допуск.

Где останавливается TLS и что она на самом деле доказывает

TLS между браузером и прокси защищает этот переход и позволяет браузеру проверить сайт, который он собирался посетить. Если прокси завершает TLS, запрос существует в читаемом виде внутри этого процесса, прежде чем быть переданным. Вторая сессия TLS к источнику может защитить следующий переход и отдельно проверить конечную точку приложения. Ни одна из сессий не решает, какой человек может пользоваться приложением. Сертификат с подстановочным знаком на прокси тоже не распространяется на этот второй переход.

Это та часть, которую люди сжимают в слово зашифровано. Конфиденциальность, целостность и идентичность сервера — это свойства транспорта; авторизация — решение приложения. Частный адрес за туннелем меняет кто может добраться до сокета, а не кто может войти, когда уже добрался.

Доверяйте переданным заголовкам только от прокси

Приложения, которые журналируют или авторизуют по адресу клиента, обычно читают заголовок, который добавляет прокси. Этот заголовок — просто текст, поэтому всё, что может добраться до источника напрямую, может заявить любой адрес. Ограничьте источник так, чтобы подключаться мог только туннельный адрес прокси, и настройте приложение принимать заголовок только с этого адреса.

curl -s -o /dev/null -w '%{http_code}
' -H 'X-Forwarded-For: 203.0.113.9' http://172.20.5.40/

Если этот запрос успешен с хоста, который не является прокси, источник доверяет заголовку, который должен был бы игнорировать. Исправьте слушателя, прежде чем трогать приложение. Отказ — гораздо лучший результат, чем строка журнала с поддельным адресом.

Держите источник доступным ровно из одного места

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

ss -ltnp | grep -E ':(80|443)'

Сделайте такой же обзор для интерфейсов управления, которые обычно и оказываются случайно выставленными. Затем запишите две модели отдельно: публичный сайт через прокси и интерфейс администрирования, доступный только через туннель. Фраза о том, что сервер находится за VPN, ничего из этого не говорит.

Похожие статьи