تصور کنید ابزاری میسازید که قرار است با هوش مصنوعی ارتباط برقرار کند، اما یک گزارش امنیتی به شما میگوید درگاهی را ببندید که دقیقاً همان پل ارتباطی است. اگر این توصیه را اجرا کنید، عملاً توانایی مدلهای هوش مصنوعی برای اتصال به ابزارهای خارجی شما را نابود کردهاید. این تنش بهتازگی در سرویس QRFLOW.codes — یک سرویس تولید کد QR که دارای سرور پروتکل زمینه مدل (Model Context Protocol یا MCP) است — رخ داد. یک گزارش امنیتی پیشنهاد داده بود که درگاه POST /api/oauth/register بسته شود تا از ثبت غیرمجاز کلاینتها جلوگیری شود.
این تضاد، نشاندهنده یک تنش رو به رشد در اکوسیستم پروتکل زمینه مدل (MCP) است. MCP به دستیارهای هوش مصنوعی مانند Claude یا ChatGPT اجازه میدهد تا به عنوان کلاینتهای OAuth به سروری متصل شوند که پیش از این هرگز با آن مواجه نشدهاند. این فرآیند باید در عرض چند میلیثانیه و بدون نیاز به اینکه یک مدیر سیستم انسانی فرمی را تأیید کند، رخ دهد. به همین دلیل، ثبت پویای کلاینت (Open Dynamic Client Registration یا DCR) بیش از آنکه یک آسیبپذیری باشد، یک ضرورت فنی است. این چالشهای امنیتی در پیادهسازی MCP موضوع جدیدی نیست و پیشتر در تحلیلهای گستردهتر مشخص شد که بسیاری از سرورهای رسمی این پروتکل در برابر آزمونهای نفوذ رفتاری شکست میخورند.
طبق گزارشی که در ۲۶ سپتامبر ۲۰۲۶ از طریق وبسایت dev.to منتشر شد، پژوهشگر امنیتی استدلال کرد که اجازه دادن به هر کسی برای ثبت یک کلاینت با هر آدرس بازگشت (Redirect URI) از نوع HTTPS، یک نقص امنیتی است. در این گزارش اشاره شد که درگاه مذکور، ثبتنامها را از هر کسی و با هر آدرس بازگشت HTTPS میپذیرد و آنها را بدون نیاز به اعتبارنامه، بررسی دستی یا لیست سفید (Allowlist) ذخیره میکند. با این حال، توسعهدهنده اشاره کرد که الزام به توکن دسترسی اولیه (Initial Access Token) یا بررسی دستی، صرفاً باعث میشود سرور MCP برای تمام کلاینتهای واقعی در دنیای واقعی غیرفعال شود.
آسیبپذیری مورد سوءبرداشت
پژوهشگر در اینجا «ثبت باز» (Open Registration) را با «بازگشت باز» (Open Redirect) اشتباه گرفته بود. گزارش مذکور پیشنهاد داده بود که یک لیست سفید برای redirect_uri اجباری شود، اما شما نمیتوانید برای برنامههایی که هنوز وجود ندارند، آدرسهای بازگشت را در لیست سفید قرار دهید. هدف اصلی ثبت پویا دقیقاً همین است.
در یک پیادهسازی صحیح، سرور در زمان صدور مجوز (Authorization Time)، هرگونه بازگشتی را که کلاینت برای خودش ثبت نکرده باشد، رد میکند. QRFLOW.codes این مورد را در فراخوانی authorize بررسی میکند و مجدداً در مرحله تبادل توکن (Token Exchange) آن را بازبینی مینماید. اگر این بررسی شکست بخورد، سیستم یک خطای OAuthError با پیام «آدرس بازگشت برای این برنامه ثبت نشده است» صادر میکند.
برای تضمین امنیت، QRFLOW.codes استفاده از PKCE با متد S256 را برای هر کلاینت ثبتشده بهصورت پویا اجباری کرده است. این مورد اختیاری نیست. کد سیستم بهطور صریح بررسی میکند: if (client.dynamic && (!codeChallenge || method !== "S256")) throw new OAuthError("invalid_request", "PKCE with code_challenge_method=S256 is required.");. این سازوکار تضمین میکند که حتی اگر یک کد مجوز (Authorization Code) شنود شود، بدون داشتن کد تأیید (Code Verifier) متناظر، هیچ ارزشی نخواهد داشت. برای مقایسه با استانداردهای سختگیرانهتر، میتوان به رویکرد Vault Cortex در جلوگیری از افشای دادههای حساس در سرورهای MCP اشاره کرد که لایههای امنیتی متفاوتی را برای احراز هویت به کار میگیرد.
حفره امنیتی واقعی: فیشینگ در صفحه تأیید
در حالی که درگاه ثبت دقیقاً طبق طراحی کار میکرد، توسعهدهنده متوجه یک نقص واقعی در صفحه تأیید (Consent Screen) شد. سیستم فیلد client_name — که یک رشته متنی آزاد است و توسط ثبتکننده ارسال میشود — را مستقیماً در رابط کاربری (UI) رندر میکرد.
صفحه تأیید پیش از این میپرسید: «آیا {client_name} به حساب QRFLOW.codes شما متصل شود؟». این متن با رنگهای رسمی برند نمایش داده میشد و مقصد واقعی تنها با فونتی کوچک در زیر آن لیست شده بود.
یک مهاجم میتوانست کلاینتی با نام «پشتیبانی رسمی QRFLOW» ثبت کند و لینک صفحه تأیید واقعی را در دامنه اصلی برای کاربران بفرستد. چون رابط کاربری نام انتخابی مهاجم را با رنگهای برند نشان میداد و از گواهینامه TLS واقعی استفاده میکرد، کاربران به احتمال زیاد به این درخواست برای اتصال حساب خود به یک سرور مخرب اعتماد میکردند. این حمله یک آسیبپذیری فنی به معنای معمول کلمه نبود، بلکه نمایش متنی که تحت کنترل مهاجم است به گونهای بود که گویی یک حقیقت تأیید شده است.
راهکار سه مرحلهای برای ترمیم
توسعهدهنده برای حل این مشکل بدون تخریب قابلیت MCP، سه تغییر مشخص اعمال کرد:
- شناسایی مبتنی بر میزبان (Host-Based Recognition): سیستم اکنون برنامهها را بر اساس میزبان بازگشت (Redirect Host) میشناسد، نه نام آنها. میزبان تنها بخشی از ثبتنام است که مهاجم نمیتواند جعل کند، زیرا باید واقعاً کالبکها را در آنجا دریافت کند. سیستم از یک مجموعه سختافزاری (Hardcoded) به نام
KNOWN_CLIENT_HOSTSاستفاده میکند که شامل موارد زیر است:claude.aiوclaude.comchatgpt.com،chat.openai.comوplatform.openai.comcursor.comوcursor.shglama.aiwww.canva.com
این لیست بهجای ذخیره در دیتابیس، بهصورت سختافزاری تعریف شده تا از تبدیل شدن به یک هدف در زمان اجرا (Runtime Target) برای مهاجمان جلوگیری شود.
- بنرهای هشدار پویا: پیش از این، هشدارهای نارنجیرنگ فقط برای کلاینتهای لوپبک (برنامههای روی ماشین کاربر) نمایش داده میشد. اکنون هر برنامهای که در لیست میزبانهای شناختهشده نباشد، یک بنر هشدار را فعال میکند. رابط کاربری صراحتاً بیان میکند: «این برنامه خودش را X مینامد و شما را به example.com میفرستد»، و بدین ترتیب نام برنامه را به عنوان یک «ادعا» مطرح میکند نه یک «واقعیت». این کار با کمی کردن نمایش بنر، از «خستگی هشدار» (Warning Fatigue) جلوگیری میکند.
- مسدودسازی جعل هویت: یک فیلتر Regex ساده اکنون هر تلاشی برای ثبت کلاینتی که نام آن شامل کلمه «QRFLOW» باشد را مسدود میکند. کد این مورد را به این شکل پیاده کرده است:
if (/qrflow/i.test(rawName)) throw new OAuthError("invalid_client_metadata", 'Client names may not contain "QRFLOW".');. این اقدام متقاعدکنندهترین نسخه حمله را حذف میکند.
عبور از تله محدودیت نرخ در محیط Serverless
معتبرترین نکته پژوهشگر مربوط به نبود محدودیت نرخ (Rate Limiting) بود که میتوانست منجر به انباشت دادههای زباله در جدول oauth_clients و افزایش هزینهها شود. با این حال، پیادهسازی این مورد در پلتفرمهای Serverless مانند Vercel یک چالش خاص ایجاد میکند.
محدودیتهای نرخ در حافظه (In-memory) در محیطهای Serverless بیفایده هستند، زیرا لودبالانسر درخواستها را بین چندین نمونه ایزوله توزیع میکند. شمارندهای که در یک پروسه است، برای پروسه دیگر نامرئی است و باعث میشود محدودیت صرفاً «تزئینی» باشد و بهراحتی دور زده شود.

برای حل این مشکل، توسعهدهنده شمارنده را به Postgres از طریق یک تابع RPC در Supabase به نام oauth_register_bump منتقل کرد. منطق سیستم اکنون آدرس IP را بررسی میکند و در صورت تجاوز از حد مجاز، خطای RateLimited صادر میکند.
محدودیت اکنون روی ۱۰ ثبت برای هر IP در هر ساعت تنظیم شده است. این عدد از الگوهای ترافیکی واقعی استخراج شد؛ جایی که شدیدترین فشار قانونی ثبت شده، ثبت ۶ باره مدل Claude در عرض چند دقیقه طی مراحل تست بود. این مقدار فضای لازم برای کاربران واقعی را فراهم میکند و در عین حال از حملات دادههای زباله جلوگیری میکند. هر مورد رد شده ثبت (Log) میشود تا اطمینان حاصل شود که کاربران قانونی بهطور بیصدا مسدود نمیشوند.
برای توسعهدهندگانی که سرورهای MCP را عرضه میکنند، درس این است که استاندارد OAuth (RFC 7591) به شما میگوید چه چیزی را تأیید کنید، اما نمیگوید چگونه آن را رندر کنید. خطر در رابط کاربری (UI) نهفته است، جایی که متن کنترلشده توسط مهاجم اغلب به عنوان حقیقت نمایش داده میشود.
اگر در حال ساخت یک سرویس سازگار با MCP هستید، فوراً صفحات تأیید دسترسی خود را بازبینی کنید. هر فیلدی را به دو دسته «آنها این را کنترل میکنند» و «آنها نمیتوانند این را جعل کنند» تقسیم کنید. مطمئن شوید که میزبان بازگشت را اعتبارسنجی میکنید و با نام کلاینت به عنوان یک ورودی غیرقابل اعتماد برخورد میکنید.
گام بعدی شما
- اگر سرویس MCP ارائه میدهید، فوراً صفحات تأیید دسترسی خود را بازبینی کنید.
- هر فیلدی را که توسط کاربر/کلاینت ارسال میشود در دسته «غیرقابل اعتماد» قرار دهید و هرگز آن را به عنوان حقیقت مطلق در UI نمایش ندهید.
- میزبان بازگشت (Redirect Host) را اعتبارسنجی کنید و از PKCE برای تمام کلاینتهای پویا استفاده کنید.
اما داستان سختافزاری این تحول حتی شگفتانگیزتر است — به تحلیل ما درباره تراشههای Blackwell مراجعه کنید.




گفتگو