سیل اسکرپر روی پلن رایگان Cloudflare: چه چیزی آن را متوقف کرد و چه چیزی را خاموش رها کردیم
عملیات
یک صبح، یکی از سایتهای لیستینگ ما باز نشد. Cloudflare به بازدیدکنندگان خطای 524 را نشان میداد، سرور مبدأ برای هر صفحه دو تا شش دقیقه زمان میبرد و چیزی حدود ده ساعت به ما چیزی نگفت. علت، یک اسکرپر بود که از طریق پروکسیهای مسکونی با سرعت حدود 225 درخواست در ثانیه حرکت میکرد.
شکل سیل
- هزاران آدرس، هر کدام با یک تا سه درخواست. اتصالات پهنای باند خانگی در آمریکا، اسپانیا، فرانسه، برزیل، انگلستان و سایر نقاط، همان نوع ترافیکی که یک شبکه پروکسی مسکونی اجاره میدهد.
- یوزر ایجنتهای کروم روی مک، با شماره نسخههای 103 تا 151.
- تقریباً هرگز کوکی یا Referer. از 2,697 درخواستی که روی سرور نمونهبرداری کردیم، 4 مورد کوکی و 4 مورد Referer داشتند.
- دو نوع کلاینت. حدود نیمی از آنها هدرهای
Sec-Fetch-*و هیچ client hint نمیفرستادند: یک اسکریپت با یک رشته user agent کپیشده. نیمه دیگر هدرهای کامل مرورگر را میفرستادند: یک مرورگر headless.
برای هر درخواست، هر صفحه رندر میشد، بنابراین هر ورکر صدها رندر را در صف میگذاشت و به سقف CPU خود میرسید.
چرا محدودیتهای بر اساس آدرس کمکی نمیکردند
یک rate limit درخواستها را بر اساس آدرس میشمارد. با یک تا سه درخواست از هر کدام از هزاران آدرس، هیچ آدرس منفردی هرگز به نزدیکی یک محدودیت نمیرسد. مسدود کردن کشورها، بازدیدکنندگان ما را هم مسدود میکرد. چیزی که اسکرپر نمیتوانست بهصورت ارزان جعل کند، رفتار شبیه به مرورگری بود که قبلاً به سایت سر زده باشد.
در لبه Cloudflare: سه قانون رایگان
پلن رایگان اجازه میدهد پنج قانون سفارشی WAF برای هر zone داشته باشیم. ما از سه مورد استفاده کردیم، همه با یک چالش مدیریتشده بهجای بلاک، بنابراین اگر شخصی اشتباهاً گیر افتاد، میتواند با کلیک از آن عبور کند:
- مرورگر جعلی: یک GET که user agent آن شامل
Chrome/است و هدرSec-Fetch-Modeندارد. هر کرومی از سال 2019 به بعد این هدر را میفرستد. - ابرهای اسکرپر: یک درخواست صفحه از شبکههای Alibaba، Tencent و Huawei Cloud، که بخش زیادی از آنچه چالش دادیم از آنها میآمد.
- حالت اضطراری، بهصورت پیشفرض خاموش: یک GET بدون هیچ کوکی و بدون Referer. کسی که قبلاً به سایت رفته باشد، یا از طریق یک لینک وارد شود، بدون دستکاری عبور میکند؛ یک اسکرپر که کوکی نگه نمیدارد، در هر درخواست با یک چالش مواجه میشود. ما آن را فقط در طول سیل روشن میکنیم، زیرا همچنین کسی را که آدرس را در یک مرورگر تازه تایپ میکند، چالش میکند.
هر سه مورد، رباتهای تأییدشده Cloudflare، یوزراجنتهایی که خود را ربات معرفی میکنند، آدرسهای IP خودمان، مسیرهای API و وبهوک، و فایلهایی که صفحه نیستند را عبور میدهند. دو روز بعد، سیل همچنان ادامه داشت: در یک ساعت، قانون مرورگر جعلی بیش از 10,000 درخواست را به چالش کشید. 10,000 رویدادی که Cloudflare در هر کوئری برمیگرداند، از 9,627 آدرس بود که هیچکدام بیش از 4 مورد نداشتند.
در مبدأ: یک دروازه در اپلیکیشن
نیمهی بدون رابط (headless) دارای هدرهای کامل مرورگر است، بنابراین قوانین لبه (edge) به تنهایی آن را شناسایی نمیکنند در حالی که قانون اضطراری غیرفعال است. در خود اپلیکیشن، یک میدلور کوچک جلوی رندرر صفحه قرار دادیم:
- یک یوزراجنت Chrome که نه
Sec-Fetch-Modeدارد و نه Client Hints، پیش از انجام هر کاری با خطای 403 مواجه میشود؛ - یک غریبه، بدون هیچکدام از کوکیهای ما و بدون Referer، تنها زمانی سرویس میگیرد که ورکر ظرفیت خالی داشته باشد، با سرعت چند صفحه در ثانیه. در صورت عبور از این حد، یک صفحه 503 با حجم 400 بایت یک کوکی تنظیم میکند و پس از دو ثانیه صفحه را دوباره بارگذاری میکند. یک انسان در تلاش دوم صفحه را دریافت میکند؛ اما یک اسکرپر که کوکی نگه نمیدارد، هرگز دریافت نمیکند.
در دقیقه اول، دروازه حدود 6,700 مرورگر جعلی را رد کرد و حدود 6,700 غریبه را دور زد، در حالی که به غریبهها حدود 9 صفحه در ثانیه سرویس میداد. درخواستهای کند به صفر رسیدند، CPU ورکرها از حد مجاز به 12 تا 15 درصد کاهش یافت و حافظه آنها از 4 تا 5 گیگابایت برای هر کدام به 0.65 گیگابایت رسید.
آنچه غیرفعال رها کردیم
- حالت Bot Fight. ترافیک خودکار را به چالش میکشد و در پلن Free نمیتوان با یک قانون سفارشی از آن رد شد، و وبهوکهای ارائهدهنده پرداخت ما را نیز گرفت.
- حالت Under Attack برای کل زون. هر بازدیدکننده، کلاینت API و وبهوک را از صفحه میانی (interstitial) عبور میدهد. قانون اضطراری همان کار را فقط برای درخواستهای صفحه غریبهها انجام میدهد.
- قانون محدودسازی نرخ (rate-limiting) در پلن Free. آن بر اساس آدرس شمارش میکند، چیزی که این سیل هرگز آن را فعال نمیکند.
- مسدود کردن خزندههای هوش مصنوعی. ما میخواهیم توسط دستیارهای جستجوی هوش مصنوعی پیدا شویم، و آن خزندهها مشکل نبودند.
نکته کلیدی
تشخیص سیل از طریق پروکسیهای مسکونی با توجه به آنچه کم دارد آسان است: هدرهای fetch مرورگر، کوکیها و Refererها. آن را در لبه به چالش بکشید، غریبهها را در محدودهای نگه دارید که ورکرهای شما میتوانند رندر کنند، و مطمئن شوید چیزی خارج از سرور متوجه میشود وقتی باز شدن صفحه متوقف میشود. Night Watch هر سه مورد را بستهبندی میکند: واچداگ، قوانین با یک سوئیچ خودکار برای قانون اضطراری، و دروازه برای اپلیکیشنهای وب Python.