DEV Community

Cover image for كيفية اختبار API الخاص بك ضد المدخلات غير الموثوقة قبل أن يستغلها المخترقون
Yusuf Khalidd
Yusuf Khalidd

Posted on • Originally published at apidog.com

كيفية اختبار API الخاص بك ضد المدخلات غير الموثوقة قبل أن يستغلها المخترقون

ملخص: يُعد مُدخل واجهة برمجة التطبيقات (API) سطح هجوم، لذا اختبره على هذا الأساس. اكتب حالات اختبار سلبية ترسل حقولًا ضخمة، وأنواعًا خاطئة، وأجسامًا مشوهة، وسلاسل حقن، ثم تأكد من أن نقطة النهاية تعيد رمز 4xx وليس 5xx أبدًا. حوّل التحقق من المخطط إلى إجراء أمني باستخدام additionalProperties: false، والتعدادات، وحدود الطول. شغّل مجموعة الاختبارات في CI مع كل تغيير. تجعل وكلاء الذكاء الاصطناعي هذه الخطوة أكثر إلحاحًا لأنهم ينشئون ويعيدون توجيه الحمولات بسرعة آلية.

معظم مجموعات الاختبار تثبت أن واجهة API تعمل عندما يرسل العميل طلبًا صالحًا: جسم صحيح، استجابة 200، ثم نجاح الاختبار. لكن ذلك لا يثبت ما يحدث عند وصول مدخلات عدائية. اعتبر كل بيانات تأتي من خارج نقطة النهاية غير موثوقة، بما في ذلك جسم الطلب، وسلاسل الاستعلام، والرؤوس، والملفات، وحمولات webhooks، وبيانات JSON التي ينشئها وكلاء الذكاء الاصطناعي.

جرّب Apidog اليوم

في يوليو 2026، وصفت Hugging Face حادثًا أمنيًا كان مدخله البيانات لا كلمة مرور مسروقة. غطينا الدروس المستفادة من هذا الاختراق بشكل منفصل. يركز هذا الدليل على التطبيق العملي: بناء اختبارات ترسل مدخلات عدائية وتشغيلها تلقائيًا مع كل تغيير. تتوافق هذه الفئات مع قائمة OWASP لأهم 10 مخاطر أمنية لواجهات API. يمكنك استخدام Apidog لتصميم العقد وتشغيل الاختبارات، لكن المنهج ينطبق على أي إطار عمل.

المدخلات هي سطح هجوم، وليست حقل نموذج

التحقق من الصحة ليس مجرد تحسين لتجربة المستخدم. كل حقل تقبله واجهة API هو عقد يمكن للعميل مخالفته:

  • limit المتوقع أن يكون عددًا صغيرًا قد يصبح 999999999.
  • filename قد يصبح ../../etc/passwd.
  • كائن config قد يحمل تعليمات بدلًا من إعدادات.
  • حقل نصي بسيط قد يحتوي سلسلة حقن أو قالبًا قابلًا للتقييم.

ابدأ لكل نقطة نهاية بالسؤال التالي:

ما أسوأ قيمة يمكن أن تصل إلى هذا الحقل؟

هذا السؤال هو أساس الاختبار السلبي وممارسات أمان واجهات API. ثم حوّله إلى حالات اختبار ثابتة في المستودع.

كيف تحولت «حمّل هذه البيانات» إلى «شغّل هذا الكود»

توضح حادثة Hugging Face لماذا يجب التعامل مع البيانات كمدخلات غير موثوقة. ذكرت الشركة أن متجه الدخول كان مجموعات بيانات خبيثة: مجموعة بيانات معدّة لتشغيل مُحمِّل بيانات ينفذ كودًا عن بعد، إلى جانب حقن قالب ضمن إعدادات مجموعة البيانات. راجع تقرير الحادث الأمني.

النمط المهم هنا بسيط:

  1. تقبل نقطة النهاية شيئًا موصوفًا بأنه بيانات.
  2. يمرر التطبيق هذه البيانات إلى مُحمّل أو مفسر أو محرك قوالب.
  3. تتحول البيانات إلى تعليمات قابلة للتنفيذ.

أي نقطة نهاية تقبل اسم مُحمّل، أو تنسيقًا، أو قالبًا، أو كائنًا مُسلسلًا، أو كتلة إعدادات، تحتاج إلى اختبارات تثبت أن هذه القيم تبقى خاملة ولا تتحول إلى تنفيذ.

اجعل التحقق من المخطط طبقة أمان

ضع مخططًا صارمًا عند حدود التطبيق، قبل منطق العمل. المخطط ليس توثيقًا فقط؛ عند رفض كل ما لا يطابقه، يصبح مرشحًا أمنيًا.

مثال باستخدام JSON Schema:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "additionalProperties": false,
  "required": ["loader", "name"],
  "properties": {
    "loader": {
      "enum": ["csv", "json", "parquet"]
    },
    "name": {
      "type": "string",
      "maxLength": 128,
      "pattern": "^[\\w .-]+$"
    },
    "rows": {
      "type": "integer",
      "minimum": 0,
      "maximum": 1000000
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

يعالج هذا المخطط عدة حالات مباشرة:

القيد ما الذي يمنعه؟
additionalProperties: false حقولًا غير متوقعة مثل template
enum لـ loader قيمًا مثل pickle:// أو أي مُحمّل غير معروف
maxLength سلاسل ضخمة قد تستنزف الذاكرة
pattern رموزًا أو صيغًا لا تدعمها قيمة name

لا يمنع المخطط كل الثغرات، لكنه يغلق فئة شائعة جدًا من الأخطاء: قبول حقول وقيم لم يكن التطبيق يدعمها أصلًا.

الاختبار السلبي: أثبت أن نقطة النهاية ترفض

اختبارات المسار السعيد تثبت أن المدخلات الصحيحة تعمل. الاختبارات السلبية تثبت أن المدخلات الخاطئة تُرفض بشكل متحكم فيه.

لكل حقل، اختبر على الأقل:

  • نوعًا خاطئًا.
  • حقلًا مطلوبًا مفقودًا.
  • حقلًا محظورًا أو غير متوقع.
  • قيمة خارج النطاق.
  • قيمة أطول من الحد.
  • سلسلة حقن مناسبة لسياق الحقل.
  • جسم طلب مشوه أو نوع محتوى غير مطابق.

ركز على سلوك الاستجابة:

المدخل العدائي → استجابة 4xx متوقعة
المدخل العدائي → يجب ألا ينتج 5xx أبدًا
Enter fullscreen mode Exit fullscreen mode

رمز 400 أو 422 يعني أن التطبيق رفض الطلب عند حدوده. أما 500 فيعني غالبًا أن المدخل وصل إلى منطق أو محلل لم يكن مستعدًا له.

لا تجعل الاختبارات تعتمد على نص رسالة الخطأ. بدلًا من ذلك، تحقق من:

  • رمز الحالة.
  • عدم وجود آثار جانبية، مثل إنشاء سجل أو تعديل بيانات.
  • عدم ظهور مخرجات تشير إلى تنفيذ قالب أو أمر.

استخدم قائمة التحقق من اختبار أمان API كنقطة بداية لتغطية الحقول.

فئات حقن تستحق اختبارات دائمة

لا تحتاج إلى مئات الحمولات لكل فئة. ابدأ بحالة استكشافية ثابتة لكل نوع حتى يفشل أي تراجع بوضوح.

حقن SQL

أرسل سلسلة مثل:

1); DROP TABLE datasets;--
Enter fullscreen mode Exit fullscreen mode

إلى أي حقل قد يدخل في استعلام. يجب أن تُعامل كسلسلة حرفية أو تُرفض، وألا تظهر رسالة خطأ من قاعدة البيانات.

حقن القوالب

أرسل القيم التالية إلى حقول الاسم أو التسمية أو الوصف:

{{ 7*7 }}
{{ config.__class__ }}
Enter fullscreen mode Exit fullscreen mode

إذا احتوت الاستجابة على 49، فقد قيّم محرك القوالب مدخل المستخدم بدل التعامل معه كنص.

إلغاء التسلسل غير الآمن ومُحمّلات الكود عن بعد

اختبر مُحمّلات غير متوقعة:

{
  "loader": "pickle://s3/models/payload.pkl"
}
Enter fullscreen mode Exit fullscreen mode

استخدم قائمة سماح صريحة للمُحمّلات والتنسيقات المدعومة. لا تحاول تفسير قيم غير معروفة «بشكل مفيد».

حقن الأوامر

اختبر الحقول التي قد تتحول إلى وسيطات shell، مثل أسماء الملفات أو خيارات التحويل:

; id
$(id)
Enter fullscreen mode Exit fullscreen mode

يجب ألا يتسبب أي إدخال في تنفيذ أمر أو تسريب بيانات عن بيئة التشغيل.

للتوسع لاحقًا، يمكنك إضافة أدوات الكشف الآلي عن ثغرات API، لكن الحالات اليدوية المحددة تكشف التراجعات الواضحة مبكرًا.

اختبر الحجم والشكل ونوع المحتوى

ليست كل المدخلات العدائية سلاسل حقن ذكية. بعض أخطرها كبير جدًا أو مشوه بطريقة تكسر المحللات قبل بدء التحقق من المخطط.

أضف حالات اختبار لـ:

  • حقل نصي بحجم 5 ميغابايت.
  • مصفوفة JSON تحتوي على مليون عنصر.
  • JSON مقطوع أو بفاصلة زائدة.
  • JSON متداخل بعمق كبير.
  • Content-Type: application/json مع جسم XML.
  • Content-Type: application/xml مع حمولة تختبر XXE.
  • جسم JSON مرسل على أنه text/plain.

السلوك المتوقع:

الحالة الاستجابة المتوقعة
جسم أكبر من الحد 413 Payload Too Large
JSON مشوه 400 Bad Request
نوع محتوى غير مطابق 400 أو 415 Unsupported Media Type
بنية متداخلة بصورة مفرطة رفض سريع دون تعليق العامل

تحقق من تطابق الرأس مع الجسم قبل تحليل المحتوى، ولا تعتمد على محلل متساهل يقبل صيغًا لا يدعمها عقد API.

لماذا تزيد وكلاء الذكاء الاصطناعي من المخاطر

كانت هذه المخاطر موجودة قبل وكلاء الذكاء الاصطناعي، لكن الوكلاء يرفعون السرعة والحجم:

  • يركبون مدخلات لم يكتبها إنسان مباشرة.
  • يعيدون المحاولة ويُسلسلون المكالمات بسرعة.
  • يعيدون توجيه بيانات قادمة من مصادر اعتُبرت موثوقة.
  • قد يحولون مستندًا أو webhook سامًا إلى آلاف الطلبات خلال ثوانٍ.

لا يتغير الدفاع: تحقق صارم عند الحدود، اختبارات سلبية، وتشغيل تلقائي في CI. لكن المراجعة اليدوية لحركة المرور لم تعد كافية. راجع أيضًا دليل حقن المطالبات لفرق API.

ابنِ مجموعة اختبارات سلبية في pytest

حوّل الحمولات السابقة إلى اختبارات تعمل ضد بيئة staging معزولة، لا ضد الإنتاج.

import httpx
import pytest

BASE = "https://staging.internal/v1"

HOSTILE_CONFIGS = [
    {"loader": "pickle://s3/models/payload.pkl", "format": "auto"},
    {"loader": "csv", "name": "{{ 7*7 }}"},
    {"loader": "csv", "name": "{{ config.__class__ }}"},
    {"loader": "csv", "filter": "1); DROP TABLE datasets;--"},
    {"loader": "csv", "name": "A" * 5_000_000},
]

@pytest.mark.parametrize("config", HOSTILE_CONFIGS)
def test_dataset_config_is_refused(config):
    response = httpx.post(
        f"{BASE}/datasets",
        json={"config": config},
        timeout=10,
    )

    assert response.status_code in (400, 413, 422), response.text
    assert response.status_code < 500, (
        "رمز 5xx يعني أن الحمولة وصلت إلى منطق لا يجب أن تصل إليه"
    )
    assert "49" not in response.text, (
        "تم تقييم القالب: احتمال حقن قالب من جهة الخادم"
    )
Enter fullscreen mode Exit fullscreen mode

أضف اختبارات مستقلة للآثار الجانبية عندما تتعامل نقطة النهاية مع بيانات قابلة للكتابة. على سبيل المثال، بعد طلب مرفوض، تحقق من عدم إنشاء سجل جديد أو تغيير حالة مورد قائم.

شغّل الاختبارات مع كل تغيير في CI

أضف الاختبارات إلى خط أنابيب CI حتى تمنع عمليات الدمج عند تخفيف التحقق من دون قصد.

name: api-abuse-tests

on: [push, pull_request]

jobs:
  negative-input:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: pytest tests/negative_input.py -q
Enter fullscreen mode Exit fullscreen mode

في Apidog، يمكنك تصميم نقطة النهاية بعقد OpenAPI، ثم حفظ سيناريوهات المسار السعيد والسيناريوهات السلبية معًا. أضف حالات للحقول الضخمة، والأنواع الخاطئة، والحقول الإضافية، وسلاسل الحقن، ثم أكد أن النتيجة 4xx. شغّل السيناريوهات نفسها في CI عبر واجهة سطر الأوامر الخاصة بـ Apidog حتى يفشل البناء عند حدوث تراجع في التحقق.

إذا أردت البدء، نزّل Apidog وأضف سيناريو سلبيًا واحدًا إلى نقطة نهاية موجودة.

حدود الأداة مهمة أيضًا: Apidog أداة تصميم واختبار ومحاكاة وتوثيق. لا تشغّل WAF، ولا تصفي حركة المرور الحية، ولا تحل محل SIEM، ولا يكتشف التحقق من العقد كل الثغرات. قيمتها هنا هي جعل ما تقبله نقطة النهاية صريحًا وقابلًا للاختبار باستمرار.

أسئلة مكررة

  • ما الفرق بين الاختبار السلبي والاختبار العشوائي؟

    الاختبار السلبي يرسل مدخلات سيئة مختارة عمدًا لكل فئة فشل مهمة. أما الاختبار العشوائي فيرسل كميات كبيرة من المدخلات المتحولة أو العشوائية للعثور على حالات غير متوقعة. ابدأ بالاختبار السلبي لأنه حتمي وسريع ومناسب لـ CI، ثم أضف fuzzing لتوسيع التغطية.

  • هل يجب تشغيل هذه الاختبارات على الإنتاج؟

    لا. شغّلها على staging أو بيئة معزولة. الحمولات الضخمة واختبارات حقن الأوامر قد تجهد النظام أو تعدل البيانات عند وجود خلل.

  • ألن يوقف WAF هذه الطلبات؟

    WAF طبقة دفاع مفيدة، لكنه ليس بديلًا عن رفض التطبيق للمدخلات غير الصحيحة. لا يعرف WAF منطق عملك ولا يجب أن يكون خط الدفاع الوحيد.

  • كم حالة سلبية أحتاج لكل نقطة نهاية؟

    ابدأ بحالة واحدة لكل حقل ولكل فئة فشل: نوع خاطئ، قيمة خارج النطاق، طول زائد، حقل محظور، وسلسلة حقن ملائمة للسياق. تغطية الفئات أهم من عدد الحالات.

  • هل يوقف التحقق من المخطط الحقن بالكامل؟

    لا. المخطط الصارم يقلص سطح الهجوم ويرفض الحقول غير المتوقعة والمدخلات المشوهة، لكنه لا يغني عن الاستعلامات المعلّمة، وإلغاء التسلسل الآمن، وترميز المخرجات، وقوائم السماح للمُحمّلات والتنسيقات.

Top comments (0)