Cloudflare Turnstile није готов после widget-а — Siteverify затвара рупу

|Аутор: Уредништво QUASA|5 мин читања| 1
Cloudflare Turnstile није готов после widget-а — Siteverify затвара рупу

Cloudflare Turnstile штити формулар тек када сервер пошаље токен на Siteverify, прихвати само успешан одговор и упореди враћени hostname са очекиваним доменом. Према Cloudflare-овом упутству за Siteverify, сам widget није довољан: токен важи пет минута и може да се потврди само једном.

Проверу поставите пре сваке радње која чува податке или шаље поруку из формулара. Посетилац, али и аутоматизовани клијент, може директно да позове серверску руту без отварања странице. Ако страница већ има Content Security Policy (CSP), учитавање Turnstile скрипте и оквира треба уклопити у ту политику.

Уградите widget у формулар

За статичан формулар довољно је имплицитно учитавање. Cloudflare-ово упутство за уградњу показује да widget унутар елемента form аутоматски додаје скривено поље cf-turnstile-response. То поље носи токен у истом захтеву као и остали подаци формулара.

Минималан пример, са вредностима које ваша апликација убацује при приказу странице, гласи: <script nonce='{{NONCE}}' src='https://challenges.cloudflare.com/turnstile/v0/api.js' async defer></script> <form action='/kontakt' method='post'><input name='email' type='email' required><div class='cf-turnstile' data-sitekey='{{SITEKEY}}'></div><button type='submit'>Пошаљи</button></form>.

SITEKEY је јавни кључ widget-а и припада HTML-у. Тајни кључ припада искључиво серверској конфигурацији, јер се њиме потврђује токен. NONCE је вредност коју сервер задаје за конкретан одговор странице; њена улога у CSP-у објашњена је ниже. Скрипту api.js учитавајте са приказане адресе, без локалног кеширања или прослеђивања преко сопственог домена, како би widget могао да добија ажурирања.

Поставите Siteverify испред обраде података

Сервер чита cf-turnstile-response и шаље POST захтев на https://challenges.cloudflare.com/turnstile/v0/siteverify. У телу захтева шаље secret, односно тајни кључ, и response, односно примљени токен. Siteverify враћа JSON; обрада формулара сме да почне тек када је success дословно true и када hostname одговара вредности задатој на серверу.

Следећи минимални пример претпоставља серверско окружење са Fetch API-јем и објектима Request и Response. saveForm је постојећа функција ваше апликације за чување или слање података. TURNSTILE_SECRET_KEY и TURNSTILE_HOSTNAME поставите у серверску конфигурацију пре покретања апликације; hostname треба да буде тачно дозвољено име хоста, а не вредност преузета из заглавља долазног захтева.

async function submit(request, env, saveForm) { const form = await request.formData(); const tokens = form.getAll('cf-turnstile-response'); if (tokens.length !== 1 || typeof tokens[0] !== 'string' || !tokens[0]) return new Response('Провера није успела', {status: 400}); const controller = new AbortController(); const timer = setTimeout(() => controller.abort(), 8000); let result; try { const reply = await fetch('https://challenges.cloudflare.com/turnstile/v0/siteverify', {method: 'POST', body: new URLSearchParams({secret: env.TURNSTILE_SECRET_KEY, response: tokens[0]}), signal: controller.signal}); if (!reply.ok) throw new Error('Siteverify'); result = await reply.json(); } catch { return new Response('Провера није доступна', {status: 503}); } finally { clearTimeout(timer); } if (result.success !== true || result.hostname !== env.TURNSTILE_HOSTNAME) return new Response('Провера није успела', {status: 400}); form.delete('cf-turnstile-response'); await saveForm(form); return new Response('Прихваћено', {status: 200}); }

Условни пример прекида чекање на Siteverify после осам секунди; прилагодите тај рок својој апликацији. Прекид везе, неуспешан HTTP одговор и неисправан JSON воде у грану у којој saveForm није позван. У стварној рути задржите и постојећу проверу осталих поља, контролу приступа ако је потребна и заштиту од захтева са другог сајта: Turnstile не замењује те механизме.

Проверите шта је Siteverify вратио

Постојање скривеног поља не говори да је његов садржај важећи. Siteverify утврђује да ли је токен прихватљив и одбија истекао или већ употребљен токен. Код грешке timeout-or-duplicate може да прати оба случаја, па га не користите као једини начин да разликујете истек од поновног слања. За нови покушај потребан је нов токен, односно освежен widget.

Hostname у одговору означава место на ком је издат изазов. Поређење са серверски задатим именом спречава да рута прихвати успешну потврду из контекста који за ту руту није дозвољен. Ако исти сервер служи више легитимних домена, задајте листу њихових тачних имена. Када користите Turnstile action да раздвојите операције, упоредите и враћени action са операцијом коју рута очекује.

Сачувајте постојећи CSP

Иста nonce вредност повезује CSP заглавље и Turnstile скрипту, док frame-src дозвољава њен iframe.

За страницу која већ користи CSP, Cloudflare-ове смернице за CSP препоручују nonce на скрипти api.js; Turnstile га преноси на ресурсе које динамички учитава. За његов iframe дозволите https://challenges.cloudflare.com у директиви frame-src. Друга могућност је да исти домен дозволите и у script-src и у frame-src.

Ако политика већ садржи те директиве, допуните их уместо да замените цело заглавље. Условни исечак политике је: script-src 'self' 'nonce-{{NONCE}}'; frame-src 'self' https://challenges.cloudflare.com. Сервер у CSP заглавље и атрибут nonce на скрипти ставља исту свежу вредност за тај одговор. Остале изворе који су вашој страници потребни задржите у одговарајућим директивама.

Страница са strict-dynamic захтева да проверите и начин учитавања осталих скрипти, пошто та директива утиче на тумачење дозвољених извора. Затим отворите формулар под стварним CSP заглављем и проверите да ли прегледач блокира Turnstile скрипту или iframe. Ако се widget не учита, серверска рута и даље треба да одбије захтев без важећег токена.

Проверите негативне случајеве на правој рути

Сваки тест усмерите на руту која заиста чува податке или шаље поруку. Поред HTTP одговора, проверите да ли је saveForm остао непозван; сама порука о грешци не доказује да обрада није извршена. Почните успешним слањем да бисте потврдили да су widget, тајни кључ и дозвољени hostname исправно повезани.

  • Изостављен токен: пошаљите формулар без cf-turnstile-response. Захтев треба да се заврши пре позива Siteverify и пре обраде података.
  • Истекао токен: у издвојеном окружењу сачекајте да стварни токен истекне, па пошаљите формулар. Неуспех Siteverify мора да заустави обраду; ново слање захтева свеж токен.
  • Поново употребљен токен: пошаљите један формулар успешно, па поновите слање са истим токеном. Поновљени захтев треба одбити без другог позива saveForm.
  • Погрешан hostname: у контролисаном тесту вратите успешан Siteverify одговор са другим именом хоста. Рута треба да одбије захтев иако је success true.

Лажирани Siteverify одговор омогућава да проверите одлуке свог кода, укључујући погрешан hostname и прекид везе. За проверу стварног истека и поновне употребе користите токене у издвојеном окружењу: локално лажирање одговора не испитује понашање самог сервиса. Поновите и слање без токена док је CSP укључен, да бисте проверили да квар учитавања widget-а не отвара пут обради формулара.

Прочитајте и:

Подели:

Претплатите се на наш билтен

Добијајте најновије вести о Web3, AI-у и криптовалутама директно у пријемно сандуче.

0