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

Первое: имя хоста только называет арендатора

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

Общая вспомогательная функция, возвращающая и контекст, и разрешение из одного поиска имени хоста, — это начало ошибки.

Второе: членство приходит из сессии

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

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

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

Третье: сеть ничего не доказывает о человеке

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

DNS — третий факт транспорта. Приватный ответ требует приватного маршрута, а публичный фронтенд требует поддерживаемого пути к источнику. Ни один из них не несёт разрешения.

Одно предложение на стену: сеть решает, как приходит запрос, а приложение решает, что он может читать.

Четвёртое: прогоните матрицу на обоих входах

Используйте контролируемые учётные записи, чтобы проверить A на A, B на B, A на B, неизвестное имя хоста и аутентифицированную учётную запись без членств. Четвёртый и пятый должны отказать закрыто и никогда не переходить к арендатору по умолчанию. Прогоните ту же матрицу и через вход VPN, с одной банкой сессии на каждую учётную запись:

curl -s -o /dev/null -w '%{http_code}' -b jar.txt https://clinic-b.example.com/records/42
curl -s -o /dev/null -w '%{http_code}' -b jar.txt https://clinic-a.example.com/records/42

Затем измените одну запись в списке разрешений и запустите снова. Результат, который сдвигается, означает, что сетевая проверка принимает решение об авторизации.

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

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