امنیت

امنیت ایجنت‌هایی که کد اجرا می‌کنند

مدل تهدید ایجنت‌هایی که ابزار واقعی در اختیار دارند، و پنج لایه‌ی کنترل — ایزولاسیون، allowlist، کمترین امتیاز، تأیید انسانی و ممیزی — با حد و مرز هرکدام.

· ۱۰ دقیقه مطالعه

مسئله در یک جمله

تا وقتی مدل فقط متن تولید می‌کند، بدترین اتفاق یک جواب غلط است. لحظه‌ای که به مدل ابزار می‌دهید — اجرای کد، خواندن فایل، صدا زدن API داخلی — بدترین اتفاق دیگر جواب غلط نیست؛ یک عمل غلط با اختیارات واقعی است. امنیت ایجنت دقیقاً از همین‌جا شروع می‌شود، و برخلاف تصور رایج، جواب آن «prompt بهتر» نیست.

دلیلش ساده است: مدل بین دستوری که شما نوشته‌اید و متنی که در ورودی‌اش قرار گرفته، مرز سختی نمی‌بیند. اگر ایجنت یک صفحه‌ی وب، یک ایمیل، یک تیکت پشتیبانی یا خروجی یک ابزار را بخواند و در آن متن جمله‌ای باشد که شبیه دستور است، احتمال اجرا شدنش صفر نیست. این همان prompt injection است. با راهنمای بهتر می‌شود احتمالش را کم کرد، اما نمی‌شود آن را به صفر رساند — و طراحی امنیتی نباید روی چیزی بنا شود که احتمالی است.

مدل تهدید را دقیق بنویسید

قبل از انتخاب هر کنترلی، سه سؤال را روی کاغذ جواب دهید:

  1. ایجنت به چه چیزی دسترسی دارد؟ کدام داده، کدام سیستم، با کدام اعتبارنامه.
  2. چه محتوای غیرقابل اعتمادی وارد context او می‌شود؟ هر چیزی که کاربر یا یک سیستم بیرونی تولید کرده باشد: ورودی کاربر، نتیجه‌ی جست‌وجو، محتوای سند، خروجی یک ابزار، پیام یک سرویس دیگر.
  3. از چه راه‌هایی می‌تواند چیزی را بیرون بفرستد؟ درخواست شبکه، ارسال ایمیل، نوشتن در یک منبع مشترک، حتی یک URL در خروجی.

خطر واقعی وقتی جدی می‌شود که هر سه با هم جمع باشند: دسترسی به داده‌ی حساس، مواجهه با محتوای غیرقابل اعتماد، و مسیری برای خروج داده. اگر بتوانید یکی از این سه را در یک workload حذف کنید، سطح حمله به‌شکل معناداری کوچک می‌شود — و این معمولاً ارزان‌تر از هر کنترل دیگری تمام می‌شود. یک ایجنت خلاصه‌ساز که هیچ دسترسی شبکه‌ای ندارد، حتی اگر گول بخورد، جایی برای فرستادن چیزی ندارد.

لایه‌ی اول: ایزوله‌سازی اجرا

اگر ایجنت کد اجرا می‌کند، آن کد باید در محیطی جدا از سرویس شما اجرا شود. سطوح ایزولاسیون یکسان نیستند:

  • جداسازی در سطح فرایند (کاربر جدا، محدودیت منابع). ساده‌ترین سطح. جلوی خطای ساده را می‌گیرد، اما مرز امنیتی محکمی در برابر مهاجم فعال نیست.
  • کانتینر. جداسازی فضای نام و فایل‌سیستم. جلوی دیدن فایل‌های میزبان و آلوده کردن حالت سرویس را می‌گیرد. هسته‌ی سیستم‌عامل همچنان مشترک است.
  • ماشین مجازی یا microVM. مرز قوی‌تر چون هسته هم جداست. هزینه‌ی راه‌اندازی بیشتر است اما برای اجرای کد تولیدشده توسط مدل معمولاً ارزشش را دارد.

مهم‌تر از انتخاب سطح، این سه قاعده است: محیط اجرا یک‌بارمصرف باشد (بعد از هر کار دور انداخته شود، نه بازاستفاده)، بدون اعتبارنامه باشد مگر آن‌که واقعاً لازم باشد، و بدون خروجی شبکه‌ی آزاد.

آخری از همه مهم‌تر و از همه بیشتر فراموش‌شده است. sandbox‌ی که فایل‌سیستم را محدود کرده اما به کد اجازه‌ی درخواست HTTP دلخواه می‌دهد، جلوی خروج داده را نمی‌گیرد. خروج شبکه باید به‌صورت پیش‌فرض بسته باشد و فقط مقصدهای مشخص باز شوند.

چه چیزی را حل نمی‌کند: ایزوله‌سازی جلوی سوءاستفاده از ابزارهایی که خودتان عمداً به ایجنت داده‌اید را نمی‌گیرد. اگر ابزار «ارسال ایمیل» را داده‌اید، sandbox مانع ارسال ایمیل نمی‌شود — چون ارسال ایمیل دقیقاً همان کاری است که مجاز است.

لایه‌ی دوم: allowlist به جای blocklist

هر جا انتخاب دارید، فهرست مجاز بنویسید نه فهرست ممنوع. blocklist یعنی باید همه‌ی راه‌های بد را از قبل حدس زده باشید؛ این بازی را همیشه می‌بازید.

allowlist را باید در چند جا هم‌زمان اعمال کرد:

ابزارها:   فقط ابزارهایی که این workload واقعاً لازم دارد
مقصد شبکه: فقط دامنه‌های مشخص، پیش‌فرض «بسته»
فایل‌سیستم: فقط مسیر کاری، فقط خواندنی جز جایی که لازم است
پارامترها: نوع و دامنه‌ی مقدار هر آرگومان اعتبارسنجی شود

نکته‌ی ظریف در سطح آخر است. کافی نیست ابزار مجاز باشد؛ آرگومان‌هایش هم باید محدود باشند. ابزاری که «کوئری SQL دلخواه» می‌گیرد عملاً یعنی دسترسی کامل به دیتابیس، هرچند اسمش یک ابزار خاص باشد. ابزار خوب دامنه‌ی محدود و پارامترهای نوع‌دار دارد؛ اصول طراحی ابزار را در function calling آورده‌ایم و همین اصول وقتی ابزارها از طریق MCP می‌آیند اهمیت بیشتری پیدا می‌کند، چون ممکن است سرور ابزار را شما ننوشته باشید.

چه چیزی را حل نمی‌کند: allowlist جلوی استفاده‌ی مخرب از ترکیب ابزارهای مجاز را نمی‌گیرد. دو ابزار که هرکدام بی‌خطرند — «خواندن سند داخلی» و «نوشتن در یک صفحه‌ی عمومی» — با هم یک مسیر نشت می‌سازند.

لایه‌ی سوم: کمترین امتیاز برای اعتبارنامه‌ها

قاعده‌ی ساده: ایجنت نباید با هویت و اختیارات یک ادمین کار کند. اعتبارنامه‌ی مخصوص خودش داشته باشد، با محدوده‌ی مشخص، عمر کوتاه، و ترجیحاً محدودشده به همان کاربری که درخواست را شروع کرده.

نکته‌ی مهمی که زیاد نادیده گرفته می‌شود: مجوز نباید از context مدل بیاید. اگر تصمیم «این کاربر اجازه‌ی این کار را دارد یا نه» جایی در prompt گرفته می‌شود، آن تصمیم قابل دستکاری است. مجوز باید در کد، پیش از اجرای ابزار و بر اساس هویت واقعی کاربر بررسی شود. مدل درخواست می‌دهد؛ سیستم شما اجازه می‌دهد یا نمی‌دهد.

همچنین کلیدها نباید داخل محیط اجرای sandbox قرار بگیرند. الگوی درست این است که فراخوانی ابزار به بیرون از sandbox برود، آنجا اعتبارسنجی و اجرا شود و فقط نتیجه برگردد. این‌طور حتی اگر کد اجراشده کاملاً در اختیار مهاجم باشد، کلیدی برای دزدیدن وجود ندارد.

لایه‌ی چهارم: دروازه‌ی تأیید انسانی

بعضی کارها نباید بدون تأیید انجام شوند. معیار انتخابشان دو چیز است: برگشت‌ناپذیری و دیده شدن بیرون از سازمان.

نوع عملحالت پیشنهادی
خواندن، جست‌وجو، خلاصه‌سازیخودکار
نوشتن قابل بازگشت در محیط داخلیخودکار با ثبت کامل
حذف، تغییر پیکربندی، تراکنش مالیتأیید انسانی
ارسال پیام به بیرون سازمانتأیید انسانی

اما دروازه‌ی تأیید فقط وقتی ارزش دارد که آنچه تأیید می‌شود قابل فهم باشد. اگر به کاربر یک JSON خام نشان دهید و او روز پنجاهم بدون خواندن روی «تأیید» بزند، شما امنیت ندارید — یک تشریفات دارید. نمایش باید صریح بگوید چه چیزی، روی کدام منبع، با چه اثری تغییر می‌کند. و اگر ایجنت روزی صد بار تأیید می‌خواهد، طراحی‌اش غلط است؛ دامنه‌ی خودکارش را درست تعریف نکرده‌اید.

چه چیزی را حل نمی‌کند: تأیید انسانی جلوی حملاتی را که در همان دامنه‌ی مجاز و به‌ظاهر بی‌خطر انجام می‌شوند نمی‌گیرد، چون اصلاً به دروازه نمی‌رسند.

لایه‌ی پنجم: ممیزی

فرض کنید یک روز یک اجرای بد اتفاق می‌افتد. سؤال این است: می‌توانید بازسازی‌اش کنید؟ برای این کار باید برای هر اجرا نگه دارید: ورودی کاربر، منشأ هر تکه محتوای بیرونی که وارد context شده، هر فراخوانی ابزار با آرگومان‌هایش، نتیجه، و اینکه چه کسی چه چیزی را تأیید کرده.

ممیزی هیچ حمله‌ای را متوقف نمی‌کند. کاری که می‌کند این است که دامنه‌ی خسارت را قابل تعیین می‌کند و به شما اجازه می‌دهد الگوی حمله را ببندید. بدون آن، بعد از هر حادثه فقط حدس می‌زنید. نگه‌داشتن منشأ محتوا («این پاراگراف از کدام سند آمد») در عمل بیشترین کمک را می‌کند، چون مسیر ورود متن آلوده را نشان می‌دهد.

جمع‌بندی عملی

هیچ‌کدام از این پنج کنترل به‌تنهایی کافی نیست، و هیچ ترکیبی از آن‌ها هم prompt injection را حذف نمی‌کند. کاری که می‌کنند این است که اثر یک تزریق موفق را محدود می‌کنند — و این تنها هدف واقع‌بینانه است.

ترتیب کار برای تیمی که از صفر شروع می‌کند:

  1. فهرست کنید ایجنت به چه چیزی دسترسی دارد و کدام ورودی‌ها غیرقابل اعتمادند.
  2. هر ابزاری را که این workload لازم ندارد بردارید. این ارزان‌ترین کاهش ریسک است.
  3. خروج شبکه را پیش‌فرض ببندید.
  4. اعتبارنامه‌ها را از محیط اجرا بیرون بیاورید و مجوز را در کد بررسی کنید.
  5. عمل‌های برگشت‌ناپذیر را پشت تأیید انسانی بگذارید.
  6. همه چیز را ثبت کنید.

اگر هنوز مطمئن نیستید ایجنت چه کارهایی می‌تواند بکند، به ایجنت هوش مصنوعی چیست برگردید — تعریف دقیق اختیارات، پیش‌نیاز هر تصمیم امنیتی است.

قاعده‌ی سرانگشتی: فرض کنید هر متنی که وارد context ایجنت می‌شود می‌تواند دستور باشد. اگر با این فرض هنوز بدترین کاری که ایجنت می‌تواند انجام دهد قابل تحمل است، طراحی شما درست است.