چگونه یک سیستم آپلود فایل امن طراحی کنیم؟

چند هفته پس از رونمایی سامانه درخواست تسهیلات یک بانک، تیم پشتیبانی گزارش عجیبی میدهد: در انبار فایل کاربران، تصویری پیدا شده که رفتار تصویر ندارد. بررسی دقیقتر نشان میدهد کاربری فایلی با پسوند تصویری بارگذاری کرده که محتوایش اسکریپت اجراشدنی است و سامانه بیسؤال آن را ذخیره و سرو کرده است. این بار خسارتی رخ نداده؛ اما سناریوی بعدی میتوانست متفاوت باشد.
آپلود فایل یکی از خطرناکترین قابلیتهای متداول وب است، دقیقاً به همین دلیل که بیخطر جلوه میکند: کاربر فقط «یک عکس اسکنشده» میفرستد. اما از نگاه مهاجم، نقطهای است که شما داوطلبانه دادهای از بیرون را روی زیرساخت خود میپذیرید و بعداً همان داده را به کاربران دیگر ارائه میکنید.
در این مقاله همین سناریو را تحلیل میکنیم: هر حلقه ضعیف سامانه آپلود را یکییکی باز میکنیم — از اعتبارسنجی نوع و حجم فایل تا نامگذاری، محل ذخیرهسازی و کنترل دسترسی — و در پایان، درسآموختهها را به شکل چکلیست طراحی جمع میکنیم.
تحلیل سناریو؛ حلقههای ضعیف یک آپلود معمولی
حلقه اول؛ اعتماد به پسوند فایل
پسوند (Extension) بخشی از نام فایل است و هر کسی میتواند آن را عوض کند. فایلی که report.jpg نامیده شده ممکن است درونش محتوای اسکریپت داشته باشد؛ پسوند وعده میدهد، اما محتوا را تعیین نمیکند. حتی نوع اعلامشده از سوی مرورگر (Content-Type) هم از همان سمت کاربر میآید و به همان اندازه قابل دستکاری است.
راه معتبرتر، خواندن امضای بایتی فایل (Magic Bytes) است: چند بایت آغازین که ساختار واقعی فایل را لو میدهند. تصمیم پذیرش باید بر پایه فهرست مجاز (Whitelist) محدود و شفاف گرفته شود — فقط انواعی که کسبوکار واقعاً نیاز دارد — نه فهرست ممنوع که همیشه جا میماند. برای تصاویر، بازپردازش فایل (بازخواندن و ذخیره مجدد) هم اعتبارسنجی را محکم میکند و هم دادههای پنهان احتمالی را میریزد.
حلقه دوم؛ حجم و تعداد بیمهار
فایل غولآسا یا آپلودهای پیاپی، چه با قصد خرابکاری و چه از سر بیدقتی، دیسک و پهنای باند را اشغال میکنند و سرویس را برای بقیه کاربران تنگ میکنند. محدودیت حجم باید همزمان در چند لایه اعمال شود: در سمت کاربری پیش از ارسال، در سرویس پذیرش و در زیرساخت. کنار آن، سقفی برای تعداد و نرخ آپلود هر کاربر بگذارید تا انباشت تدریجی هم دیده شود.
حلقه سوم؛ نام فایلی که کاربر میفرستد
نام فایل کاربر داده تمیزی نیست: ممکن است کاراکترهای خاص، مسیرهای نسبی یا نامهای تکراری داشته باشد. اگر نام کاربر مستقیم در مسیر ذخیرهسازی به کار رود، مهاجم میتواند با دستکاری نام، امید به نوشتن در جای دیگری از سیستم ببندد؛ تکنیکی که با نام پیمایش مسیر (Path Traversal) شناخته میشود.
قاعده ساده است: نام کاربر را فقط بهعنوان یک رشته نمایشی نگه دارید؛ نام واقعی فایل روی دیسک را خودتان بسازید — شناسهای یکتا و تصادفی. تعارض نامها هم از همینجا ریشه میگیرد و با همین تصمیم حل میشود.
حلقه چهارم؛ محل ذخیرهسازی و اجرا
محل نگهداری فایلها نباید جایی باشد که سرور محتوایش را اجرا میکند؛ فایلی که در پوشهای ذخیره شود که محتوایش بهعنوان کد تفسیر میشود، بمب ساعتی است. فایلها را خارج از ریشه وب یا بهتر از آن، در فضای ذخیرهسازی شیءگرا (Object Storage) نگه دارید و از دامنه جداگانهای سرو کنید تا دسترسیها و نشستهای سایت اصلی در معرض آنها نباشد.
پیش از پذیرش نهایی، عبور فایل از اسکن ضدبدافزار و ثبت نتیجه اسکن در کنار فایل، لایه دیگری است که هزینه کمی دارد و در روز حادثه تفاوت را میسازد.
حلقه پنجم؛ چه کسی به چه فایلی دسترسی دارد؟
در سامانه تسهیلات، مدارک هر متقاضی باید فقط برای همان متقاضی و کارشناس مجاز دیده شود. آدرسهایی که با الگو ساخته میشوند — شناسه ترتیبی مانند شماره پرونده — قابل حدساند؛ کافی است یکی را تغییر دهید تا فایل دیگری باز شود. کنترل دسترسی باید در هر درخواست دانلود دوباره بررسی شود، نه فقط هنگام آپلود.
راهکار رایج، لینک امضاشده با انقضا (Signed URL) است: آدرسی کوتاهعمر که فقط برای کاربر مجاز و برای مدت محدود تولید میشود. با این حال بررسی مجوز هنگام تولید لینک را فراموش نکنید؛ لینک امضاشده جایگزین تصمیم دسترسی نیست، حامل آن است.
| تهدید | نشانه در سناریو | لایه دفاعی |
|---|---|---|
| فایل مخرب با پسوند جعلی | اسکریپت با نام تصویر | امضای بایتی، فهرست مجاز، بازپردازش، اسکن |
| فایل غیرمتعارف حجیم | اشغال دیسک و کندی سرویس | سقف حجم در چند لایه و سقف نرخ آپلود |
| دستکاری نام فایل | نوشتن خارج از مسیر مجاز | نامگذاری تصادفی سمت سرور و جداسازی مسیرها |
| حدسزدن فایل دیگران | تغییر شناسه در آدرس دانلود | کنترل دسترسی در هر درخواست و لینک امضاشده |
| اشباع با آپلود انبوه | پرشدن فضای ذخیرهسازی | محدودیت نرخ و پایش حجم هر کاربر |
درسآموخته؛ دفاع لایهای بهجای یک گیت امنیتی
حادثه فرضی ما از یک نکته عبور میکند: هیچ بررسی تکیای کافی نیست. پذیرش فایل باید مانند گذر از چند ایست بازرسی طراحی شود؛ اگر مهاجم از پسوند رد شد، به امضای بایتی بخورد؛ از آن رد شد، به اسکن و بازپردازش؛ و حتی اگر فایلی ذخیره شد، نه اجرا شود و نه به دیگران نرسد. به این نگرش، دفاع لایهای (Defense in Depth) میگویند.
درس دوم این است که همه دادههای ورودی کاربر — نام، نوع اعلامشده، محتوا و حتی حجم — باید نامعتبر فرض شوند تا اثبات خلاف. درس سوم: چنین سناریوهایی را باید پیش از حادثه تمرین کرد؛ تیمی که آپلود را فقط با فایلهای تمیز میآزماید، در برابر فایلهای عمداً بدشکل کور است.
خطاهای رایج در پیادهسازی
- اعتماد به نوع اعلامشده مرورگر بهجای بررسی خودِ محتوا.
- ذخیرهسازی فایلها در مسیر قابلاجرا یا در همان دامنه سایت اصلی.
- سرو کردن فایل کاربران با آدرس قابل حدس و بدون بررسی مجوز.
- پیام خطای مبهم برای فایل ردشده که کاربر را به امتحانهای پیاپی وادار میکند؛ رد شدن باید دلیل روشن داشته باشد.
- فراموشکردن پایش: بدون ثبت گزارش آپلودها، حمله تدریجی دیر دیده میشود.
کاربرد عملی؛ چکلیست طراحی سامانه آپلود
- فهرست مجاز انواع فایل را بر اساس نیاز واقعی کسبوکار ببندید و آن را با امضای بایتی بررسی کنید.
- سقف حجم و نرخ آپلود را در سمت کاربر، سرویس و زیرساخت تعریف کنید.
- نام فایل سمت سرور را تصادفی و یکتا بسازید؛ نام کاربر فقط متادیتای نمایشی است.
- فایلها را خارج از مسیر اجرا یا در فضای شیءگرا ذخیره و از دامنه جداگانه سرو کنید.
- اسکن ضدبدافزار و بازپردازش تصاویر را پیش از پذیرش نهایی اجرا کنید.
- برای هر دانلود، مجوز را دوباره بسنجید و دسترسی را با لینک امضاشده و کوتاهعمر بدهید.
- آپلود و دانلودها را ثبت و پایش کنید تا رفتار غیرعادی زود دیده شود.
نکات کلیدی این مقاله
- آپلود فایل یعنی پذیرش داوطلبانه داده بیرونی؛ از پسوند، نوع اعلامشده و نام فایل هرگز اعتماد نکنید.
- اعتبارسنجی نوع با امضای بایتی و فهرست مجاز انجام میشود، نه با پسوند و نوع مرورگر.
- محل ذخیرهسازی باید غیرقابلاجرا و از دامنه اصلی جدا باشد و دسترسی با لینک امضاشده کنترل شود.
- سقف حجم و نرخ، همزمان در چند لایه اعمال شود؛ یک گیت تنها کافی نیست.
- موفقیت آپلود امن در دفاع لایهای است: اگر یک لایه رد شد، لایه بعدی باید بایستد.
سوالات متداول
اگر فقط تصویر میپذیریم، آیا باز هم خطر جدی وجود دارد؟
بله؛ تصویر هم میتواند داده پنهان یا محتوای مخرب داشته باشد و تشخیص «این یک تصویر است» با امضای بایتی انجام میشود نه با پسوند. بازپردازش تصویر و حذف دادههای جانبی را بخشی از مسیر پذیرش کنید.
فایلها را در پایگاه داده ذخیره کنیم یا روی دیسک و فضای ابری؟
پایگاه داده کنترل و پشتیبانگیری سادهتری میدهد اما برای فایلهای حجیم کارآمد نیست؛ ذخیره روی دیسک یا فضای شیءگرا رایجتر است، به شرط آنکه مسیر غیرقابلاجرا باشد و مجوزها در هر دانلود بررسی شود. تصمیم باید بر اساس حجم، الگوی دسترسی و نیاز پشتیبانگیری شما گرفته شود.
سقف حجم مناسب برای فایلها چقدر باشد؟
از نیاز واقعی کسبوکار شروع کنید، نه از عدد پیشفرض؛ مثلاً برای اسکن مدارک در سامانه فرضی ما چند ده مگابایت کفایت میکند و سقف بزرگتر فقط ریسک میخرد. مهم این است که سقف در چند لایه و با پیام خطای روشن اعمال شود.



