ملخص: يُعد مُدخل واجهة برمجة التطبيقات (API) سطح هجوم، لذا اختبره على هذا الأساس. اكتب حالات اختبار سلبية ترسل حقولًا ضخمة، وأنواعًا خاطئة، وأجسامًا مشوهة، وسلاسل حقن، ثم تأكد من أن نقطة النهاية تعيد رمز
4xxوليس5xxأبدًا. حوّل التحقق من المخطط إلى إجراء أمني باستخدامadditionalProperties: false، والتعدادات، وحدود الطول. شغّل مجموعة الاختبارات في CI مع كل تغيير. تجعل وكلاء الذكاء الاصطناعي هذه الخطوة أكثر إلحاحًا لأنهم ينشئون ويعيدون توجيه الحمولات بسرعة آلية.
معظم مجموعات الاختبار تثبت أن واجهة API تعمل عندما يرسل العميل طلبًا صالحًا: جسم صحيح، استجابة 200، ثم نجاح الاختبار. لكن ذلك لا يثبت ما يحدث عند وصول مدخلات عدائية. اعتبر كل بيانات تأتي من خارج نقطة النهاية غير موثوقة، بما في ذلك جسم الطلب، وسلاسل الاستعلام، والرؤوس، والملفات، وحمولات webhooks، وبيانات JSON التي ينشئها وكلاء الذكاء الاصطناعي.
في يوليو 2026، وصفت Hugging Face حادثًا أمنيًا كان مدخله البيانات لا كلمة مرور مسروقة. غطينا الدروس المستفادة من هذا الاختراق بشكل منفصل. يركز هذا الدليل على التطبيق العملي: بناء اختبارات ترسل مدخلات عدائية وتشغيلها تلقائيًا مع كل تغيير. تتوافق هذه الفئات مع قائمة OWASP لأهم 10 مخاطر أمنية لواجهات API. يمكنك استخدام Apidog لتصميم العقد وتشغيل الاختبارات، لكن المنهج ينطبق على أي إطار عمل.
المدخلات هي سطح هجوم، وليست حقل نموذج
التحقق من الصحة ليس مجرد تحسين لتجربة المستخدم. كل حقل تقبله واجهة API هو عقد يمكن للعميل مخالفته:
-
limitالمتوقع أن يكون عددًا صغيرًا قد يصبح999999999. -
filenameقد يصبح../../etc/passwd. - كائن
configقد يحمل تعليمات بدلًا من إعدادات. - حقل نصي بسيط قد يحتوي سلسلة حقن أو قالبًا قابلًا للتقييم.
ابدأ لكل نقطة نهاية بالسؤال التالي:
ما أسوأ قيمة يمكن أن تصل إلى هذا الحقل؟
هذا السؤال هو أساس الاختبار السلبي وممارسات أمان واجهات API. ثم حوّله إلى حالات اختبار ثابتة في المستودع.
كيف تحولت «حمّل هذه البيانات» إلى «شغّل هذا الكود»
توضح حادثة Hugging Face لماذا يجب التعامل مع البيانات كمدخلات غير موثوقة. ذكرت الشركة أن متجه الدخول كان مجموعات بيانات خبيثة: مجموعة بيانات معدّة لتشغيل مُحمِّل بيانات ينفذ كودًا عن بعد، إلى جانب حقن قالب ضمن إعدادات مجموعة البيانات. راجع تقرير الحادث الأمني.
النمط المهم هنا بسيط:
- تقبل نقطة النهاية شيئًا موصوفًا بأنه بيانات.
- يمرر التطبيق هذه البيانات إلى مُحمّل أو مفسر أو محرك قوالب.
- تتحول البيانات إلى تعليمات قابلة للتنفيذ.
أي نقطة نهاية تقبل اسم مُحمّل، أو تنسيقًا، أو قالبًا، أو كائنًا مُسلسلًا، أو كتلة إعدادات، تحتاج إلى اختبارات تثبت أن هذه القيم تبقى خاملة ولا تتحول إلى تنفيذ.
اجعل التحقق من المخطط طبقة أمان
ضع مخططًا صارمًا عند حدود التطبيق، قبل منطق العمل. المخطط ليس توثيقًا فقط؛ عند رفض كل ما لا يطابقه، يصبح مرشحًا أمنيًا.
مثال باستخدام 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
}
}
}
يعالج هذا المخطط عدة حالات مباشرة:
| القيد | ما الذي يمنعه؟ |
|---|---|
additionalProperties: false |
حقولًا غير متوقعة مثل template
|
enum لـ loader
|
قيمًا مثل pickle:// أو أي مُحمّل غير معروف |
maxLength |
سلاسل ضخمة قد تستنزف الذاكرة |
pattern |
رموزًا أو صيغًا لا تدعمها قيمة name
|
لا يمنع المخطط كل الثغرات، لكنه يغلق فئة شائعة جدًا من الأخطاء: قبول حقول وقيم لم يكن التطبيق يدعمها أصلًا.
الاختبار السلبي: أثبت أن نقطة النهاية ترفض
اختبارات المسار السعيد تثبت أن المدخلات الصحيحة تعمل. الاختبارات السلبية تثبت أن المدخلات الخاطئة تُرفض بشكل متحكم فيه.
لكل حقل، اختبر على الأقل:
- نوعًا خاطئًا.
- حقلًا مطلوبًا مفقودًا.
- حقلًا محظورًا أو غير متوقع.
- قيمة خارج النطاق.
- قيمة أطول من الحد.
- سلسلة حقن مناسبة لسياق الحقل.
- جسم طلب مشوه أو نوع محتوى غير مطابق.
ركز على سلوك الاستجابة:
المدخل العدائي → استجابة 4xx متوقعة
المدخل العدائي → يجب ألا ينتج 5xx أبدًا
رمز 400 أو 422 يعني أن التطبيق رفض الطلب عند حدوده. أما 500 فيعني غالبًا أن المدخل وصل إلى منطق أو محلل لم يكن مستعدًا له.
لا تجعل الاختبارات تعتمد على نص رسالة الخطأ. بدلًا من ذلك، تحقق من:
- رمز الحالة.
- عدم وجود آثار جانبية، مثل إنشاء سجل أو تعديل بيانات.
- عدم ظهور مخرجات تشير إلى تنفيذ قالب أو أمر.
استخدم قائمة التحقق من اختبار أمان API كنقطة بداية لتغطية الحقول.
فئات حقن تستحق اختبارات دائمة
لا تحتاج إلى مئات الحمولات لكل فئة. ابدأ بحالة استكشافية ثابتة لكل نوع حتى يفشل أي تراجع بوضوح.
حقن SQL
أرسل سلسلة مثل:
1); DROP TABLE datasets;--
إلى أي حقل قد يدخل في استعلام. يجب أن تُعامل كسلسلة حرفية أو تُرفض، وألا تظهر رسالة خطأ من قاعدة البيانات.
حقن القوالب
أرسل القيم التالية إلى حقول الاسم أو التسمية أو الوصف:
{{ 7*7 }}
{{ config.__class__ }}
إذا احتوت الاستجابة على 49، فقد قيّم محرك القوالب مدخل المستخدم بدل التعامل معه كنص.
إلغاء التسلسل غير الآمن ومُحمّلات الكود عن بعد
اختبر مُحمّلات غير متوقعة:
{
"loader": "pickle://s3/models/payload.pkl"
}
استخدم قائمة سماح صريحة للمُحمّلات والتنسيقات المدعومة. لا تحاول تفسير قيم غير معروفة «بشكل مفيد».
حقن الأوامر
اختبر الحقول التي قد تتحول إلى وسيطات shell، مثل أسماء الملفات أو خيارات التحويل:
; id
$(id)
يجب ألا يتسبب أي إدخال في تنفيذ أمر أو تسريب بيانات عن بيئة التشغيل.
للتوسع لاحقًا، يمكنك إضافة أدوات الكشف الآلي عن ثغرات 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, (
"تم تقييم القالب: احتمال حقن قالب من جهة الخادم"
)
أضف اختبارات مستقلة للآثار الجانبية عندما تتعامل نقطة النهاية مع بيانات قابلة للكتابة. على سبيل المثال، بعد طلب مرفوض، تحقق من عدم إنشاء سجل جديد أو تغيير حالة مورد قائم.
شغّل الاختبارات مع كل تغيير في 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
في Apidog، يمكنك تصميم نقطة النهاية بعقد OpenAPI، ثم حفظ سيناريوهات المسار السعيد والسيناريوهات السلبية معًا. أضف حالات للحقول الضخمة، والأنواع الخاطئة، والحقول الإضافية، وسلاسل الحقن، ثم أكد أن النتيجة 4xx. شغّل السيناريوهات نفسها في CI عبر واجهة سطر الأوامر الخاصة بـ Apidog حتى يفشل البناء عند حدوث تراجع في التحقق.
إذا أردت البدء، نزّل Apidog وأضف سيناريو سلبيًا واحدًا إلى نقطة نهاية موجودة.
حدود الأداة مهمة أيضًا: Apidog أداة تصميم واختبار ومحاكاة وتوثيق. لا تشغّل WAF، ولا تصفي حركة المرور الحية، ولا تحل محل SIEM، ولا يكتشف التحقق من العقد كل الثغرات. قيمتها هنا هي جعل ما تقبله نقطة النهاية صريحًا وقابلًا للاختبار باستمرار.
أسئلة مكررة
ما الفرق بين الاختبار السلبي والاختبار العشوائي؟
الاختبار السلبي يرسل مدخلات سيئة مختارة عمدًا لكل فئة فشل مهمة. أما الاختبار العشوائي فيرسل كميات كبيرة من المدخلات المتحولة أو العشوائية للعثور على حالات غير متوقعة. ابدأ بالاختبار السلبي لأنه حتمي وسريع ومناسب لـ CI، ثم أضف fuzzing لتوسيع التغطية.هل يجب تشغيل هذه الاختبارات على الإنتاج؟
لا. شغّلها على staging أو بيئة معزولة. الحمولات الضخمة واختبارات حقن الأوامر قد تجهد النظام أو تعدل البيانات عند وجود خلل.ألن يوقف WAF هذه الطلبات؟
WAF طبقة دفاع مفيدة، لكنه ليس بديلًا عن رفض التطبيق للمدخلات غير الصحيحة. لا يعرف WAF منطق عملك ولا يجب أن يكون خط الدفاع الوحيد.كم حالة سلبية أحتاج لكل نقطة نهاية؟
ابدأ بحالة واحدة لكل حقل ولكل فئة فشل: نوع خاطئ، قيمة خارج النطاق، طول زائد، حقل محظور، وسلسلة حقن ملائمة للسياق. تغطية الفئات أهم من عدد الحالات.هل يوقف التحقق من المخطط الحقن بالكامل؟
لا. المخطط الصارم يقلص سطح الهجوم ويرفض الحقول غير المتوقعة والمدخلات المشوهة، لكنه لا يغني عن الاستعلامات المعلّمة، وإلغاء التسلسل الآمن، وترميز المخرجات، وقوائم السماح للمُحمّلات والتنسيقات.
Top comments (0)