اگر سرور هوش مصنوعی شخصی شما دسترسی نوشتن به تمام یادداشتهای خصوصیتان را داشته باشد، هر نشت کوچک میتواند به یک فاجعه امنیتی تبدیل شود. Vault Cortex، یک سرور متنباز مبتنی بر پروتکل زمینه مدل (MCP)، با پیادهسازی کامل استک OAuth 2.1، این ریسک را برای کاربران Obsidian حذف کرده است تا از دسترسیهای غیرمجاز به «مغز دوم» کاربر جلوگیری کند. این رویکرد امنیتی در حالی اهمیت مییابد که بسیاری از کاربران پیش از این از روشهای اتصال Obsidian به ChatGPT برای تبدیل یادداشتهای خود به حافظه دائمی هوش مصنوعی استفاده میکردند که لزوماً استانداردهای سختگیرانه OAuth را نداشت.
بسیاری از سرورهای MCP در حال حاضر با شکافهای امنیتی خطرناکی عرضه میشوند. طبق یک تحلیل در سال ۲۰۲۶ که توسط این پروژه به آن استناد شده است، ۴۱٪ از سرورهای MCP هیچگونه سیستم احراز هویتی ندارند و تنها ۸.۵٪ آنها از OAuth استفاده میکنند. در یک سرور تککاربره، لو رفتن یک کد دسترسی ساده یعنی افشای تمام یادداشتهای خصوصی، کلیدهای API و تاریخچه پروژههای ذخیره شده در یک خزانه (Vault).
Vault Cortex به عنوان پلی میان claude.ai و یک خزانه محلی Obsidian عمل میکند. از آنجا که سرور باید از طریق دستگاههای موبایل قابل دسترس باشد، نمیتواند تنها به توکنهای محلی ساده تکیه کند. به همین دلیل، این پروژه از یک سیستم دوگانه استفاده میکند: OAuth 2.1 با قابلیت PKCE برای کلاینتهای دارای مرورگر مانند Claude Desktop، Claude Code و claude.ai، و توکنهای استاتیک (Bearer Tokens) برای ابزارهای خط فرمان (CLI)، MCP Inspector، دستورات curl و اتوماسیونها.
مدل تهدید
این سرور به طور خاص برای یک کاربر واحد طراحی شده است. در این مدل، نیازی به جداسازی مستاجران (Tenant Isolation) یا مهار جابجاییهای جانبی (Lateral Movement) نیست، اما ارزش دادهها بسیار بالاست. یک نفوذ موفق یعنی افشای همهچیز: از نظرات مربوط به کدنویسی و برنامههای سفر گرفته تا تاریخچه نشستهای هر پروژه.
برای محافظت از این دادهها، سرور محدودیتهای خاصی را اعمال میکند:
- مسدودسازی مسیرها: دسترسی به مسیرهایی که با نقطه شروع میشوند، مانند پوشه تنظیمات
.obsidian/در تمام عملیاتهای خزانه مسدود شده است. این کار مانع از آن میشود که توکنهای لو رفته، کلیدهای API شخص ثالث را که توسط پلاگینهای جامعه کاربری ذخیره شدهاند، افشا کنند. - مدیریت دادههای حساس: به دلیل اینکه یک نفوذ کل دادهها را یکباره لو میدهد، طراحی سیستم با دادههای یک کاربر به عنوان «دادههای با ارزش بالا» برخورد میکند و همین امر لزوم عبور از توکنهای استاتیک برای کلاینتهای مرورگر را ضروری میسازد.
مدلهای استقرار
این سرور در دو پیکربندی استقرار متمایز اجرا میشود. استقرار مرجع، یک سرور Express در یک کانتینر Docker روی AWS Lightsail VPS است. این مسیر دارای لایههای حفاظتی متعددی است: کلاینت $ \rightarrow $ Cloudflare (دامنه پروکسی شده، WAF) $ \rightarrow $ API Gateway (Lambda authorizer) $ \rightarrow $ Cloudflare Tunnel (قفل شده با Access) $ \rightarrow $ کانتینر (Express). در این ساختار، WAF و سیستم حفاظت در برابر DDoS کلودفلر در نقطه انتهایی عمومی قرار دارند و نام میزبان پیشفرض execute-api در گیتوی غیرفعال شده است تا تضمین شود که دامنه پروکسی شده تنها نقطه ورود است. این تاکید بر استفاده از ابزارهای متنباز و استقرار مستقل، بخشی از یک جریان گستردهتر است که در آن زیرساختهای قابل جابهجایی در برابر مدلهای بسته برای پایان دادن به مالکیت انحصاری دادهها مورد بحث قرار گرفتهاند.
در مقابل، استقرارهای تککلیکی در Render و Railway بدون هیچ لایه بیرونی اجرا میشوند: کلاینت $ \rightarrow $ کانتینر (Express). در این موارد، کانتینر باید خودش هر درخواست را احراز هویت کند. هر آنچه کانتینر به تنهایی انجام میدهد باید کافی باشد، در حالی که گیتوی AWS یک لایه امنیتی اضافی را فراهم میکند.
معماری OAuth 2.1
سرور به عنوان مرکز صدور مجوز (Authorization Server) خودش عمل کرده و یک جریان سختگیرانه ۹ مرحلهای را دنبال میکند تا تضمین شود هیچ نشستی بدون رضایت صریح کاربر ایجاد نمیشود. این امر ضروری است زیرا مدل اتصال claude.ai برای حسابهای فردی، یا OAuth را میپذیرد یا هیچچیز. (یک اعتبارنامه مبتنی بر هدر درخواست در نسخه بتا برای سازمانهای محدود وجود دارد، اما چون بین همه اعضای سازمان مشترک است، برای یک سرور شخصی نامناسب است.)

۱. POST /mcp (بدون توکن): بازگشت خطای ۴۰۱، همراه با WWW-Authenticate که به بخش شناسایی اشاره میکند.
۲. GET /.well-known/oauth-protected-resource: شناسایی مکان استقرار سرور مجوز (که در فرمت پسوند-مسیر RFC 9728 نیز ارائه میشود).
۳. GET /.well-known/oauth-authorization-server: ارائه لیست نقاط اتصال (Endpoints).
۴. POST /register: ثبت پویای کلاینت که در آن کلاینت نام و URIهای بازگشت خود را برای دریافت Client ID ارسال میکند.
۵. GET /authorize: کاربر به یک صفحه رضایت در مرورگر با یک code_challenge هدایت میشود.
۶. Consent: کاربر با وارد کردن یک توکن استاتیک مالکیت خود را ثابت میکند؛ سپس سرور با یک کد مجوز (Authorization Code) کاربر را بازمیگرداند.
۷. POST /token: کلاینت کد و code_verifier را با یک توکن دسترسی JWT و یک توکن نوسازی (Refresh Token) مبادله میکند.
۸. POST /mcp: درخواستهای واقعی با استفاده از هدر Authorization: Bearer <JWT> ارسال میشوند.
۹. POST /token (refresh_token): پس از انقضا، یک JWT جدید بدون نیاز به مرورگر صادر میشود.

ثبت پویا و تایید دسترسی
مرحله چهارم شامل ثبت پویای کلاینت است. اگرچه بازبینی جولای ۲۰۲۶ در مشخصات MCP این روش را به نفع «اسناد متادیتای کلاینت» (که در آن کلاینت خود را با URL-ی که میزبانی میکند معرفی میکند) کنار گذاشته است، اما SDK فعلی MCP در تایپاسکریپت هنوز از این اسناد پشتیبانی نمیکند.
این موضوع باعث میشود صفحه رضایت (Consent) به دروازه اصلی تبدیل شود. چون صفحه /authorize یک صفحه عمومی است، الزام به ارائه توکن استاتیک تضمین میکند که تنها اپراتور سرور بتواند یک کلاینت را تایید کند. حتی اگر مهاجمی کلاینتی با نامی آشنا ثبت کند، بدون داشتن رمز (Secret) نمیتواند توکنی دریافت کند. تنها ریسک موجود، مهندسی اجتماعی است، اما از آنجا که تنها یک اپراتور وجود دارد، هر لینک تایید غیرمنتظره یک هشدار واضح است.
در عمل، این جریان عمدتاً نامرئی است. در بررسی لاگهای تولیدی طی ۵۹ روز منتهی به ۲۲ اوت، تنها ۸ جریان رضایت در مرورگر رخ داده است؛ تقریباً ۹۰٪ از تمام توکنهای صادر شده از طریق نوسازیهای بیصدا (Silent Refreshes) ایجاد شدهاند. هر توکن دسترسی دارای شش ادعا (Claim) است: sub ،scope ،exp ،iss ،aud و iat.
سختسازی تولید و دفاع لایهای
در استقرار مرجع AWS، پروژه Vault Cortex از استراتژی «دفاع در عمق» با لایههای متعدد استفاده میکند.
مسیر مرجع: کلاینت $ \rightarrow $ Cloudflare (دامنه پروکسی شده، WAF) $ \rightarrow $ API Gateway (Lambda authorizer) $ \rightarrow $ Cloudflare Tunnel (قفل شده با Access) $ \rightarrow $ کانتینر (Express).
مسیر تککلیکی (Render/Railway): کلاینت $ \rightarrow $ کانتینر (Express).

این ساختار تضمین میکند که هر درخواست دو بار بهطور مستقل تایید شود. Lambda authorizer در لبه شبکه، امضای JWT، تاریخ انقضا، صادرکننده و مخاطب را بررسی میکند. سپس سرور Express پایگاهداده داخلی SQLite را چک میکند تا ببیند آیا توکن ابطال شده است یا خیر. هر دو لایه JWT را با یک رمز HMAC یکسان تایید میکنند اما هیچ ذخیرهساز نشست (Session Store) یا گام شبکهای مشترکی ندارند.
لاگهای حسابرسی از دو بازه ۳۰ روزه غیرهمپوشان، اثربخشی این لایهبندی را نشان میدهد:
- API Gateway: حدود ۱,۱۶۰ پاسخ ۴xx را مسدود کرد. این شامل ۱۷ درخواست از ۹ IP ناشناخته (اسکنرهای کلودفلر، درخواستهای favicon و curl) بود.
- Lambda Authorizer: از ۲۳,۶۱۹ فراخوانی، صفر مورد رد شد، زیرا درخواستهای بدون توکن قبلاً توسط گیتوی متوقف شده بودند.
- Express: تنها ۲ مورد رد درخواست داشت که هر دو تلاشهای عمدی با توکنهای اشتباه بودند که از طریق Tailscale برای تست لایه داخلی ارسال شده بودند.
درسهای سه ماه ترافیک واقعی
ترافیک واقعی تولیدی بین مه و اوت ۲۰۲۶ باعث ایجاد چندین تغییر معماری حیاتی شد.
تضاد ۴۰۳ در مقابل ۴۰۱
در ابتدا، افزودن سرور در claude.ai وضعیت «Connection issue» را نشان میداد. بررسیها نشان داد که کلاینتهای MCP جریان OAuth را با دریافت پاسخ ۴۰۱ شروع میکنند. اما وقتی Lambda authorizer در یک HTTP API در AWS درخواستی را رد میکند، گیتوی پاسخ ۴۰۳ برمیگرداند.
در حالی که Claude Code هر دو پاسخ را میپذیرفت، claude.ai سختگیرانه نیاز به ۴۰۱ داشت. راه حل این مشکل، ثبت هدر Authorization به عنوان منبع هویت authorizer و جداسازی مسیرها بود. اکنون درخواستهای بدون توکن به /mcp پیش از فراخوانی Lambda، یک پاسخ ۴۰۱ خودکار از گیتوی دریافت میکنند که باعث کاهش هزینه و اصلاح وضعیت اتصال شد. این یک اصلاح حیاتی بود زیرا اتصالهای برقرار شده هرگز قطع نمیشدند (نوسازی از مسیر باز /token استفاده میکند)، بنابراین مشکل فقط هنگام تنظیمات اولیه کانکتور ظاهر میشد.
شکافهای استاندارد و خطاهای ۴۰۴
در اوایل اوت، Perplexity تعداد ۶۳ درخواست ارسال کرد که منجر به خطای ۴۰۴ شد. این کلاینت از RFC 9728 پیروی میکرد و مسیر /.well-known/oauth-protected-resource/mcp (URL شناسایی با پسوند مسیر) را درخواست میکرد. سرور تنها سند ریشه را ارائه میداد. افزودن مسیر پسوندی این خطاها را از بین برد.
محدودیت نرخ و اعتماد به پروکسی
یک پژوهشگر امنیتی آسیبپذیریای را گزارش کرد که در آن محدودکننده نرخ (Rate Limiter)، سطل (Bucket) خود را بر اساس هدر Forwarded ارسالی کلاینت کلیدگذاری میکرد. یک مهاجم میتوانست این هدر را جعل کند تا برای هر درخواست یک سطل جدید باز کند و محدودیتهای نقطه انتهایی /register (که احراز هویت نمیخواهد) را دور بزند. یک اثبات مفهوم (PoC) نشان داد در حالی که ۶ درخواست کنترلی باعث ایجاد خطای ۴۲۹ شد، ۶ درخواست جعل شده همگی پذیرفته شدند و ۱۲ ردیف در جدول کلاینتها ایجاد کردند.
برای رفع این مشکل، متغیرهای TRUST_PROXY_HOPS و TRUST_FORWARDED_HOPS معرفی شدند که هر دو به طور پیشفرض صفر هستند.
- در حالت ۰: هدر نادیده گرفته شده و کلید سطل بر اساس TCP peer تعیین میشود.
- در حالت Trust: تجزیهکننده (Parser) به جای شروع زنجیره، از انتهای زنجیره (ادعاهای خود پروکسی) میخواند.
برای مسیر AWS، مقدار TRUST_FORWARDED_HOPS روی ۲ (Cloudflare $ \rightarrow $ Gateway) تنظیم شده است. این کار از جعل هویت peer توسط مهاجمان جلوگیری میکند. همچنین محدودیت نرخ به ۵ درخواست در دقیقه سختتر شد. لاگهای تولید نشان میدهد این مقدار کافی است؛ شدیدترین burst ثبت شده (۴ ثبت، ۲ تایید و ۲ تبادل توکن در ۴۰ ثانیه) بدون محدود شدن عبور کرد. برای جلوگیری از تورم پایگاهداده، ثبتهایی که قدیمیتر از یک هفته هستند و توکن نوسازی منقضی نشدهای ندارند، هنگام بوت شدن و پیش از ثبتهای جدید پاکسازی میشوند.
چرخه عمر و نوسازی توکنها
منطق توکنهای نوسازی در Vault Cortex طی چهار نسخه تکامل یافت تا شکافهای امنیتی بسته شوند:
- نسخه ۱ (لانچ): در هر بار استفاده نوسازی میشد، اما تاریخ انقضا نداشت.
- نسخه ۲ (۳ روز پس از لانچ): یک پنجره غیرفعال بودن لغزان ۶۰ روزه اضافه شد. این تضمین میکند که توکن لو رفته برای یک کلاینت غیرفعال، در نهایت منقضی شود. مهاجرت به این نسخه باعث شد نشستهای فعال یک بار دوباره احراز هویت شوند.
- نسخه ۳ (اوت): ذخیرهسازی از متن ساده به ردیفهایی با کلید
HMAC-SHA256(secret, token)تغییر یافت. این تضمین میکند که تغییر رمز استاتیک، تمام توکنهای نوسازی را یتیم کرده و تمام نشستها را یکباره پایان دهد. همچنین توکنهای نوسازی اکنون طبق پیشنویس OAuth 2.1 به کلاینت ثبتکننده متصل هستند. - نسخه ۴ (اوت): قابلیت تشخیص استفاده مجدد (Reuse Detection) پیاده شد. اگر یک توکن نوسازی که قبلاً جایگزین شده است دوباره ارائه شود، سرور کل مجوز (Grant) شامل توکن نوسازی و تمام توکنهای دسترسی مرتبط را ابطال میکند.
برای به حداقل رساندن پنجره فرصت برای یک JWT لو رفته، عمر توکنهای دسترسی از ۲۴ ساعت به ۶ ساعت کاهش یافت. در ۵۹ روز لاگ، ۷۵ نوسازی بیصدا در ۹ کلاینت هیچ اختلال مشهودی ایجاد نکرد، که ثابت میکند عمر کوتاهتر توکنها از نظر تجربه کاربری (UX) تقریباً بدون هزینه است. توکن استاتیک که به عنوان کلید امضا استفاده میشود، به صورت ۳۲ بایت تصادفی (openssl rand -hex 32) تولید میشود تا حملات Brute Force غیرممکن شود.
تاییدکننده و تطبیق با استاندارد
برای اجتناب از ریسکهای «سطح ویژگی» (Feature Surface) در کتابخانههای بزرگ، پروژه از یک تاییدکننده JWT سفارشی در ۳۰ خط کد استفاده میکند که بر پایه توابع داخلی Node.js (crypto.createHmac و crypto.timingSafeEqual) ساخته شده است.
این طراحی از حملات رایج جلوگیری میکند:
- سردرگمی الگوریتم (Algorithm Confusion): تاییدکننده فقط HS256 را میپذیرد و هدر
algرا تجزیه نمیکند. - حملات زمانبندی (Timing Attacks): استفاده از
timingSafeEqualتضمین میکند که مهاجمان نتوانند با اندازهگیری زمان پاسخ، به سمت یک امضای معتبر حرکت کنند. یک پیشبررسی طول (Length pre-check) استفاده شده است زیرا این تابع در صورت نابرابر بودن بافرها خطا میدهد، که در غیر این صورت به جای خطای ۴۰۱، به صورت خطای ۵۰۰ ظاهر میشد. - اندازه باندل: استفاده از توابع داخلی باعث میشود بسته Lambda authorizer کوچک بماند و از وارد کردن کتابخانههای ۲۰۰ کیلوبایتی برای یک الگوریتم واحد اجتناب شود.
در نهایت، پروژه دو شکاف در مشخصات MCP و OAuth 2.1 را بست. ادعاهای «مخاطب» (aud) و «صادرکننده» (iss) به توکنها اضافه شدند. این کار مانع از آن میشود که توکن یک استقرار در استقرار دیگری (در صورتی که رمز مشترک داشته باشند) استفاده شود. از آنجا که رد کردن توکنهای پیش از ارتقا در گیتوی باعث خطای ۴۰۳ (و مسدود شدن نوسازیها) میشد، گیتوی موقتاً آنها را عبور میدهد در حالی که Express پاسخ ۴۰۱ لازم برای تحریک نوسازی بیصدا را برمیگرداند.
اسکن امنیتی و لاگهای حسابرسی
پس از اینکه یک سایت اسکنر بهاشتباه نمره 'F' را با ۴۳۸ آسیبپذیری به سرور داد (به دلیل شناسایی اشتباه دستورات import به عنوان رمزهای سختافزاری و setTimeout به عنوان eval())، پروژه سیستم جامع لاگ حسابرسی OAuth را پیاده کرد. این سیستم شامل ۱۴ نوع رویداد است که ثبت، مجوزدهی، نتایج PKCE، گرنتها و ابطالها را پوشش میدهد.
این اقدام در پی مطالعهای در جولای ۲۰۲۶ بود که نشان داد اسکنرهای محبوب به طور متوسط تنها ۴۵.۵٪ دقت در شناسایی آسیبپذیریهای سرورهای MCP دارند. اکنون پروژه در CI از CodeQL، Socket Security، Gitleaks، Trivy، OpenSSF Scorecard و Dependabot استفاده میکند و نسخهها را در یک لاگ شفافیت عمومی با cosign امضا میکند.
این رویکرد سختگیرانه، یک ابزار شخصی را به یک گیتوی امن در سطح تولید تبدیل میکند. با برخورد با دادههای یک کاربر واحد به عنوان دادههای با ارزش بالا، Vault Cortex الگویی برای سایر توسعهدهندگان MCP فراهم میکند تا از استقرارهای «بدون احراز هویت» فاصله بگیرند.
گام بعدی شما
- اگر سرور MCP شخصی دارید، بررسی کنید آیا از توکنهای استاتیک استفاده میکنید یا OAuth؛ در صورت نبود OAuth، سریعاً لایهای مانند Cloudflare Access را اضافه کنید.
- برای توسعهدهندگان: پیادهسازی
timingSafeEqualدر تایید توکنها را برای جلوگیری از حملات زمانبندی به عنوان یک استاندارد در نظر بگیرید. - بررسی کنید که آیا مسیرهای حساس مانند
.obsidian/در سرورهای شما مسدود شدهاند یا خیر.
اما داستان سختافزاری این تحول حتی شگفتانگیزتر است — به تحلیل ما دربارهی تراشههای Blackwell مراجعه کنید.




گفتگو