Админският поддомейн не спира CSRF: четири проверки преди старт
Ново име на хост е нов origin, често същият сайт, затова same-site бисквитки и прости формуляри го пресичат. Проверете токените, бариерата и оторизацията.
Преместването на административния интерфейс на admin.example.com е истинско подобрение: държи админ бисквитките далеч от публичните страници, дава на двете приложения отделни кешове и позволява по-строга мрежова политика да се насочи към едно име на хост. Но това не е контрол срещу CSRF и не прави кода на публичния сайт безопасен за оставяне отворен пред влязъл администратор. Разделението променя това, което браузърът смята за граница, а не това, което сървърът проверява, затова направете тези четири проверки, преди да го обявите за готово.
Четете origin и сайт като две различни думи
Origin е схема, хост и порт, така че https://www.example.com и https://admin.example.com са различни origin. Сайт в смисъла на SameSite е схема плюс регистрируем домейн, така че тези две имена на хост обикновено са един сайт. Тази разлика е целият капан: атрибутът SameSite няма да ви помогне между съседни поддомейни, защото браузърът изобщо не смята заявката за междусайтова. Насочете админ интерфейса към наистина различен регистрируем домейн, например admin-example.net, и заявката наистина става междусайтова, и точно там SameSite=Lax или Strict започва да върши работа, на която може да се разчита.
Тествайте го в браузъра, вместо да разсъждавате.
Заредете публичния сайт, отворете инструментите за разработчици и вижте кои бисквитки браузърът прикачва към заявка към админ хоста. Ако бисквитката няма атрибут Domain, тя е само за хоста и остава на собственото си име; ако носи Domain=example.com, тя пътува до всеки съседен, и новият поддомейн не ви е донесъл нищо за тази бисквитка.
Отделете четенето на отговора от изпращането на заявката
Политиката за един и същ произход ограничава четенето на отговори между origin. Тя не спира изпращането на заявка и не пречи на формуляр да носи удостоверения, които браузърът вече държи. Проста заявка, с тип съдържание на формуляр или обикновен GET, се доставя без предварителна проверка; CORS след това решава дали извикващият скрипт може да прочете отговора. CSRF живее изцяло от страната на изпращането.
Затова сървърът се нуждае от явна проверка за операции, които променят състояние. Токен за синхронизация, свързан със сесията, или бисквитка за двойно подаване, сравнявана на сървъра, покрива случая; сравнение на Origin или Referer си струва да се добави като втора бариера, но не като единствена, защото не всяка заявка носи заглавката и не всеки прокси я запазва. Ръководството на OWASP за предотвратяване на CSRF разглежда SameSite като един слой сред няколко точно по тази причина.
Решете какво всъщност доказва мрежовата бариера
Списък с разрешени VPN изходи пред админ хоста е добра контрола и слабо твърдение за самоличност. Той доказва, че заявката е дошла от адрес, който VPN дава, който може да се споделя от всички на този изход, и не казва нищо за това кой човек или устройство стои зад него. Отнасяйте се към него като към входен филтър, не като към автентикация.
Дръжте го независим от проверките на ниво заявка. Ако списъкът е единственото нещо между нападател и крайна точка, която променя състояние, един погрешно конфигуриран маршрут, един клиент със split-tunnel или един зает лаптоп премахва контролата напълно.
Записвайте и отказите извън очакваните диапазони. Внезапният им поток е най-полезният сигнал, че някой проверява границата, която току-що построихте, а тишината е сигнал, че филтърът изобщо не се достига.
Дръжте бисквитките, влизането и оторизацията явни
Обхватът на бисквитката решава по-голямата част от резултата. Бисквитка на родителски домейн се изпраща към админ хоста, така че инжектиран скрипт на публичния сайт може да действа със сесията на администратор; бисквитка само за хоста не може. Предпочитайте формата само за хоста, добавете атрибута Secure и използвайте префикса __Host-, където платформата го поддържа, защото този префикс изисква Secure, Path=/ и без атрибут Domain. Четете заглавката на отговора, а не буркана с бисквитки: Set-Cookie: __Host-admin_session=...; Secure; Path=/; HttpOnly; SameSite=Lax, без атрибут Domain. Браузърът изхвърля бисквитка __Host- с Domain, така че бисквитка, която все още се вижда на съседни хостове, е доказателство, че префиксът никога не е бил приложен.
След това дръжте оторизацията на сървъра, за всяка заявка, на всяка административна крайна точка, не само при влизане. Заявка от разрешена мрежа все още трябва да бъде автентикирана и оторизирана за операцията, която иска; името на хоста не е субект. Ако публичното и админ приложението споделят поток за влизане или хранилище на сесии, запишете тази връзка, защото тя е най-краткият път от бъг в публичния сайт до административно действие.
Проверете границата отново след разделянето
Пуснете негативните тестове, не само щастливия път: междусайтов формуляр без токен трябва да бъде отхвърлен, токен от друга сесия трябва да бъде отхвърлен и никой GET не бива да променя състояние. Проверете атрибутите на бисквитките в инструментите за разработчици, потвърдете, че проверката на Origin задейства при несъответстваща заявка, и опитайте админ хоста отвън диапазона на VPN, за да видите филтъра в действие.
Нищо от това не премахва дефект XSS в самото админ приложение. Отделното име на хост е граница за изолация от страна на браузъра с реална стойност и не е заместител на предотвратяването на опасно изпълнение на код или на защитата на заявките от страна на сървъра. След разделянето списъкът е по-кратък, отколкото изглежда: отделен origin, бисквитки само за хоста, токен при всяка промяна, входен филтър, на който не се доверявате като самоличност, и оторизация, решавана при всяка заявка.