0Pricing
AI Engineering Academy · درس

أمان MCP والمصادقة

أضيفوا المصادقة إلى خادم MCP باستخدام رموز OAuth 2.0، ونفذوا التحقق من المدخلات لمنع هجمات الحقن، وطبّقوا مبدأ أقل الصلاحيات على أذونات الأدوات.

أمان MCP والمصادقة درس مجاني في AI Engineering Academy على CoddyKit. هذا هو الدرس 4 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في AI Engineering Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة AI Engineering Academy 4 دروس في المجموع.

لماذا يهم أمان MCP

خادم MCP هو بوابة إلى أنظمتكم. ومن دون أمان مناسب، قد يقرأ عميل ذكاء اصطناعي مخترق أو مطالبة خبيثة بيانات حساسة، أو يفعّل عمليات مدمرة، أو يسرّب المعلومات عبر قناة استدعاء الأدوات. يجب أن يستند أمان خوادم MCP إلى الدفاع متعدد الطبقات: المصادقة على مستوى النقل، والتفويض على مستوى الأداة، والتحقق من الإدخال في كل استدعاء.

أمان الخادم المحلي مقابل البعيد

يوفّر نقل stdio، الذي يستخدمه Claude Desktop، أمانًا متأصلًا: إذ يعمل الخادم كعملية محلية لا يمكن الوصول إليها إلا من المستخدم الذي بدأ تشغيلها. أما خوادم MCP المكشوفة على الشبكة باستخدام HTTP/SSE فتواجه مجموعة تهديدات أمان الويب كاملةً، مثل تجاوز المصادقة وهجمات الحقن والوصول غير المصرح به. وتختلف متطلبات الأمان اختلافًا كبيرًا بحسب نمط النشر.

  • stdio المحلي: الوثوق بالمستخدم المحلي والتركيز على التحقق من الإدخال
  • HTTP/SSE البعيد: مصادقة كاملة، وTLS، وتحديد معدل الطلبات، وتنقية الإدخال

المصادقة بمفتاح API للخوادم البعيدة

أبسط أساليب المصادقة لخوادم MCP البعيدة هو التحقق من مفتاح API عبر ترويسة HTTP. تحقّقوا من الترويسة Authorization: Bearer <token> في كل طلب وارد، وارفضوا الطلبات غير المصادق عليها باستخدام HTTP 401. خزّنوا مفاتيح API الصالحة في قاعدة بيانات مع بيانات وصفية للمستخدم حتى تتمكنوا من إبطال المفاتيح الفردية.

# For HTTP/SSE MCP servers using FastAPI or similar:
from fastapi import FastAPI, HTTPException, Depends, Header
from typing import Optional
import secrets

app_http = FastAPI()

# In production: store in database with user_id, created_at, last_used
VALID_KEYS = {'sk-mcp-abc123': {'user': 'alice', 'scopes': ['read']},
              'sk-mcp-def456': {'user': 'bob', 'scopes': ['read', 'write']}}

async def verify_api_key(authorization: Optional[str] = Header(None)) -> dict:
    if not authorization or not authorization.startswith('Bearer '):
        raise HTTPException(status_code=401, detail='Missing API key')
    key = authorization.removeprefix('Bearer ')
    if key not in VALID_KEYS:
        raise HTTPException(status_code=401, detail='Invalid API key')
    return VALID_KEYS[key]  # Returns user context

# Use in route handlers:
# @app_http.get('/sse')
# async def sse_endpoint(user=Depends(verify_api_key)):

OAuth 2.0 لخوادم MCP المؤسسية

بالنسبة إلى عمليات النشر المؤسسية، استخدموا OAuth 2.0 حتى يصادق المستخدمون باستخدام موفّر هويتهم المؤسسي مثل Okta أو Azure AD أو Google Workspace. يحصل عميل MCP على رمز وصول OAuth، ويضمّنه في طلبات استدعاء الأدوات. يتحقق خادمكم من توقيع الرمز مقابل المفاتيح العامة لموفّر الهوية باستخدام python-jose أو authlib.

from jose import jwt, JWTError
import httpx

AUTH_DOMAIN = 'your-tenant.auth0.com'
AUDIENCE = 'https://api.your-mcp-server.com'

async def get_jwks():
    async with httpx.AsyncClient() as client:
        resp = await client.get(f'https://{AUTH_DOMAIN}/.well-known/jwks.json')
        return resp.json()

async def verify_oauth_token(token: str) -> dict:
    jwks = await get_jwks()
    try:
        payload = jwt.decode(
            token,
            jwks,
            algorithms=['RS256'],
            audience=AUDIENCE,
            issuer=f'https://{AUTH_DOMAIN}/'
        )
        return payload  # Contains sub (user ID), scope, exp, etc.
    except JWTError as e:
        raise ValueError(f'Invalid token: {e}')

التفويض المستند إلى النطاقات

لا ينبغي أن تتاح جميع أدوات MCP لجميع المستخدمين. استخدموا نطاقات OAuth أو مطالبات الأدوار في رمز JWT لتحديد الأدوات التي يجوز للمستخدم الذي تمت مصادقته استدعاؤها. تحقّقوا من التفويض في بداية كل عملية تنفيذ لأداة، قبل إجراء أي استدعاء لقاعدة بيانات أو API.

TOOL_REQUIRED_SCOPES = {
    'list_products': ['read:products'],
    'search_products': ['read:products'],
    'create_order': ['write:orders'],
    'delete_order': ['admin:orders']
}

def check_authorization(tool_name: str, token_payload: dict):
    '''Raise ValueError if user lacks required scope for the tool.'''
    required = TOOL_REQUIRED_SCOPES.get(tool_name, [])
    if not required:
        return  # No scope required

    user_scopes = set(token_payload.get('scope', '').split())
    missing = [s for s in required if s not in user_scopes]
    if missing:
        raise ValueError(
            f'Access denied. Tool "{tool_name}" requires scopes: {missing}. '
            f'Your token has: {list(user_scopes)}'
        )

# In call_tool handler:
# check_authorization(name, current_user_token)
# ... then execute the tool

التحقق من الإدخال ومنع الحقن

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

import re
from pathlib import Path

BASE_DATA_DIR = Path('/data/mcp-files')

def safe_file_path(user_input: str) -> Path:
    '''Validate and normalize a file path to prevent traversal attacks.'''
    # Remove any path traversal sequences
    clean = re.sub(r'\.\./', '', user_input)
    clean = re.sub(r'\.\.\\\\', '', clean)
    path = (BASE_DATA_DIR / clean).resolve()

    # Ensure the resolved path is still within the allowed base directory
    if not str(path).startswith(str(BASE_DATA_DIR)):
        raise ValueError(f'Path traversal detected: {user_input}')

    return path

def safe_identifier(value: str) -> str:
    '''Validate a database identifier (table/column name).'''
    if not re.match(r'^[a-z_][a-z0-9_]{0,63}$', value, re.IGNORECASE):
        raise ValueError(f'Invalid identifier: {value}')
    return value

تحديد معدل استدعاءات الأدوات

قد يستدعي وكيل مبني على نموذج لغوي أدوات مكلفة مئات المرات في الدقيقة أثناء وجوده في حلقة، مما يستنزف اتصالات قاعدة البيانات أو حصص واجهات API التابعة لجهات خارجية أو ميزانية الحوسبة. نفّذوا حدودًا لمعدل الطلبات لكل مستخدم باستخدام خوارزمية دلو الرموز في Redis. ارفضوا استدعاءات الأدوات التي تتجاوز الحد برسالة خطأ وصفية حتى يعرف الوكيل أنه ينبغي عليه الانتظار.

import redis
import time

r = redis.Redis.from_url('redis://localhost:6379')

def check_rate_limit(user_id: str, tool_name: str, limit: int = 60, window: int = 60) -> None:
    '''Allow at most `limit` calls per `window` seconds per user per tool.'''
    key = f'rate:{user_id}:{tool_name}'
    pipe = r.pipeline()
    pipe.incr(key)
    pipe.expire(key, window)
    count, _ = pipe.execute()

    if count > limit:
        retry_after = r.ttl(key)
        raise ValueError(
            f'Rate limit exceeded for {tool_name}. '
            f'Limit: {limit} calls/{window}s. '
            f'Retry after {retry_after} seconds.'
        )

مبدأ أقل قدر من الامتيازات

طبّقوا مبدأ أقل قدر من الامتيازات في كل طبقة من خادم MCP الخاص بكم. ينبغي أن يملك مستخدم قاعدة البيانات صلاحية SELECT فقط على الجداول التي يحتاج إليها الخادم. ويجب أن تعمل عملية الخادم كمستخدم لنظام التشغيل ليس root. وينبغي أن تطلب الأدوات الأذونات التي تحتاج إليها فقط. كما يجب أن تملك مفاتيح API الحد الأدنى من النطاق اللازم لغرضها. كل إذن تمنعونه هو هجوم محتمل لا يمكن أن ينجح.

-- PostgreSQL: Create a dedicated read-only database user for your MCP server
CREATE ROLE mcp_reader LOGIN PASSWORD 'strong_random_password';

-- Grant SELECT on only the tables the server needs
GRANT SELECT ON products, categories, public_content TO mcp_reader;

-- Explicitly deny access to sensitive tables
REVOKE ALL ON users, api_keys, payment_methods FROM mcp_reader;

-- Never grant: INSERT, UPDATE, DELETE, TRUNCATE, or DDL permissions

أمان TLS والنقل

يجب أن تستخدم خوادم MCP البعيدة TLS لحماية البيانات أثناء النقل. اضبطوا خادمكم بحيث لا يقبل إلا اتصالات HTTPS. في بيئة الإنتاج، استخدموا وكيلًا عكسيًا مثل nginx أو Caddy لمعالجة إنهاء TLS، وحافظوا على تحديث الشهادات من خلال التجديد التلقائي، مثل Let's Encrypt عبر Certbot أو دعم ACME المضمّن في Caddy.

# Example Caddyfile for TLS-terminating MCP server at a subdomain:
#
# mcp.yourcompany.com {
#     reverse_proxy localhost:8080
#     encode gzip
#     tls internal  # Use Let's Encrypt in production
#     header {
#         Strict-Transport-Security 'max-age=31536000; includeSubDomains'
#         X-Content-Type-Options nosniff
#         X-Frame-Options DENY
#     }
# }

حقن المطالبات عبر موارد MCP

هناك مسار هجوم خفي: إذا قرأ خادم MCP الخاص بكم محتوى من مصادر خارجية، مثل صفحات الويب أو الملفات التي يحمّلها المستخدمون أو قواعد البيانات غير الموثوقة، وأعاده كنتيجة لأداة، فقد يضمّن المهاجم تعليمات عدائية في ذلك المحتوى. وقد يطيع النموذج تعليمات مخفية في البيانات المسترجعة؛ وهذا هو حقن المطالبات غير المباشر. نقّوا المحتوى المسترجع، ولا تعيدوا نصًا خامًا غير موثوق مباشرةً كمخرجات للأداة.

import re

def sanitize_for_mcp_output(text: str) -> str:
    '''Remove patterns that look like instructions to the LLM.'''
    # Remove common injection patterns
    dangerous_patterns = [
        r'ignore previous instructions',
        r'ignore all prior instructions',
        r'system:',
        r'<\|.*?\|>',  # Special tokens
        r'\[INST\]',
        r'<s>',
    ]
    for pattern in dangerous_patterns:
        text = re.sub(pattern, '[FILTERED]', text, flags=re.IGNORECASE)
    return text[:10000]  # Also cap length to prevent context stuffing

تدقيق الأمان والمراقبة

سجّل جميع الأحداث المرتبطة بالأمان: عمليات نجاح المصادقة وفشلها، ومخالفات حدود المعدل، وعمليات رفض التفويض، وأخطاء التحقق، وأنماط الوصول غير المعتادة. أعدّ تنبيهات للحالات التالية: محاولات مصادقة فاشلة متعددة (هجوم القوة الغاشمة)، واستدعاء مستخدم واحد لأدوات مدمّرة بسرعة، وأي استدعاء لأداة يتضمن مدخلات كبيرة للغاية. راجع سجلات التدقيق بانتظام، وأتمت اكتشاف الحالات الشاذة.

تحقق سريع

اختبر مدى فهمك لمفاهيم أمان MCP والمصادقة.

مراجعة الدرس

تعلّمت في هذا الدرس أن: خوادم MCP البعيدة تتطلب مصادقة OAuth 2.0 أو مصادقة باستخدام مفتاح API في كل طلب، وأن التفويض القائم على النطاقات يحدد الأدوات التي يمكن لكل مستخدم تمت مصادقته استدعاؤها، وأن جميع مدخلات الأدوات يجب التحقق منها لمنع هجمات الحقن واجتياز المسارات. بهذا نختتم وحدة MCP — وفي الدرس التالي نستكشف استراتيجيات متقدمة لتقسيم النصوص بهدف الاسترجاع عالي الدقة باستخدام RAG.

الأسئلة الشائعة

هل درس «أمان MCP والمصادقة» مجاني؟

نعم — نص درس «أمان MCP والمصادقة» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة AI Engineering Academy، انتقل إلى CoddyKit PRO. تتضمن دورة AI Engineering Academy 4 دروس في المجموع.

ماذا ستتعلم في «أمان MCP والمصادقة»؟

أضيفوا المصادقة إلى خادم MCP باستخدام رموز OAuth 2.0، ونفذوا التحقق من المدخلات لمنع هجمات الحقن، وطبّقوا مبدأ أقل الصلاحيات على أذونات الأدوات. تتمرن على AI Engineering Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ AI Engineering Academy؟

لا تُشترط خبرة سابقة. AI Engineering Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 4 من أصل 4.

كم من الوقت يستغرق درس «أمان MCP والمصادقة»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس AI Engineering Academy هذا؟

نعم. كل درس في AI Engineering Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. ما هو MCP ولماذا يهم
  2. بناء خادم MCP الأول لكم
  3. إتاحة موارد قواعد البيانات عبر MCP
  4. أمان MCP والمصادقة
← العودة إلى AI Engineering Academy