Адмінскі паддомэн не спыняе 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 абмяжоўвае чытанне адказаў паміж 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, кукі толькі для хоста, токен на кожнае змяненне, уваходны фільтр, якому не давяраюць як асобе, і аўтарызацыя, што вырашаецца на кожны запыт.