Галоўная / Артыкулы

Чаму Next.js Server Actions патрабуюць автарызацію ў кожным тэле функцыі

Аналіз прыклада захоплення кантролю над акаунтом паказвае, як неавтантыфікованыя Next.js Server Actions адкрываюць можлівасць выкарыстоўвання прывілейованых операцый, і дзе павінна знаходзіцца перацэнка прав, каб гэта запобiec.

Выдавец: REACTAPP.TOP4 хв чытання994 слоў

Крыніцы: Unauthenticated Next.js Server Actions Leading to Zero Click Account Takeover

Server Actions у Next.js дазваляюць компаненту React безпасабліва вызываць функцыю сервера, не патрабуючы наявнасці API-маршрута межы. Гэта зручнае рашэнне усувае едын стаціонарны месца, дзе багато каманд звыклі выканаць пераконтроль прав, — адзін маршрутны працоўнік. Калі пераконтроль не пераводзится ў тэла функцыі разам з логікай, функцыю можа вызваць кожны, хто знае ўсё яе ідэнтыфікатора. У прыкладзе нижчэй показана самэ гэтая проблема на рэальным портале падпісоў, дзе два незахаваныя дзеяння былі складзеныя ў адной схеме для безклікаўскага перэялявання адной кантактнай інформацыі, а пасля практычна паказаныя захоўніцкія правіла, якія моглі б гэта запобiec.

Як на самай працы дзеяння сервера

У рамках App Router серверная дзеянне — это функцыя сервера, якая запускаецца безпосередна з компаненту. Фрэймворк прызначае кожнай дзеянню 40-символьны ID у шыстнадцатым канале, додае гэты ID у пакет для кліента і ператварае запуск на запит POST, який несе загаловку Next-Action. Ключовы момант закладзены ў тым, што дзеянні запускаюцца на аднойчыну з гэтай загаловкі, а не за счытам шляху URL, а тэла запита — это проста аргументы функцыі, якія перадаюцца па порядку.

У такім дзеянні є наследкі, які легка працяе пазіць. Не існуе файлу з маршрутом, які можна было бы обернуць у мідлвэр, таму няма нічога, што магло б стаць пунктом контролю, дзе захіст на рэверсі фрамворку запускаўся б перад вашым кодам. Якщо перакананне ў правах не напісанае внутры самай функцыі, то контролу ўзагалі няма. Кожны, хто выкарыстоўвае ID-ы дзеяння з готавага пакету і перабудоўвае форматы аргументаў з мініфікараваных месцаў вызова, можа праказаць запит без жадных кукі-сесыяў.

Першае дзеянне: электранацыя прыходзіць, прывілейаваны запис выходзіць

У дакладна гэтым портале запыт, выкарыстоўваючы які не было кукі, заголовка з правамі і нічога іншага, што магло б аўтентыфікаць вызывальніка, дасягнуў першага дзеяння. У тэле была толькі адреса электранацыі і булева значэнне.

POST /particuliers/integrale-web-mensuel-2116 HTTP/2
Host: subdomain.target.com
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36
Next-Action: 42a24b711d12f695d798b371e38b584c551ebb6a
Content-Type: text/plain;charset=UTF-8
Accept: text/x-component
["victim@gmail.com",true]

У адпаведзенні быў вярнуты цэлы запис абліквату для той электранацыі.

{
"user_id": "auth0|000000000000000000000001",
"email": "researcher@example.com",
"identities": [
{ "provider": "auth0", "connection": "www-target-com" }
],
"app_metadata": {
"subscriber_number": "900000000",
"custom_user_id": "00000000–0000–4000–8000–000000000000"
}
}

Форма гэтаго палетайла ёсць ключовым сігналам. Поле такое як identities і app_metadata не адналежаць публічнаму API аутантыкацыі прадастаўца ідэнтычнасцяў; яны прыходзяць з його API адарожнення, адміністратыўнага інтэрфейсу, да якога прайшоцца за дапамогою токена машына-машына, які мае правы на чытанне і адчыненне дадзеных корыстувачаў. Адзержанне іх з непрацавісага вызову значыць, што на сервере быў прывілейваваны токен, і анонімная функцыя таямна яго выкарыстоўвала. Кроме таго, у адпаведзі таксама былі пераданы два значэння, неабходныя для наступных дзеянь: ID корыстувача і назва з’ўязку.

Наступнае дзеянне: задаўанне пароля будзь-каго з корыстувачаў

Наступнае дзеянне прымало об’ект і строку. У об’екте быў пароль і з’ўязак; строка — ID корыстувача. Калі гэта было адправлена на тестовы акаунт, які ўсё ще не быў аутантыфікованы, выглядала гэта так.

POST / HTTP/2
Host: subdomain.target.com
Next-Action: 89abcdef0123456789abcdef0123456789abcdef
Content-Type: text/plain;charset=UTF-8
Accept: text/x-component
[{"password":"<REDACTED>","connection":"www-target-com"},"auth0|000000000000000000000001"]

Запрос нічога не падкрасіў: жадных кукусоў сесіі, жадных ведамае пра існуючы пароль, жадных токена для перазначэння або підтверджэння па электранайцы, а таксама жадных запросаў на паўторную пераверку. Сэрвер адпавязаў пасля успеху і з актуальным об’ектам пользователя. Ключовая адсутнасць — у тым, звядзе камплектуецца ID пользователя: гэта другі аргумент, які надае вызывач, а не даныя, чытаныя з сесіі або з пола subject у падписанам токене. Функцыя зміняе той акаунт, які ёй прадаўаны.

Тая ж дзеянне, інша польна, перехоплены шлях вясці

Паколькі першы аргумент праходзіць без змян да функцыі апдэйта пользователя у постачальніку ідэнтычнасці, якае б польна вы там не разместилі, гэта самае польна будзе зменяцца. Адменстаўкай пароля на адресу электранайцы апдэйтуецца толькі адреса электранайцы акаунта.

POST / HTTP/2
Host: subscribe.target.com
Next-Action: 89abcdef0123456789abcdef0123456789abcdef
Content-Type: text/plain;charset=UTF-8
Accept: text/x-component
[{"email":"attacker@example.com","connection":"www-target-com"},"auth0|000000000000000000000001"]

Рэзультат быў тым жа успехам, пры тым жа абсэнце будзь-якай пераканальніцы пра права ўласнасці. Штосьць такое гэта ўжо хужа, чым здаецца на першы погляд: адреса на рахунку — гэта там, дзе надаюцца канфігурацыі пароляў, таму, калі яна пераходзіць у рукі хакера, процес вярнення праваў справжнему власніку больш не ведае да яго. Паколькі пароль установліваецца безпосередна, а не за дапамогою запозычанай сесіі, права на доступ не выгораюць самыя по сабе.

Урокі, якія дае гэты прыклад

Дзеянні сервера — это бэкенд-канцэнтры, якія выглядаюць як функцыі, і ўсе яны заслуговуюць на тое жа падазрэнне. Распісваце перакананне ў правах у кожным дзеянні, якое чыпае прывілейаваныя данні або стан, і пераканвайцеся ў тым, хто выклікае дзеянне, прычымоўваючы нічога іншага. Выводзіце ідэнтыфікатор выконваючага пользователя з сесіі або паверыранага токена, ніколі не з аргумента, які контролюець кліент, таким чынам запит не можа паведаміць ID жертвы і заставіць сервер яго выконаць. Храніце прывілейаваныя токены падаючага сервісу далёка ад шляхоў коду, якія є доступныя без аутэнтыкацыі. А таксавайце ID дзеяння як публічныя, адтакуль ўсе яны надаюцца браузеру; анонімнасць не є кантролем доступу. Кожная функцыя, якую можа паведаміць кліент, — гэта функцыя, якую можа вызваць атакавальнік, і ўсё, што стоіць межы між ямі і вашымі даннемі, — гэта перакананне, якое вы напісалі ў тэле запита.