پرش به محتوا
آموزشی

امنیت اپلیکیشن ساخته‌شده با هوش مصنوعی؛ شش کاری که هنوز به عهده‌ی توست

هوش مصنوعی کد را می‌نویسد، اما کسی که کلید را جا می‌گذارد یا بکاپ ندارد، تو هستی.

امنیت اپلیکیشن ساخته‌شده با هوش مصنوعی؛ شش کاری که هنوز به عهده‌ی توست

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

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

کلیدها و توکن‌ها؛ جایی که بیشتر از هر جای دیگری کار خراب می‌شود

دستیار هوش مصنوعی برای اینکه کدش «همین حالا کار کند» گرایش دارد کلید را همان‌جا وسط فایل بنویسد. تا وقتی روی لپ‌تاپ خودت هستی اتفاقی نمی‌افتد؛ ماجرا از لحظه‌ای شروع می‌شود که همان فایل به گیت‌هاب می‌رود یا داخل بیلدِ سمت مرورگر می‌نشیند و هر کسی با یک نگاه به سورس صفحه می‌بیندش.

سه قاعده که استثنا ندارند:

  • هر کلید و رمز در فایل .env می‌نشیند و آن فایل در .gitignore است. مقدارهای واقعی را روی هاست یا پنل سرویس ست کن، نه داخل مخزن.
  • هر متغیری که کد سمت مرورگر آن را می‌خواند، عمومی است. در Next.js پیشوند NEXT_PUBLIC_ یعنی «این را به همه نشان بده». کلیدهایی مثل service_role در Supabase یا کلید مخفی درگاه پرداخت فقط و فقط سمت سرور معنا دارند.
  • کلیدی که یک‌بار کامیت شده، سوخته است. پاک کردنش از فایل کافی نیست چون در تاریخچه‌ی گیت باقی می‌ماند؛ در پنل همان سرویس باطلش کن و کلید تازه بساز.
# .gitignore
.env
.env.local
*.pem

یک‌بار هم مخزن را با ابزاری مثل gitleaks اسکن کن — gitleaks detect --source . — تا اگر کلیدی در تاریخچه جا مانده پیدا شود. روی مخزن‌های عمومی گیت‌هاب، اسکن سکرت‌ها و جلوگیری از پوش‌شدنشان رایگان قابل فعال‌سازی است؛ برای مخزن خصوصی به پلن حساب بستگی دارد، پس رویش حساب باز نکن و خودت اسکن را اجرا کن.

ورود کاربر را از صفر ننویس

احراز هویت بخشی است که «کار می‌کند»ش خیلی زود می‌رسد و «درست کار می‌کند»ش خیلی دیرتر. اگر مدل پیشنهاد داد یک جدول کاربر و یک فرم ورود دست‌ساز بسازد، عقب بکش و سراغ سرویس آماده برو: Supabase Auth، Clerk، Auth.js، یا اگر روی وردپرس کار می‌کنی همان سیستم کاربری خود وردپرس. این‌ها سال‌ها زیر فشار واقعی بوده‌اند و قرار نیست دوباره اختراعشان کنی.

در هر حالت این چند مورد را خودت بررسی کن:

  • نشست کاربر در کوکی با پرچم‌های httpOnly و Secure و SameSite نگه داشته شود، نه در localStorage. توکنی که جاوااسکریپتِ صفحه می‌تواند بخواند، با یک اسکریپت مزاحم هم خوانده می‌شود.
  • اگر واقعاً خودت رمز را ذخیره می‌کنی، فقط هش با bcrypt یا argon2. md5 و sha1 و متن ساده جواب غلط‌اند.
  • تعداد تلاش ورود محدود باشد؛ حتی یک سقف ساده‌ی چند تلاش در دقیقه برای هر آی‌پی بهتر از هیچ است.
  • لینک بازیابی رمز یک‌بارمصرف باشد و عمر کوتاه داشته باشد؛ ۱۵ دقیقه عدد متعارفی است.
  • روی حساب مدیر خودت ورود دومرحله‌ای فعال باشد، حتی اگر برای کاربران عادی چنین چیزی نگذاشته‌ای. حساب تو دروازه‌ی همه‌چیز است.

دسترسی‌ها: فرق «نشان نده» با «اجازه نده»

این شایع‌ترین حفره در کدی است که سریع تولید شده. رابط کاربری دکمه‌ی ویرایش را برای کاربر عادی مخفی می‌کند، ولی خودِ مسیر سمت سرور هر کسی را که آدرس را بداند راه می‌دهد. کاربر فقط کافی است در /api/invoices/1043 عدد را عوض کند تا فاکتور یک نفر دیگر را ببیند.

// unsafe: any id works
const invoice = await db.invoice.findUnique({ where: { id } });

// safe: scoped to the signed-in user
const invoice = await db.invoice.findFirst({
  where: { id, userId: session.user.id },
});

قاعده ساده است: هر جا داده‌ای برگردانده یا تغییر داده می‌شود، شناسه‌ی کاربرِ نشست باید بخشی از شرط باشد — نه چیزی که کلاینت فرستاده. اگر روی Supabase کار می‌کنی، Row Level Security را روشن کن و برای هر جدول سیاست بنویس. فقط حواست باشد این لایه وقتی با کلید کاربر یا anon وصل شوی کار می‌کند؛ درخواستی که با service_role می‌رود از روی همه‌ی سیاست‌ها رد می‌شود و همین است که آن کلید باید پشت سرور بماند.

لایه چه چیزی را تضمین می‌کند اگر فقط همین‌جا چک کنی
رابط کاربری تجربه‌ی تمیز و بدون دکمه‌ی بی‌فایده هر کسی با درخواست مستقیم از کنارش رد می‌شود
سمت سرور (API) واقعاً جلوی درخواست غیرمجاز را می‌گیرد امن است، تا وقتی حتی یک مسیر را جا نینداخته باشی
دیتابیس (RLS) ردیف کاربر دیگر اصلاً برنمی‌گردد محکم‌ترین لایه، ولی نوشتن سیاست‌ها کار توست

پیش از انتشار، کدی را که مدل نوشته بخوان

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

بعد از هر تغییر معنادار، این پرسش‌ها را از خود دستیار بپرس:

  1. فهرست همه‌ی مسیرهای API را بده و مشخص کن کدام‌ها بدون ورود کاربر هم جواب می‌دهند.
  2. در این تغییر کجا داده در دیتابیس نوشته می‌شود و ورودی کاربر پیش از نوشتن چطور اعتبارسنجی شده است؟
  3. اگر کاربر A شناسه‌ی کاربر B را در این درخواست بفرستد چه می‌شود؟ خط کدی را که جلویش را می‌گیرد نشان بده.
  4. کدام متغیرهای محیطی در باندل سمت مرورگر قرار می‌گیرند؟
  5. در این مرحله چه فایل‌هایی تغییر کردند؟ هر فایل را در یک خط توضیح بده.

اگر جواب کلی گرفتی («بله، موارد امنیتی رعایت شده») قبولش نکن و بخواه خط دقیق کد را نشان بدهد. مدل‌ها وقتی کاری را انجام نداده‌اند هم با همان لحن مطمئن حرف می‌زنند. همین عادتِ ساده‌ی «نشانم بده» مرز میان کسی است که با هوش مصنوعی محصول می‌سازد و کسی که فقط خروجی تولید می‌کند؛ در دوره‌ی ساخت سایت با هوش مصنوعی بدون کدنویسی همین حلقه‌ی «بساز، بخوان، منتشر کن» را قدم‌به‌قدم تمرین می‌کنیم.

بکاپ؛ تنها چیزی که بعداً نمی‌شود درستش کرد

تقریباً هر اشتباه دیگری جبران‌شدنی است. یک دستور اشتباه روی دیتابیس، یا هاستی که حسابش تعلیق می‌شود، جبران‌شدنی نیست مگر اینکه از قبل نسخه‌ی پشتیبان داشته باشی. بکاپ سالم سه جزء دارد و هر سه لازم است:

  • خودکار و روزانه. بکاپ دستی یعنی بکاپی که دقیقاً همان هفته‌ی حساس فراموش می‌شود.
  • جایی بیرون از همان سرور. اسنپ‌شاتی که روی خودِ سرور نشسته، دقیقاً در سناریویی که سرور را از دست می‌دهی بی‌فایده است. یک فضای ابری جدا یا حتی دیسک خانه.
  • هم دیتابیس، هم فایل‌های آپلودی. تصویرها و پیوست‌های کاربر معمولاً در بکاپ دیتابیس نیستند.
pg_dump "$DATABASE_URL" | gzip > backup-$(date +%F).sql.gz

روی وردپرس همین کار با mysqldump برای دیتابیس و یک آرشیو از پوشه‌ی wp-content انجام می‌شود. یک کران‌جاب شبانه و نگه‌داشتن ۷ نسخه‌ی روزانه به‌علاوه‌ی ۴ نسخه‌ی هفتگی برای اکثر پروژه‌های کوچک کافی است.

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

آپدیت: چند دقیقه در ماه، نه یک پروژه‌ی جدا

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

  • در پروژه‌های جاوااسکریپتی npm audit را ماهانه بگیر و Dependabot را روی مخزن روشن کن تا خودش پول‌ریکوئست آپدیت بسازد. خروجی audit همیشه فوریت واقعی را نشان نمی‌دهد؛ اول سراغ وابستگی‌های مستقیم و چیزی برو که در مسیر اجرای سرورت هست.
  • در وردپرس، هسته و افزونه‌ها و قالب را به‌روز نگه دار. افزونه یا قالبی که استفاده نمی‌کنی را حذف کن، نه غیرفعال؛ کد غیرفعال هم روی سرور هست.
  • آپدیت‌های بزرگ را اول روی یک محیط آزمایشی امتحان کن، بعد روی نسخه‌ی اصلی. بدون بکاپ هیچ آپدیتی نزن.
  • خطاها را جایی ببین: یک سرویس ثبت خطا مثل Sentry یا دست‌کم لاگ سرور، به‌علاوه‌ی یک مانیتور ساده‌ی در دسترس بودن سایت که اگر پایین آمد به تو خبر بدهد.

ریتم پیشنهادی

  • هفتگی: نگاهی به لاگ خطاها و پیام‌های کاربران؛ مطمئن شو بکاپ دیشب واقعاً ساخته شده.
  • ماهانه: آپدیت وابستگی‌ها و افزونه‌ها، مرور حساب‌های ادمین و حذف دسترسی‌های بلااستفاده.
  • فصلی: یک تست بازگردانی بکاپ و یک دور چرخاندن کلیدهای حساس.

چک‌لیست پیش از انتشار

پیش از اینکه اولین کاربر واقعی وارد شود، این فهرست را یک‌بار از بالا به پایین برو. امنیت اپلیکیشن ساخته‌شده با هوش مصنوعی در عمل یعنی همین چند تیک، نه چیزی پیچیده‌تر:

  1. هیچ کلید و رمزی داخل مخزن نیست و .env در .gitignore است.
  2. کلیدهای حساس فقط سمت سرور استفاده می‌شوند.
  3. ورود کاربر روی یک سرویس شناخته‌شده سوار است و نشست در کوکی امن نگه داشته می‌شود.
  4. هر مسیر API که داده برمی‌گرداند یا تغییر می‌دهد، کاربر نشست را بررسی می‌کند.
  5. ورودی فرم‌ها سمت سرور اعتبارسنجی می‌شود، نه فقط در مرورگر.
  6. آپلود فایل محدود است: نوع مجاز، حجم بیشینه، و اجرانشدن فایل آپلودشده.
  7. سایت روی HTTPS است و گواهی خودکار تمدید می‌شود.
  8. پیام خطای کاربر، جزئیات فنی و مسیر فایل را لو نمی‌دهد.
  9. حساب ادمین رمز یکتا و ورود دومرحله‌ای دارد.
  10. بکاپ خودکار فعال است و یک‌بار تست بازگردانی شده.
  11. یک مانیتور خبر می‌دهد اگر سایت پایین آمد.
  12. می‌دانی اگر همین امشب چیزی خراب شود، دقیقاً چه کاری انجام می‌دهی.

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

محمدرضا حسینی

مهندس نرم‌افزار و مدرس وایب کدینگ. بیش از ۱۰ سال تجربه ساخت محصولات وب، و سه سال تمرکز روی ساخت محصول با ابزارهای هوش مصنوعی. تا امروز بیش از ۴٬۰۰۰ نفر در دوره‌هایش شرکت کرده‌اند.

خواندن ادامه دهید

همه مقاله‌ها

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *