یک پرامپت که به عامل هوش مصنوعی میگوید «فقط بخوان و هرگز ننویس»، صرفاً یک پیشنهاد است که با یک تزریق پرامپت (Prompt Injection) هوشمندانه بهسادگی دور زده میشود. برای توسعهدهندگانی که Claude Code را در محیط تولید (Production) مستقر میکنند، تنها مرز واقعی جایی است که انجام عملیات خطرناک بهصورت فیزیکی غیرممکن باشد. این تغییر رویکرد از «اعلام» به «اجرا»، هستهٔ اصلی چارچوب جدید سختسازی برای ابزارهای دیتابیس در پروتکل زمینهٔ مدل (MCP) است که در ۱۳ ژوئیه ۲۰۲۶ منتشر شد.
پروتکل زمینهٔ مدل — شبیه به یک مترجم استاندارد که اجازه میدهد مدلهای مختلف با هر نوع نرمافزار یا دیتابیسی با زبان واحد صحبت کنند — اکنون نیاز به لایههای حفاظتی سختگیرانهتری دارد. همانطور که در تحلیل قبلی ما دربارهی روشهای عیبیابی Claude Code با APIهای خارجی اشاره کردیم، این راهنمای جدید بهدنبال پر کردن «شکاف تولید» است. در حالی که آموزشهای اولیه MCP بر حداقل عملکرد تمرکز داشتند — مانند ابزار دیتابیس حداقلی که در بخش چهارم سری «فراتر از پرامپت» معرفی شد — ابزارهای دنیای واقعی به حفاظهای ساختاری نیاز دارند. چالش اینجاست که مدلهای زبانی بزرگ (LLM) — مثل کتابخانهداری که میلیاردها صفحه را خوانده و حالا با همان لحن جواب میدهد — گاهی پرسوجوهای «نادانی» تولید میکنند؛ مثلاً یک Cross-join تصادفی که میتواند کل دیتابیس را بدون هیچ قصد تخریبی، صرفاً به دلیل مصرف شدید منابع، کرش کند. در این نقطه، تفاوت بین «به او گفتم که نکند» و «فیزیکاً نمیتواند انجام دهد»، تفاوت بین یک خطای کوچک و یک حادثه بزرگ سیستمی است.
لایه ۱: حفاظت ساختاری از نوشتن
بسیاری از توسعهدهندگان به تراکنشهای Read-only اکتفا میکنند، مثلاً با استفاده از دستور SET default_transaction_read_only = on یا تنظیم conn.read_only = True در کتابخانه psycopg. اما این روشها قابل بازگشت هستند؛ یک پرسوجوی تزریقشده از طریق پرامپت میتواند بهسادگی دستور SET transaction_read_only = off را اجرا کرده و مجدداً اجازه نوشتن در دیتابیس را به دست آورد. چون این تنظیم صرفاً یک فلگ (پرچم) است، میتوان آن را تغییر داد و خاموش کرد.
تنها دیوار واقعی و ساختاری، تعریف یک Role در دیتابیس است که بهطور کلی هیچ دسترسی INSERT، UPDATE، DELETE یا مجوزهای DDL (تغییر ساختار دیتابیس) در هیچ کجای سیستم ندارد. با اعطای دسترسی SELECT تنها روی اسکیماهای مشخص، امتیاز نوشتن برای ابزار وجود نخواهد داشت و بنابراین هیچ کلیدی برای تغییر این وضعیت وجود ندارد. این پیکربندی باید با رویکرد «ابتدا محدودیت» (grants-first) انجام شود:
- ایجاد نقش محدود:
CREATE ROLE claude_readonly LOGIN PASSWORD '***'; - سلب تمام دسترسیهای پایه:
REVOKE ALL ON SCHEMA app FROM claude_readonly; - افزودن دسترسیهای ضروری:
GRANT USAGE ON SCHEMA app TO claude_readonly; - اعطای دسترسی خواندن مشخص:
GRANT SELECT ON app.orders_summary TO claude_readonly;
اگرچه توصیه میشود تراکنشهای Read-only را به عنوان یک لایه حفاظتی اضافی (مانند استفاده همزمان از کمربند و تعلیق شلوار) نگه دارید، اما «اعطای دسترسی» (Grant) دیوار واقعی است. بررسیهای مبتنی بر رشته (String-based checks) مانند sql.strip().startswith("select") باید حذف شوند یا تنها برای نمایش پیامهای خطای دوستانه استفاده گردند؛ چرا که یک پرسوجو مانند SELECT 1; DROP TABLE users بهراحتی از چنین بررسیهایی عبور کرده و دیتابیس را تخریب میکند.
لایه ۲: جلوگیری از تخلیه منابع
دسترسی Read-only جلوی تخریب دادهها را میگیرد، اما مانع از آن نمیشود که مدل از طریق اجرای پرسوجوهای runaway، یک حادثه سیستمی ایجاد کند. برای اینکه سرور در محیط تولید پابرجا بماند، دو تنظیم غیرجذاب اما حیاتی مورد نیاز است:
- Timeouts دستورات: اجرای
cur.execute("SET statement_timeout = '5s'")تضمین میکند که Cross-joinهای تصادفی که سعی در خواندن میلیاردها ردیف دارند، قبل از اینکه باعث کرش سیستم شوند،e متوقف گردند. - سقف ردیفها: پیادهسازی
rows = cur.fetchmany(500)مجموعه نتایج را محدود میکند. این کار مانع از آن میشود که یک پرسوجوی قانونی، دادههای بیشتری از آنچه حافظه سیستم یا پنجرهٔ زمینه (Context Window) — مثل میز کاری که فقط جای چند ورق دارد، نه کل کتابخانه — میتواند مدیریت کند، بازگرداند. - محدودیت اتصالات: افزودن سقف برای نقش کاربر از طریق
ALTER ROLE claude_readonly CONNECTION LIMIT 4تضمین میکند که یک ابزار گیرکرده نتواند کل استخر اتصالات (Connection Pool) را تخلیه کند.

لایه ۳: محدود کردن دسترسی از طریق Viewها
حفاظت از نوشتن به این پرسش پاسخ میدهد که «آیا ابزار میتواند به دادهها آسیب بزند؟»، اما این سوال را نادیده میگیرد که «آیا ابزار میتواند دادههایی را ببیند که نباید ببیند؟». یک نقش Read-only کلی با دسترسی به کل اسکیما، با خوشحالی کل جدول کاربران را در اختیار مدل قرار میدهد، حتی اگر وظیفه مدل فقط شمارش سفارشات دیروز بوده باشد.
برای حل این مشکل، توسعهدهندگان باید بهجای یک نقش واحد و قدرتمند «خدا-خواننده»، برای هر ابزار یک هویت (Identity) مجزا تعریف کنند. محدوده خواندن باید بهصورت صریح در اسکیمای دیتابیس و با استفاده از Viewهای Read-only طراحیشده برای اهداف خاص، بهجای جداول پایه تعریف شود:
- نمونه View:
CREATE VIEW app.orders_summary AS SELECT order_id, status, created_at, total_cents FROM app.orders;(توجه کنید که ستونهایcustomer_emailیاaddressدر اینجا حذف شدهاند). - نمونه Grant:
GRANT SELECT ON app.orders_summary TO claude_readonly;
فیلتر کردن نتایج در کدِ ابزار یک اشتباه است؛ این کار صرفاً همان خطای startswith است که کلاه متفاوتی سر دارد. با استفاده از Viewها، موتور دیتابیس مرز را اجرا میکند تا حتی یک دستور SELECT خلاقانه هم نتواند به ستونی دسترسی یابد که View آن را نمایش نمیدهد.
لایه ۴: مجوزهای بادوام
مجوزهای استاندارد (Grants) مربوط به لحظه اعطاست. اگر توسعهدهندهای از GRANT SELECT ON ALL TABLES استفاده کند، این دستور فقط جداولی را پوشش میدهد که امروز وجود دارند. جدولی که ماه آینده ایجاد شود، بدون مجوز برای نقش read-only متولد میشود. اگرچه این وضعیت باعث میشود جدول بهصورت پیشفرض در برابر نوشتن امن باشد، اما باعث میشود دسترسی خواندن بهطور بیصدا قطع شود و وضعیت امنیتی به یک فرآیند دستی (و در نتیجه فراموششدنی) تبدیل گردد.
برای بادوام کردن مجوزها، از ALTER DEFAULT PRIVILEGES استفاده کنید. با اجرای دستور ALTER DEFAULT PRIVILEGES IN SCHEMA app GRANT SELECT ON TABLES TO claude_readonly; هر جدول آینده در آن اسکیما بهطور خودکار «خواندنی-اما-هرگز-غیرقابل-نوشتن» خواهد بود و تضمین میکند که دیوار امنیتی بدون دخالت دستی پابرجا میماند.
لایه ۵: تست کنترل منفی
پیکربندی یک سیستم بهصورت Read-only یک «اعلام» است؛ اما اثبات آن یک «اجرا» است. مرزی که هرگز مورد حمله قرار نگرفته، صرفاً اعلام شده است. این چارچوب پیشنهاد میکند یک تست کنترل منفی در خط لوله CI اضافه شود تا وجود این دیوار تأیید گردد.
این تست باید یک شیء (Object) تازه را مورد حمله قرار دهد تا ثابت کند DEFAULT PRIVILEGES برای جداول ماه آینده نیز کار میکند، نه فقط برای جداول امروز. یک جریان تست معمولی شامل موارد زیر است:
- اتصال بهعنوان مدیر (Admin) برای ایجاد یک جدول کاملاً جدید:
CREATE TABLE app.scratch_probe (id int). - اتصال با نقشِ ابزار و تلاش برای اجرای
INSERT INTO app.scratch_probe VALUES (1). - الزام سیستم به بازگرداندن خطای
psycopg.errors.InsufficientPrivilege. - حذف جدول probe از طریق حساب مدیر.
اگر این تست زمانی از سبز به قرمز تغییر کند، یعنی تضمین Read-only دچار پسرفت شده است و تیم توسعه بهجای اینکه در حین یک حادثه تولید متوجه شود، در مرحله CI با آن مواجه میشود.
لایه ۶: محیط ایزوله در سطح سیستمعامل (Sandboxing)
حفاظهای دیتابیس از دادهها محافظت میکنند، اما خودِ سرور MCP یک پروسه است. یک باگ در هر ابزار نباید اجازه دهد پروسه فراتر از مجوزهای اعطاشده برود. برای تضمین استقلال کامل، کل سرور MCP باید بهعنوان یک کاربر لینوکسی بدون دسترسی (unprivileged) اجرا شود. این ضرورت سختگیرانه به دلیل تجربیاتی است که در بررسیهای امنیتی پیشین بر روی Claude Code صورت گرفت، جایی که حفرههای امنیتی امکان دسترسی ریشه به کدهای محرمانه را فراهم کرده بود.
این محیط ایزوله شامل موارد زیر است:
- یک لیست سفید (allowlist) قفلشده در sudoers (یا عدم دسترسی کامل به sudo).
- سیستم-فایلی (Filesystem) که دقیقاً به دایرکتوری خودش محدود شده است.
- حذف تمام اعتبارنامههای محیطی (Ambient Credentials) مربوط به سرویسهایی که ابزار بهطور مشخص از آنها استفاده نمیکند.
با انجام این کار، حتی یک ابزار هکشده یا دارای باگ نمیتواند به دایرکتوری /etc نفوذ کند یا سرویسهای غیرمرتبط را لمس کند. این کار یک «دفاع در عمق» (defense-in-depth) ایجاد میکند که در آن مجوزهای دیتابیس، کاربر سیستم-عامل و کد ابزار، هر کدام بهطور مستقل از عملیات خطرناک خودداری میکنند.
لایه ۷: لاگبرداری مبتنی بر Assertion
لاگهای حسابرسی خام — که پرسوجوهای نرمالشده، اسکیمای نتایج و تعداد ردیفها را ردیابی میکنند — بهندرت بهصورت پیشدستانه خوانده میشوند. لاگی که فقط بعد از یک کرش باز شود، یک ابزار جرمشناسی است که بهطور ماهیتی «واکنشی» است. برای تبدیل لاگها به یک مکانیزم اجرایی، آنها باید به هشدار (Alert) تبدیل شوند.
تأییدیههای (Assertions) مؤثر شامل موارد زیر هستند:
- هشدار در زمانی که یک ابزار با مسیر نوشتن (write-path) خارج از بازه زمانی مورد انتظار خود فعال شود.
- هشدار در زمانی که یک ابزار استقرار (deploy tool) بدون وجود یک PR ادغامشده در شاخه اصلی (main) اجرا شود.
- تشخیص جهشهای ناگهانی در حجم فراخوانیها که با فعالیت انسانی همخوانی ندارد.
برای مثال، یک هشدار فعالشده توسط ابزار استقرار (در حالی که PR ادغامشدهای وجود نداشت)، یکبار باعث شناسایی استقرار کد قدیمی شد؛ جایی که دستورالعملها نسخهای کهنه را ارسال میکردند چون تغییرات هنوز Push نشده بود. یک هشدار روی لاگ حسابرسی یک «مکانیزم» است، اما قول به بررسی لاگها صرفاً یک «آرزو» است.
این رویکرد هفتلایه، رابط دیتابیس و هوش مصنوعی را از مجموعهای شکننده از دستورالعملها به یک دژ مستحکم تبدیل میکند. با جایگزینی اعلامیهها — مانند پرامپتها، فلگها و بررسیهای رشتهای — با اجراهای ساختاری، توسعهدهندگان تضمین میکنند که هیچ اشتباه واحدی نمیتواند منجر به حادثه فاجعهبار از دست رفتن دادهها شود. این چارچوب از طریق بینشهای جمعی جامعه توسعهدهندگان شکل گرفت و خوانندگانی که نمونه بخش چهارم را کالبدشکافی کردند تا هر نقطهای که در آن «حداقلی بودن» با «آمادگی برای تولید» در تضاد بود را شناسایی کنند.
برای کسانی که میخواهند این حفاظتها را به بخش بازیابی حافظه عاملها تعمیم دهند — یعنی سختسازی آنچه یک عامل میتواند از زمینه ذخیرهشده خود بخواند — پروژه متنباز RE-call یک چارچوب تکمیلی مناسب را ارائه میدهد.
گام بعدی شما
- بازبینی تمام Roleهای دیتابیسی که توسط عاملهای AI استفاده میکنند و حذف دسترسیهای DDL.
- پیادهسازی
statement_timeoutدر تمام ارتباطات دیتابیس برای جلوگیری از حملات DoS تصادفی. - جایگزینی دسترسی مستقیم به جداول با Viewهای محدودشده برای کاهش سطح حمله (Attack Surface).




گفتگو