كنا نحدّ من معدل طلبات خدماتنا نفسها
تسمح واجهة Mythex البرمجية بـ 300 طلب في الدقيقة من عنوان شبكة واحد. هذا الحد موجود لحماية الواجهة من شخص واحد أو سكربت واحد يضغط عليها بشدة. وفي الإنتاج، بدأ يرفض خدماتنا نفسها، أي الجزء من حافتنا الذي يقدم التطبيقات المنشورة، والخدمة التي تشغّل وكيل الذكاء الاصطناعي، لأن كلاً منهما يصل إلى الواجهة من عدد قليل من العناوين فقط. والطلبات التي تحمل بيانات الاعتماد الداخلية لدينا معفاة الآن، ويخضع كل من عداها للحد تماماً كما كان.
العَرَض
بدأت الواجهة البرمجية ترد على بعض استدعاءاتنا الداخلية بالخطأ 429 Too Many Requests. تعرضت ثلاثة أنواع من الاستدعاءات لذلك، وكل منها يهم أحداً يستخدم Mythex:
- البحث عن التطبيق الذي يعيش على نطاق مخصص. عندما يفتح زائر تطبيقاً منشوراً على نطاقه الخاص، تسأل حافتنا الواجهة عن الموقع الذي يخص ذلك النطاق. ورد 429 هنا يعني زائراً لا يستطيع الوصول إلى الموقع.
- حفظ دور وكيل قيد التشغيل. أثناء عمل الوكيل، يُحفظ تقدمه باستمرار، حتى تبقى الإجابة قائمة بعد تحديث الصفحة أو انقطاع الاتصال. ورد 429 هنا يعني تقدماً لم يُحفظ.
- التحقق من صلاحية الوصول إلى المعاينة. معاينة التطبيق الذي تبنيه محمية، والبوابة تسأل الواجهة. ورد 429 هنا يعني معاينة لا تفتح.
لم يكن أيٌّ من هذه الاستدعاءات من أشخاص يتصلون بالواجهة. كلها كانت منا نحن.
لماذا حدث ذلك؟
يفترض حد المعدل لكل عنوان أمراً واحداً: العنوان الواحد يقابل مستدعياً واحداً تقريباً. وبالنسبة للناس، هذا كافٍ تقريباً. أما بالنسبة لبنيتنا التحتية الداخلية، فهو خاطئ بشكل واضح.
- تصل خدمة الحافة التي تقدم التطبيقات المنشورة والمعاينات إلى الواجهة من عدد قليل من عناوين الخروج المشتركة. وكل زائر لكل تطبيق منشور، وكل فحص معاينة، يبدو وكأنه قادم من أحد هذه العناوين القليلة.
- ينادي المنسّق، أي الخدمة التي تشغّل أدوار الوكيل، الواجهة من عنوان حاوية واحد. وكل دور قيد التشغيل، لكل مستخدم، يشترك فيه.
فالميزانية المصممة لشخص واحد كانت تُقسَّم على كل حركة مرور خدمة كاملة. واستنفدتها الخدمات بين بعضها، وفعل الحد ما أُمر به: رفض الخدمات.
الإصلاح
خدماتنا تثبت هويتها بالفعل. كل استدعاء داخلي يحمل رمزاً داخلياً، وكل مسار تحت القسم الداخلي للواجهة يتحقق من هذا الرمز قبل أن يفعل أي شيء.
وحد المعدل يستخدم الآن الفحص نفسه. الطلب الذي يطابق رمزه الرمز الداخلي موجود في قائمة مسموح بها ولا يُحسب ضمن ميزانية العنوان لكل شخص. وكل شيء آخر يُحسب بالضبط كما كان: 300 طلب في الدقيقة لكل عنوان.
تفصيلتان منعتا ذلك من أن يصبح ثغرة:
- الرمز الخاطئ لا يحصل على استثناء. القائمة المسموح بها تطابق الرمز الداخلي الحقيقي فقط. الطلب برمز مُختلق يُحسب ويُحدّ كأي طلب آخر، والمسارات الداخلية ترفضه بخطأ
401 Unauthorized. - الحد نفسه لم يتغير. لم نرفع الرقم لاستيعاب المشكلة. رفعه كان سيُخفي المشكلة إلى أن يزداد حجم الحركة مرة أخرى، وكان سيُضعف الحماية للحالة التي وُجد الحد من أجلها.
نقلنا إعدادات حد المعدل إلى دالة صغيرة واحدة وكتبنا اختبارات ضدها. أحدها يرسل 20 طلباً بالرمز الداخلي إلى حد مضبوط على 5 طلبات، ويتوقع نجاح الـ 20 جميعها. وآخر يرسل طلبات عادية من عنوان واحد، ويتوقع نجاح أول خمسة ورفض ما بعدها. والثالث يرسل طلبات برمز مزوَّر، ويتوقع رفضها بالطريقة نفسها.
ما الذي استخلصناه
- للحدود افتراضات. «عنوان واحد، مستدعٍ واحد» مدمجة في حد لكل عنوان. وتتوقف عن الصحة في اللحظة التي تقع فيها خدماتك خلف عناوين مشتركة، وكثير منها كذلك: موازنات الحمل، وشبكات الحافة، والحاويات، وشبكات المكاتب.
- ميّز حركة مرورك الخاصة بالهوية لا بالعنوان. العناوين هي الطريقة التي تصل بها الحركة، لا من أرسلها. وكان لدينا بالفعل بيانات اعتماد تثبت أن الاستدعاء لنا، والحد فقط لم يكن ينظر إليها.
- لا تحل المشكلة برفع الرقم. حد أكبر كان سيُخفي ردود 429 لفترة، ويحمي أقل، ويفشل لاحقاً.
- انظر إلى من يُحدّ منه. رد 429 يقع على خدمتك نفسها هو تقرير خطأ عن حدودك، لا دليل على أن الحد يعمل.
ماذا يعني ذلك إن كنت تبني على Mythex؟
لا شيء تحتاج إلى تغييره من جهتك. التطبيقات المنشورة على نطاقات مخصصة، ودورات الوكيل، والمعاينات لم تعد تعتمد على مقدار انشغال بقية Mythex. وحركة تطبيقك هي شأن تطبيقك: الحد المذكور هنا موجود على واجهتنا البرمجية، لا على التطبيقات التي تنشرها.
وإذا كان لديك خلفية خاصة بك، فالفخ نفسه ينطبق على أي حد معدل تضيفه. دليلانا عن ما هي الواجهة البرمجية وقائمة التحقق الأمنية للتطبيقات المبنية بالذكاء الاصطناعي نقطة بداية جيدة. ولمثال آخر على بنيتنا التحتية وهي تعيق نفسها، انظر كيف وصلنا إلى نشر بصفر أخطاء 502.