Общие поддомены, два входа: кто какие записи видит?
Поддомен выбирает брендинг, а подтверждённое членство выбирает данные. Выполняйте одни и те же проверки арендатора независимо от того, приходит ли запрос с офисного адреса или через VPN.
Клиника 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
Затем измените одну запись в списке разрешений и запустите снова. Результат, который сдвигается, означает, что сетевая проверка принимает решение об авторизации.
Повторяйте матрицу после любого изменения фронтенда, потому что второй путь кода, пропускающий проверку, — самый частый способ эрозии этой границы. Ожидаемый результат скучен: каждый вход даёт одинаковые ответы.