شرلوک هلمز: مورد اضافه بار ردیس در طول یک حمله DDoS

روز آرامی بود تا اینکه فاجعه رخ داد. ما هشدارهایی در مورد حملات DDoS و brute-force دریافت کردیم که از IP های ربات تصادفی منشا می گرفتند. تیم ما به سرعت بسیج شد تا حملات را کاهش دهد. درست زمانی که فکر می کردیم اوضاع تحت کنترل است، پیام هشداردهنده دیگری ظاهر شد: پایگاه داده Redis ما در دسترس بود ظرفیت 80 درصد! با توجه به اینکه Redis DB ما معمولاً کمتر از 20 مگابایت باقی میماند، این به ویژه تکاندهنده بود.
مرحله تحقیق: رمز و راز ردیس
قبل از پرداختن به مشکل Redis، ما بر توقف حملات DDoS و brute-force تمرکز کردیم. ما محدودیت نرخ را برای نقاط پایانی خاص از طریق Cloudflare اجرا کردیم.
اکنون، بیایید آنچه را که در Redis ذخیره می کنیم را بررسی کنیم. ما از آن برای مدیریت جلسات کاربر در برنامه Node.js خود با Passport.js استفاده می کنیم. در اینجا نمونه ای از ظاهر یک جلسه آمده است:
{
"cookie": {
"originalMaxAge": number,
"expires": "date",
"secure": true,
"httpOnly": false,
"domain": "domain",
"path": "https://dev.to/",
"sameSite": false
},
"passport": {
"user": // Actual user data here
}
}
با این شرایط، ما تحقیقات خود را آغاز کردیم. من تمام داده ها را در Redis جستجو کردم تا اعتبار جلسات را بررسی کنم. در کمال تعجب، فقط 10% از جلسات حاوی داده های کاربر معتبر بود. بقیه نامعتبر بودند، فاقد آن بودند کاربر کلید
کد معرفی شده: چرا تعداد جلسات نامعتبر زیاد است؟
من به چگونگی ایجاد این جلسات نامعتبر پی بردم و متوجه شدم که به طور پیش فرض، اکسپرس جلسه برای هر درخواستی که کوکی پیوستی ندارد یک جلسه ایجاد می کند (شما می توانید به اینجا مراجعه کنید). در طول حمله DDoS، این منجر به ایجاد یک جلسه جدید برای هر درخواست شد که سپس در Redis ذخیره شد.
برای حل این مشکل، ما را تنظیم کردیم saveUninitialized: false
گزینه:
const session = require('express-session');
app.use(session({
secret: 'keyboard cat',
resave: false,
saveUninitialized: false,
cookie: { secure: true }
}));
رفع مشکل
پس از اجرای تغییر کد، یک اسکریپت برای حذف جلسات نامعتبر از Redis نوشتم. در حالی که امیدوار بودیم این مشکل حل شود، ذخیره سازی Redis با سرعت هشدار دهنده ای به رشد خود ادامه داد.
تحقیقات ادامه دارد
با وجود رفع اولیه، متوجه شدیم که پایگاه داده Redis همچنان به سرعت در حال گسترش است. هنوز چیزی اشتباه بود.
من عمیق تر در پایگاه کد حفاری کردم و آن را کشف کردم فلش بسته ای که برای انتقال پیام بین سرورها استفاده می کردیم. پس از بررسی بیشتر، متوجه شدم که هنگام دسترسی به پیام ها:
const { msg } = req.flash();
بسته یک شی خالی را به آن اختصاص می دهد req.session.flash
اگر یکی از قبل وجود نداشته باشد:
var msgs = this.session.flash = this.session.flash || {};
این اصلاح از req.session
باعث شد اکسپرس جلسه برای ذخیره جلسه در Redis. عملکرد فلش در نقاط پایانی عمومی استفاده می شد، که باعث می شد جلسات کاربر خالی بماند و منجر به درج جلسات جدید با هر درخواست می شد.
مسیر رسیدن به وضوح
برای حل این مشکل، کد را تغییر دادم تا پس از خواندن پیام، جلسه را از بین ببرد، همانطور که در زیر نشان داده شده است:
const { msg } = req.flash();
req.session.destroy();
و بدین ترتیب، سفر کارآگاهی به پایان رسید.
در نهایت، اگر مقاله مفید بود، لطفا کف بزنید 👏و فالو کنید، ممنون!