নিরাপদ ফাইল আপলোড: অনুমতি, সীমা, সাইন করা URL, স্ক্যানিং
ওয়েব অ্যাপে নিরাপদ ফাইল আপলোডের জন্য কঠোর অনুমতি, সাইজ সীমা, সাইন করা URL ও মৌলিক ম্যালওয়্যার স্ক্যানিং প্যাটার্ন দরকার যাতে ইনসিডেন্ট এড়ানো যায়।

কেন ফাইল আপলোড ঝুঁকিপূর্ণ (সরল ভাষায়)
ফাইল আপলোড বেশ নিরদোষ দেখায়: একজনের প্রোফাইল ছবি, একটা PDF, একটি স্প্রেডশীট। কিন্তু এগুলো প্রায়ই প্রথম সিকিউরিটি ইনসিডেন্টের কারণ হয়ে থাকে, কারণ এতগুলো অচেনা লোক আপনার সিস্টেমে একটি ‘রহস্য বাক্স’ পাঠাতে পারে। আপনি এটাকে গ্রহণ করলে, সংরক্ষণ করলে এবং অন্যদের সামনে দেখালে, আপনি আপনার অ্যাপে আক্রমণের নতুন পথ খুলে দিয়েছেন।
ঝুঁকি কেবল “কেউ ভাইরাস আপলোড করেছে”—এটাই নয়। একটি খারাপ আপলোড গোপন ফাইল ফাঁস করতে পারে, আপনার স্টোরেজ বিলকে ভেঙে দিতে পারে, বা ব্যবহারকারীদেরকে প্রবেশাধিকার হস্তান্তর করার ফাঁদে ফেলতে পারে। একটি নেরবে রাখা নাম “invoice.pdf” আসলেই PDF নাও হতে পারে। এমনকি বাস্তব PDF ও ইমেজও সমস্যা করতে পারে যদি আপনার অ্যাপ মেটাডেটায় বিশ্বাস করে, স্বয়ংক্রিয়ভাবে প্রিভিউ করে, বা ভুল নিয়মে সার্ভ করে।
বাস্তব ব্যর্থতা সাধারণত এমনভাবে দেখা যায়:
- কেউ একটি ফাইল URL অনুমান করে অন্য ব্যবহারকারীর ডকুমেন্ট ডাউনলোড করে।
- একটি আপলোডকৃত HTML ফাইল ওয়েব পেজের মতো সার্ভ হয়ে লগইন চুরি করার প্রম্পট দেখায়।
- একজন আক্রমণকারী বারবার বিরাট ফাইল আপলোড করে আপনার অ্যাপকে ধীর বা ক্র্যাশ করতে পারে।
- একটি “নিরাপদ” ফাইল টাইপ নকল করা হয় এবং স্টাফরা ইন্টারনাল মেশিনে এটি খুলে ফায়দা পায়।
একটি গুরুত্বপূর্ণ বিষয় অনেক ঘটনার জন্য তাত্পর্যপূর্ণ: ফাইল সংরক্ষণ করা মানে ফাইল সার্ভ করা নয়। স্টোরেজ হল যেখানে বাইট রাখা হয়। সার্ভ করা হল কিভাবে সেই বাইট ব্রাউজার ও অ্যাপে সরবরাহ করা হয়। সমস্যা তখনই হয় যখন কোনো অ্যাপ ইউজার আপলোডকে একই বিশ্বাস স্তর ও নিয়মে সার্ভ করে যেটা মূল ওয়েবসাইটে আছে, ফলে ব্রাউজার সেই আপলোডকে “ট্রাস্টেড” মনে করে।
ছোট বা বাড়তে থাকা অ্যাপের জন্য “পর্যাপ্ত নিরাপত্তা” সাধারণত চারটি প্রশ্নের পরিষ্কার উত্তর দেয়ার মতো: কে আপলোড করতে পারে, আপনি কী গ্রহণ করেন, কত বড় ও কত ঘন ঘন, এবং পরে কে এটি পড়তে পারে। দ্রুত তৈরি করলেও (জেনারেটেড কোড বা চ্যাট-চালিত প্ল্যাটফর্ম), এসব গার্ডরেলগুলো গুরুত্বপূর্ণ।
আপলোডের জন্য একটি সহজ থ্রেট মডেল
প্রতিটি আপলোডকে অনবিশ্বাসী ইনপুট হিসেবে বিবেচনা করুন। আপলোডগুলো নিরাপদ রাখার ব্যবহারিক উপায় হল ভাবা—কে এগুলোকে দুর্ব্যবহার করতে পারে এবং তাদের “সফলতা” কিরকম দেখায়।
অনেক আক্রমণকারী হয় বট যা দুর্বল আপলোড ফর্ম খোঁজে, বা রিয়েল ব্যবহারকারী যারা লিমিট টেস্ট করে ফ্রি স্টোরেজ পেতে, ডেটা স্ক্র্যাপ করতে বা সার্ভিসকে টরল করতে চেষ্টা করে। মাঝে মাঝে প্রতিদ্বন্দ্বী কেও থাকেন লিক বা আউটেজ খোঁজার জন্য।
তারা সাধারণত কি চায়? এগুলোর মধ্যে সাধারণত একটিঃ
- আপনার সার্ভারে কোড চালানো—কিছু আপলোড করে যা এক্সিকিউট হয়।
- ডাউনলোড URL অনুমান, পুনরায় ব্যবহার বা শেয়ার করে গোপন ফাইল চুরি করা।
- আপলোড ফ্লাড করে বা ব্যয়বহুল প্রসেসিং করিয়ে অস্তিত্বহীন করা (availability)।
- স্টোরেজ বা ব্যান্ডউইথ ব্যবহার বাড়িয়ে আপনার বিল ফুলানোর চেষ্টা।
তারপর দুর্বল স্থলগুলো ম্যাপ করুন। আপলোড এন্ডপয়েন্ট হলো সামনের দরজা (অতিরিক্ত আকার, অদ্ভুত ফরম্যাট, উচ্চ রিকোয়েস্ট রেট)। স্টোরেজ হলো পিছনের রুম (পাবলিক বালতি, ভুল অনুমতিসমূহ, শেয়ার্ড ফোল্ডার)। ডাউনলোড URL হলো এক্সিট (পূর্বানুমানযোগ্য, দীর্ঘজীবী, বা ব্যবহারকারীর সাথে না বেঁধে থাকা)।
উদাহরণ: “রিজিউম আপলোড” ফিচার। একটি বট হাজার হাজার বড় PDF আপলোড করে খরচ বাড়ায়, আর একটি বেয়াদবি ব্যবহারকারী একটি HTML ফাইল আপলোড করে সেটিকে “ডকুমেন্ট” হিসাবে শেয়ার করে অন্যদের ঠকাতে পারে।
নিয়ন্ত্রণ যোগ করার আগে সিদ্ধান্ত নিন আপনার অ্যাপের জন্য কি বেশি গুরুত্বপূর্ণ: গোপনীয়তা (কে পড়তে পারে), উপলব্ধতা (আপনি সার্ভ রাখতে পারবেন কি), খরচ (স্টোরেজ ও ব্যান্ডউইথ), এবং কমপ্লায়েন্স (ডেটা কোথায় রাখা হচ্ছে ও কতদিন রাখা হবে)। সেই অগ্রাধিকার তালিকা সিদ্ধান্তকে ধারাবাহিক রাখে।
বাস্তবে টিকে থাকা অনুমতি এবং এক্সেস কন্ট্রোল
বেশিরভাগ আপলোড ইনসিডেন্ট জটিল হ্যাক নয়—এগুলো সাধারণ “আমি অন্য কারোর ফাইল দেখতে পারি” বাগ। আপলোডকে ফিচারের একটা অংশ হিসেবে দেখুন, পরে লাগানোর মতো কিছু হিসেবে নয়।
একটি নিয়ম দিয়ে শুরু করুন: ডিফল্ট ডিনাই। প্রতিটি আপলোডকৃত অবজেক্টকে ব্যক্তিগত ধরে নিন যতক্ষণ না আপনি স্পষ্টভাবে অ্যাক্সেস অনুমোদন করেন। “ডিফল্টে ব্যক্তিগত” হলো শক্তিশালী বেসলাইন—ইনভয়েস, মেডিকেল ফাইল, অ্যাকাউন্ট ডকুমেন্ট বা কোনোই ব্যবহারকারীর সঙ্গে যুক্ত জিনিসের জন্য। ব্যবহারকারী স্পষ্টভাবে পাবলিক প্রত্যাশা করলে (যেমন পাবলিক অবতার) কেবল তখনই ফাইল পাবলিক করুন, এবং এমন ক্ষেত্ৰে-ও সময়-সীমাবদ্ধ অ্যাক্সেস বিবেচনা করুন।
কাজের সাথে ম্যাচ করা রোলস
রোলগুলো সোজা ও আলাদা রাখুন। একটি প্রচলিত বিভাজন:
- Uploader: তাদের নিজের অ্যাকাউন্টের জন্য আপলোড তৈরি করতে পারে
- Viewer: তারা যে ফাইলগুলো দেখতে পারবে সেগুলো ডাউনলোড করতে পারে
- Support: অডিটেবল, সাময়িক গ্রান্ট দিয়ে ফাইল অ্যাক্সেস পায়
- Admin: নীতি ব্যবস্থাপনায় সক্ষম, কিন্তু স্বয়ংক্রিয়ভাবে সব কিছু পড়া উচিত নয়
ফোল্ডার-লেভেল নিয়ম যেমন “/user-uploads/ এর সব কিছু ঠিক আছে” এ ধরনের ওপর নির্ভর করবেন না। প্রতিটি ফাইল পড়ার সময় মালিকানা বা টেন্যান্সি চেক করুন। কেউ দল পরিবর্তন করলে, সংস্থা ছেড়ে গেলে বা ফাইল পুনরায় নিয়োগ হলে এটা আপনাকে রক্ষা করবে।
একটি ভাল সাপোর্ট প্যাটার্ন হলো সংকীর্ণ ও অস্থায়ী: একটি নির্দিষ্ট ফাইলের জন্য অ্যাক্সেস দিন, লগ রাখুন এবং স্বয়ংক্রিয়ভাবে মেয়াদ শেষ করে দিন।
বিশ্বাস না করে ফাইল টাইপ যাচাই করা
বেশিরভাগ আপলোড আক্রমণ একটি সহজ কৌশল দিয়ে শুরু হয়: একটি ফাইল নাম বা ব্রাউজার হেডার দেখে নিরাপদ মনে হয়, কিন্তু আসলে তা অন্য কিছু। ক্লায়েন্ট যা পাঠায় সবকিছুই অনবিশ্বাসী ধরণে নিন।
একটি allowlist দিয়ে শুরু করুন: আপনি সঠিকভাবে কোন ফরম্যাটগুলো গ্রহণ করবেন তা নির্ধারণ করুন (উদাহরণ: .jpg, .png, .pdf) এবং অন্য সবকিছু প্রত্যাখ্যান করুন। “যে কোনো ইমেজ” বা “যে কোনো ডকুমেন্ট” এড়িয়ে চলুন যদি না সত্যিই দরকার হয়।
ফাইলের এক্সটেনশন বা ক্লায়েন্টের Content-Type হেডারের উপর বিশ্বাস করবেন না। দুটিই সহজেই নকল করা যায়। invoice.pdf নামের ফাইলও executable হতে পারে, এবং Content-Type: image/png মিথ্যা হতে পারে।
একটি শক্তিশালী পদ্ধতি হলো ফাইলের প্রথম বাইটগুলো পরীক্ষা করা, যাকে সাধারণত “magic bytes” বা ফাইল সিগনেচার বলা হয়। অনেক কমন ফরম্যাটের নির্দিষ্ট হেডার থাকে (যেমন PNG ও JPEG)। হেডার অনুমোদিত না হলে প্রত্যাখ্যান করুন।
একটি ব্যবহারিক ভ্যালিডেশন সেটআপ:
- সার্ভার-সাইডে যে এক্সটেনশনগুলো গ্রহণ করবেন সেগুলোর allowlist রাখুন
- MIME টাইপ সার্ভার-সাইডে শনাক্ত করুন (ক্লায়েন্ট হেডার নয়)
- সমর্থিত ফরম্যাটগুলোর জন্য magic bytes স্নিফ করুন
- স্টোরেজে একটা নতুন র্যান্ডম নাম জেনারেট করুন এবং আসল নামকে মেটাডেটা হিসেবে রাখুন
- রিস্কি ফরম্যাট ব্লক করুন যদি সত্যিই প্রয়োজন না থাকে, বিশেষ করে HTML, SVG এবং স্ক্রিপ্ট-রকম কন্টেন্ট
নাম পরিবর্তন ভাবনার চেয়েও বেশি গুরুত্বপূর্ণ। যদি আপনি ইউজার-প্রদানকৃত নামগুলো সরাসরি সংরক্ষণ করেন, আপনি পথ-চিট, অদ্ভুত ক্যারেক্টার এবং অনিচ্ছাকৃত ওভাররাইটিং আমন্ত্রণ জানাবেন। সংরক্ষণে একটি জেনারেটেড আইডি ব্যবহার করুন এবং মূল ফাইলনাম শুধুমাত্র প্রদর্শনের জন্য রাখুন।
প্রোফাইল ছবির জন্য শুধুমাত্র JPEG ও PNG গ্রহণ করুন, হেডার যাচাই করুন, এবং সম্ভব হলে মেটাডেটা সরিয়ে দিন। ডকুমেন্টের জন্য PDF-এ সীমাবদ্ধ রাখুন এবং সক্রিয় কন্টেন্ট থাকা কিছু প্রত্যাখ্যান করুন। ভবিষ্যতে যদি SVG বা HTML দরকার হয়, সেগুলোকে সম্ভাব্য এক্সিকিউটেবল ধরে আলাদা আইসোলেশনে রাখুন।
সাইজ সীমা, রেট লিমিট ও DoS মৌলিক বিষয়
বেশিরভাগ আপলোড আউটেজ জটিল হ্যাক নয়। এগুলো বড় ফাইল, অনেক অনুরোধ, বা ধীর সংযোগের কারণেই সার্ভারগুলো ব্যস্ত হয়ে পড়ে যতক্ষণ না অ্যাপ ধীর বা ডাউন হয়ে যায়। প্রতিটি বাইটকে খরচ মনে করুন।
এমন সাইজ সীমা সেট করুন যা বাস্তবে কাজ করে
প্রতিটি ফিচারের জন্য সর্বোচ্চ সাইজ পছন্দ করুন, একটি একগ্লোবাল সংখ্যার পরিবর্তে। একটি অবতার একই লিমিট চাইবে না যেটা একটি কর ডকুমেন্ট বা ছোট ভিডিও দরকার। সবচেয়ে ছোট লিমিট সেট করুন যা এখনও স্বাভাবিক লাগে, তারপর আলাদা “বড় আপলোড” প ath যোগ করুন যখন সত্যিই প্রয়োজন।
ক্লায়েন্ট মিথ্যা বলতে পারে বলে একাধিক স্থানে লিমিট গুরুতর রাখুন: অ্যাপ লজিকে, ওয়েব সার্ভার বা রিভার্স প্রোক্সিতে, আপলোড টাইমআউটে, এবং ঘোষণা করা সাইজ বড় হলে শরীর পড়ার আগে তৎক্ষণাৎ প্রত্যাখ্যান করে দিন।
কংক্রিট উদাহরণ: অবতার 2 MB-এ ক্যাপ, PDF 20 MB-এ ক্যাপ, এবং এর চেয়েও বড় হলে আলাদা ফ্লো লাগবে (যেমন সরাসরি অবজেক্ট স্টোরেজে সাইন করা URL)।
রেট লিমিট ও দুর্ব্যবহার কন্ট্রোল
ছোট ফাইলগুলোও লুপে আপলোড হলে DoS হতে পারে। আপলোড এন্ডপয়েন্টে রেট লিমিট যোগ করুন—প্রতি ইউজার ও প্রতি IP হিসেবে। অননুমোদিত ট্রাফিকের জন্য কঠোর লিমিট বিবেচনা করুন।
রিজিউমেবল আপলোড বাস্তব ব্যবহারকারীদের জন্য সহায়ক, কিন্তু সেশন টোকেনটিকে শক্ত রাখতে হবে: সংক্ষিপ্ত মেয়াদ, ব্যবহারকারীর সাথে বাঁধা এবং নির্দিষ্ট ফাইল সাইজ ও গন্তব্যের সাথে বেঁধে দিন। নাহলে “resume” এন্ডপয়েন্ট হয়ে যাবে স্টোরেজে ফ্রি পাইপ।
আপনি যখন কোনো আপলোড ব্লক করেন, ব্যবহারকারীর জন্য পরিষ্কার ত্রুটি দেখান (ফাইল খুব বড়, অনেক অনুরোধ), কিন্তু ভেতরের তথ্য লিক করবেন না (স্ট্যাক ট্রেস, বালতি নাম, ভেন্ডর ডিটেইল)।
নিরাপদ স্টোরেজ ও ডেলিভারি পছন্দসমূহ
নিরাপদ আপলোড শুধুই কি গ্রহণ করছেন তা নয়—এটা ফাইল কোথায় যায় এবং পরে কিভাবে ফিরিয়ে দেওয়া হয় তাতেও গুরুত্বপূর্ণ।
আপলোড বাইটগুলোকে আপনার মেইন ডাটাবেস থেকে দূরে রাখুন। বেশিরভাগ অ্যাপ metadata-ই DB-তে রাখে (owner user ID, original filename, detected type, size, checksum, storage key, created time)। বাইটি-গুলো অবজেক্ট স্টোরেজ বা বড় ব্লবের জন্য ডিজাইন করা ফাইল সার্ভিসে রাখুন।
স্টোরেজ লেভেলে পাবলিক ও প্রাইভেট ফাইল আলাদা রাখুন। বিভিন্ন বালতি বা কন্টেইনার ব্যবহার করুন ভিন্ন নিয়ম নিয়ে। পাবলিক ফাইল (যেমন পাবলিক অবতার) লগইন ছাড়াই পড়া যেতে পারে। প্রাইভেট ফাইল (চুক্তি, ইনভয়েস, মেডিকেল ডকস) কখনই পাবলিক-রিডেবল হওয়া উচিত না, এমনকি কেউ URL অনুমান করলেও।
যতটা সম্ভব আপনার মেইন ডোমেন থেকে ব্যবহারকারীর ফাইল সার্ভ করা এড়িয়ে চলুন। যদি একটি ঝুঁকিপূর্ণ ফাইল স্লিপ করে (HTML, SVG-এ স্ক্রিপ্ট বা ব্রাউজারের MIME স্নিফিং সমস্যা), মেইন ডোমেনে হোস্ট করলে এটি অ্যাকাউন্ট টেকওভার এ পরিণত হতে পারে। একটি ডেডিকেটেড ডাউনলোড ডোমেইন (বা স্টোরেজ ডোমেইন) ব্লাস্ট রেডিয়াস সীমিত করে।
ডাউনলোডে নিরাপদ হেডার বাধ্য করুন। আপনি যা অনুমোদন করেন সেটার উপর ভিত্তি করে Content-Type সেট করুন, ব্যবহারকারীর দাবি নয়। যে কোনো কিছু ব্রাউজার দ্বারা ব্যাখ্যা করা যেতে পারে এমন হলে ডাউনলোড হিসেবে পাঠানোই বাঞ্ছনীয়।
কিছু ডিফল্ট যা বিস্ময় রোধ করে:
- ডকুমেন্টের জন্য
Content-Disposition: attachmentব্যবহার করুন - সেফ
Content-Typeব্যবহার করুন (বাapplication/octet-stream) - অদৃশ্য অবজেক্ট কীগুলো (opaque object keys) ব্যবহার করুন—ইউজার ফাইলনেম নয়
- প্রাইভেট ফাইলের ডাউনলোড লগ করুন
রিটেনশনও সিকিউরিটি—পরিত্যক্ত আপলোড মুছুন, পুরোনো ভার্সন রিমুভ করুন, অস্থায়ী ফাইলের সময়সীমা সেট করুন। কম ডেটা সংরক্ষণ মানে কম লিক হওয়ার ঝুঁকি।
সাইন করা URL: কখন ব্যবহার করবেন ও কিভাবে টাইট রাখবেন
Signed URLs (প্রেসাইনড URL) খুবই সাধারণ উপায় যাতে ব্যবহারকারীরা স্টোরেজ বালতি পাবলিক না করে এবং প্রতিটি বাইট আপনার API দিয়ে না পাঠিয়ে আপলোড/ডাউনলোড করতে পারে। URL-টি সাময়িক অনুমতি বহন করে, তারপর মেয়াদ শেষ হয়ে যায়।
দুই সাধারণ ফ্লো:
- Direct-to-storage upload: আপনার অ্যাপ একটি স্বল্প-জীবী signed URL ইস্যু করে এবং ব্রাউজার সরাসরি অবজেক্ট স্টোরেজে আপলোড করে।
- Upload-through-server: ফাইল প্রথমে আপনার API-তে পড়ে, তারপর আপনার সার্ভার এটি সংরক্ষণ করে।
Direct-to-storage API লোড কমায়, কিন্তু স্টোরেজ নীতিমালা ও URL কনে constraints আরও গুরুত্বপূর্ণ করে তোলে।
কিভাবে signed URL টাইট রাখবেন
একটি signed URL-কে ওয়ান-টাইম কী হিসেবে ভাবুন। এটিকে নির্দিষ্ট ও স্বল্প-জীবী রাখুন।
- লিখন (write) URL দ্রুত মেয়াদ শেষ করুন (প্রায়ই 1–5 মিনিট)
- পড়ার (read) URL মিটস-মিনিটে রাখুন, দিন নয়
- URL-কে প্রত্যাশিত অবজেক্ট কীর সাথে বেঁধে দিন (একটি অবজেক্ট, ফোল্ডার নয়)
- যেখানে সমর্থিত, অতিরিক্ত কনস্ট্রেইন্ট দিন: প্রত্যাশিত কনটেন্ট টাইপ, ম্যাক্স সাইজ, চেকসম
- পারমিশন চেকের পরে মাত্র URL ইস্যু করুন
- কে URL অনুরোধ করেছে সেটি লগ করুন (user ID, object key, উদ্দেশ্য, IP/user agent)
একটি ব্যবহারিক প্যাটার্ন: প্রথমে একটি আপলোড রেকর্ড তৈরি করুন (status: pending), তারপর signed URL ইস্যু করুন। আপলোড হয়ে গেলেই নিশ্চিত করুন অবজেক্টটি আছে এবং প্রত্যাশিত সাইজ ও টাইপ মেলে তারপর status ready করুন।
ধাপে ধাপে: একটি নিরাপদ আপলোড ফ্লো যা আপনি বাস্তবায়ন করতে পারেন
একটি নিরাপদ আপলোড ফ্লো মূলত স্পষ্ট নিয়ম ও স্পষ্ট স্টেট। প্রতিটি আপলোডকে যাচাই না হওয়া পর্যন্ত অনবিশ্বাসী ধরুন।
লিখে রাখুন প্রতিটি ফিচার কি অনুমোদন করে। প্রোফাইল ছবি ও ট্যাক্স ডকুমেন্ট একই ফাইল টাইপ, সাইজ লিমিট বা ভিজিবিলিটি শেয়ার করা চলবে না।
একটি ব্যবহারিক ফ্লো (বাস্তব স্ট্যাটাসসহ)
-
অনুমোদিত টাইপ ও প্রতিটি ফিচারের জন্য সাইজ লিমিট নির্ধারণ করুন (উদাহরণ: ফটো 5 MB পর্যন্ত; PDF 20 MB পর্যন্ত)। ব্যাকএন্ডে একই নিয়ম জোরদার করুন।
-
বাইট আসার আগে একটি “upload record” তৈরি করুন। স্টোর করুন: owner (user বা org), purpose (avatar, invoice, attachment), original filename, expected max size, এবং একটি স্ট্যাটাস যেমন
pending। -
একটি প্রাইভেট লোকেশনে আপলোড করুন। ক্লায়েন্টকে চূড়ান্ত পথ বাছাই করতে দেবেন না।
-
সার্ভার-সাইডে আবার ভ্যালিডেট করুন: সাইজ, magic bytes/type, allowlist। যদি পাশ করে, তাহলে status পরিবর্তন করে
uploadedকরুন। -
ম্যালওয়্যার স্ক্যান করুন এবং status
cleanবাquarantinedআপডেট করুন। যদি স্ক্যান অ্যাসিঙ্ক্রোনাস হয়, তখন পর্যন্ত অ্যাক্সেস লক করে রাখুন। -
শুধু তখনই ডাউনলোড, প্রিভিউ বা প্রসেসিং অনুমতি দিন যখন status
clean।
ছোট উদাহরণ: প্রোফাইল ছবির জন্য, ব্যবহারকারীর সাথে টাইটভাবে টাই করা একটি রেকর্ড তৈরি করুন purpose avatar দিয়ে, প্রাইভেটভাবে সংরক্ষণ করুন, নিশ্চিত করুন এটি আসলেই JPEG/PNG (শুধু নাম নয়), স্ক্যান চালান, তারপর প্রিভিউ URL জেনারেট করুন।
মৌলিক ম্যালওয়্যার স্ক্যান প্যাটার্ন (অতিম্ভাবনা না করে)
ম্যালওয়্যার স্ক্যানিং একটি সেফ্টি নেট—প্রতিশ্রুতি নয়। এটা পরিচিত খারাপ ফাইল ও স্পষ্ট কৌশলগুলো ধরা দেয়, কিন্তু সব কিছু ধরে ফেলবে না। লক্ষ্য হচ্ছে ঝুঁকি কমানো এবং অজানা ফাইলগুলোকে ডিফল্টে ক্ষতিকর না করে রাখা।
একটি নির্ভরযোগ্য প্যাটার্ন হলো আগে কোয়ারেন্টাইন করা। প্রতিটি নতুন আপলোডকে একটি প্রাইভেট, নন-পাবলিক লোকেশনে সংরক্ষণ করুন এবং সেটাকে pending হিসেবে মার্ক করুন। সব চেক পাস করার পরেই তাকে “clean” লোকেশনে সরান বা উপলব্ধ করে দিন।
সিঙ্ক্রোনাস স্ক্যান শুধুমাত্র ছোট ফাইল ও কম ট্র্যাফিকের জন্য কাজ করে কারণ ব্যবহারকারী অপেক্ষা করে। বেশিরভাগ অ্যাপ অ্যাসিঙ্ক্রোনাস স্ক্যান ব্যবহার করে: আপলোড গ্রহণ করুন, “processing” স্টেট ফেরত দিন, ব্যাকগ্রাউন্ডে স্ক্যান করুন।
“বেসিক স্ক্যানিং”-এ কি থাকে
বেসিক স্ক্যানিং সাধারণত একটি অ্যান্টিভাইরাস ইঞ্জিন (বা সার্ভিস) এবং কিছু গার্ডরেল অন্তর্ভুক্ত করে: AV স্ক্যান, ফাইল-টাইপ চেক (magic bytes), আর্কাইভ সীমা (zip bombs, nested zips, বিশাল আনকমপ্রেসড সাইজ), এবং আপনি না পারলে এমন ফরম্যাট ব্লক করা।
যদি স্ক্যান ব্যর্থ করে, টাইমআউট হয়, বা “অজানা” ফলায়, ফাইলকে সন্দিগ্ধ ধরুন। কোয়ারেন্টাইনে রাখুন এবং ডাউনলোড লিংক দেবেন না। এখানে টিমগুলো জ্বালায়: “scan failed” কখনই “ship it anyway” এ পরিণত হওয়া উচিত নয়।
যখন আপনি কোনো ফাইল ব্লক করেন, বার্তাটি নিরপেক্ষ রাখুন: “আমরা এই ফাইল গ্রহণ করতে পারিনি। ভিন্ন ফাইল চেষ্টা করুন বা সাপোর্টে যোগাযোগ করুন।” নিশ্চিত না হলে ম্যালওয়্যার সনাক্ত করেছি বলবেন না।
উদাহরণ: প্রোফাইল ফটো এবং ডকুমেন্ট আপলোড
ধরা যাক দুইটি ফিচার: একটি প্রোফাইল ফটো (পাবলিকভাবে দেখানো) এবং একটি PDF রিসিট (প্রাইভেট, বিলিং বা সাপোর্টে ব্যবহৃত)। দুটি ক্ষেত্রে আপলোড সমস্যা একই ধরনের, কিন্তু নিয়মগুলো আলাদা হওয়া উচিত।
প্রোফাইল ছবির জন্য কড়া সীমা রাখুন: শুধুমাত্র JPEG/PNG অনুমোদন করুন, সাইজ ক্যাপ করুন (উদাহরণ 2–5 MB), এবং সার্ভার-সাইডে পুনরায় এনকোড করুন যাতে ইউজারের আসল বাইটি সার্ভ না করা হয়। চেক পাস করার পরে তা পাবলিক স্টোরেজে রাখুন।
PDF রিসিটের জন্য বড় সাইজ রাখুন (উদাহরণ 20 MB পর্যন্ত), ডিফল্টে প্রাইভেট রাখুন, এবং প্রধান অ্যাপ ডোমেইন থেকে ইনলাইন রেন্ডার করা এড়িয়ে চলুন।
একটি সহজ স্ট্যাটাস মডেল ব্যবহারকারীদের জানিয়ে রাখে:
- pending: ব্যবহারকারী ফাইল বেছে নিয়েছে, আপলোড শুরু হয়নি
- uploaded: স্টোরেজে বাইট এসেছে
- scanning: ব্যাকগ্রাউন্ড জব চেক করছে
- clean (বা rejected): ফাইল উপলব্ধ (বা ব্লক)
Signed URLs এখানে সুন্দরভাবে ফিট করে: write-only, এক অবজেক্ট কী-র জন্য স্বল্প-জীবী signed URL ব্যবহার করুন আপলোডের জন্য। পড়ার জন্য আলাদা স্বল্প-জীবী signed URL ইস্যু করুন এবং সেটা কেবল তখন দিন যখন status clean।
তদন্তের জন্য যা লাগে তা লগ করুন, না যে কাঁচা ফাইল: user ID, file ID, type guess, size, storage key, timestamps, scan result, request IDs। র কনটেন্ট বা ডকুমেন্টের সংবেদনশীল ডেটা লগ করবেন না।
সাধারণ ভুল এবং সহজ ফাঁদ
বেশিরভাগ আপলোড বাগ ঘটে কারণ একটি ছোট “অস্থায়ী” শর্টকাট স্থায়ী হয়ে যায়। প্রতিটি ফাইলকে অনবিশ্বাসী ধরুন, প্রতিটি URL শেয়ার করা হবে মনে করুন, এবং প্রতিটি “আমরা পরে ঠিক করে নিব” সেটিং ভুলে যাওয়া হবে ধরে নিন।
ঘটশর মানুষ বারবার পড়ে এমন ফাঁদগুলো:
- কেবল ক্লায়েন্ট-সাইড চেকের ওপর নির্ভর করা। ব্রাউজার কয়েক সেকেন্ডে বাইপাস করা যায়।
- ব্যবহারকারীদেরকে পথ, ফাইলনেম বা অবজেক্ট কীর প্রভাবিত করতে দেওয়া।
- আপলোডগুলো “মুহূর্তের জন্য” পাবলিক করা।
- অত্যন্ত দীর্ঘজীবী বা একাধিক ব্যবহারকারীর জন্য কাজ করা signed URLs ব্যবহার করা।
- ভুল
Content-Typeদিয়ে ফাইল সার্ভ করা যাতে ব্রাউজার ঝুঁকিপূর্ণ কন্টেন্ট ইন্টারপ্রেট করে।
মনিটরিং হলো একমাত্র বিষয় টিমগুলো এমনকি পরে বাদ দেয়। আপলোড ভলিউম, গড় সাইজ, শীর্ষ আপলোডার ও এরর রেট ট্র্যাক করুন। একটি বোশ্যুক অ্যাকাউন্ট রাতারাতি হাজার হাজার বড় ফাইল আপলোড করতে পারে।
উদাহরণ: একটি টিম ইউজার-প্রদানকৃত ফাইলনেম ব্যবহার করে avators সংরক্ষণ করে “avatar.png” নামে শেয়ার্ড ফোল্ডারে। একজন ব্যবহারকারী অন্যদের ছবি ওভাররাইট করে দেয়। সমাধান হল: সার্ভার-সাইডে অবজেক্ট কী জেনারেট করা, আপলোড ডিফল্টে প্রাইভেট রাখা, এবং কন্ট্রোলড রেসপন্সের মাধ্যমে রিসাইজড ইমেজ এক্সপোজ করা।
দ্রুত চেকলিস্ট ও পরবর্তী ধাপ
শিপ করার আগে ফাইনাল পাস হিসেবে এটাকে ব্যবহার করুন। প্রতিটি আইটেমকে একটি রিলিজ ব্লকার হিসেবে বিবেচনা করুন, কারণ বেশিরভাগ ইনসিডেন্ট একটি অনুপস্থিত গার্ডরেল থেকে শুরু হয়।
দ্রুত চেকলিস্ট
- সার্ভারে allowlist, বাস্তব কন্টেন্ট চেক (নাম নয়), এবং প্রতিটি ফাইলে একটি হার্ড ম্যাক্স সাইজ দিয়ে ভ্যালিডেট করুন।
- আপলোডগুলো ডিফল্টে প্রাইভেট রাখুন, এবং প্রতিবার যখন ফাইল পড়া/ডাউনলোড/প্রিভিউ হয় তখন পারমিশন চেক করুন।
- যদি signed URL আপলোড ব্যবহার করেন, সেগুলো স্বল্প-জীবী, এক অবজেক্ট কী-ভিত্তিক এবং ইস্যু লগ করা রাখুন যাতে অপব্যবহার ট্রেস করা যায়।
- কোআরেন্টাইন প্রথমে, স্ক্যান পরে: ফাইল clean না হওয়া পর্যন্ত প্রিভিউ বা ডাউনলোড অনুমোদন করবেন না।
- নিরাপদ ডাউনলোড আচরণ জোরদার করুন: পূর্বানুমানযোগ্য
Content-Type, নিরাপদ ফাইলনেম, এবং ডকুমেন্টের জন্যattachment।
পরবর্তী ধাপ যা মূল্য দেয়
আপনার নিয়মগুলো সাদামাটা ভাষায় লিখে রাখুন: অনুমোদিত টাইপ, ম্যাক্স সাইজ, কে কি অ্যাক্সেস পায়, signed URL কতক্ষণ বাঁচে, এবং “scan passed” মানে কী। এটা product, engineering, এবং support-শহীদ একটি অংশিক চুক্তি হয়ে যায়।
কিছু টেস্ট যোগ করুন যা সাধারণ ব্যর্থতা ধরবে: অতিরিক্ত বড় ফাইল, নাম পরিবর্তন করে executable, অননুমোদিত রিড, মেয়াদোত্তীর্ণ signed URLs, এবং “scan pending” অবস্থায় ডাউনলোড চেষ্টা। এই টেস্টগুলো একটি ইনসিডেন্টের তুলনায় সস্তা।
আপনি যদি দ্রুত তৈরির উপর থাকেন, এমন ওয়ার্কফ্লো ব্যবহার করুন যেখানে পরিবর্তন প্ল্যান করা এবং নিরাপদে রোলব্যাক করা যায়। Koder.ai (koder.ai) ব্যবহার করা টিমগুলো প্রায়ই planning mode এবং snapshots/rollback-এ নির্ভর করে আপলোড নিয়ম কড়া করার সময়, কিন্তু মূল দরকারি শর্ত থাকে একই: নীতি UI নয়, ব্যাকএন্ড-Enforces করবে।
সাধারণ প্রশ্ন
What’s the minimum I should do to make file uploads “safe enough”?
Start with private by default and treat every upload as untrusted input. Enforce four basics server-side:
- Who can upload
- What file types you accept (allowlist)
- How big/how often (size + rate limits)
- Who can read it later (per-file permission checks)
If you can answer those clearly, you’re already ahead of most incidents.
Why are file uploads a common first security incident?
Because users can upload a “mystery box” that your app stores and might later serve back to other users. That can lead to:
- Unauthorized access to private documents
- Phishing or account takeover if a file is served as trusted web content
- Outages and high bills from upload floods or huge files
It’s rarely just “someone uploaded a virus.”
What’s the difference between storing files and serving files, and why does it matter?
Storing is keeping bytes somewhere. Serving is delivering those bytes to browsers and apps.
The danger is when your app serves user uploads with the same trust and rules as your main site. If a risky file is treated like a normal page, the browser may execute it (or users may trust it too much).
A safer default is: store privately, then serve through controlled download responses with safe headers.
How do I stop users from downloading someone else’s uploaded file?
Use default deny and check access every time a file is downloaded or previewed.
Practical rules:
- Every file record should have an owner (user/org) and purpose (avatar, invoice, etc.)
- On read/download, verify the requester is allowed for that specific file
- Avoid “folder-based” security like “anything under
/uploads/is fine” - Keep support access temporary and logged (grant access to one file, expire it automatically)
Most real bugs are simple “I can see another user’s file” mistakes.
How do I validate file type without trusting the filename or Content-Type?
Don’t trust the filename extension or the browser’s Content-Type. Validate on the server:
- Use an allowlist of formats per feature (e.g., JPEG/PNG for avatars, PDF for receipts)
- Detect type server-side and check magic bytes (file signatures)
- Rename files for storage using a random ID; keep the original name only as metadata
- Block risky formats you don’t need (especially HTML, SVG, script-like content)
If the bytes don’t match an allowed format, reject the upload.
What limits should I set to prevent upload-based DoS attacks?
Because outages often come from boring abuse: too many uploads, huge files, or slow connections tying up server resources.
Defaults that work well:
- Set per-feature max sizes (avatars small, documents bigger)
- Enforce limits at multiple layers (app + reverse proxy + timeouts)
- Add rate limits per user and per IP, with stricter limits for anonymous traffic
Treat every byte as cost and every request as potential abuse.
Should I use signed URLs for uploads, and what’s the safest default?
Yes, but do it carefully. Signed URLs let the browser upload/download directly from object storage without making the bucket public.
Good defaults:
- Keep write URLs short-lived (often 1–5 minutes)
- Scope each URL to one object key, not a folder
- Issue URLs only after permission checks
- Log who requested the URL and for what file
Direct-to-storage reduces API load, but it makes scoping and expiration non-negotiable.
What’s a safe step-by-step upload flow I can implement?
The safest pattern is:
- Create an upload record with status
pending - Upload bytes into a private location
- Validate size + type (magic bytes) server-side
- Scan (usually async) and move status to
cleanorquarantined - Only allow download/preview when status is
clean
This prevents “scan failed” or “still processing” files from being shared accidentally.
Do I really need malware scanning, and what does “basic scanning” look like?
Scanning helps, but it’s not a guarantee. Use it as a safety net, not your only control.
Practical approach:
- Quarantine first: don’t expose links until scanning completes
- Scan asynchronously for scale; show “processing” to the user
- If scanning fails or times out, treat the file as suspicious and keep it blocked
- Add guardrails for archives (zip bombs, huge uncompressed sizes) if you allow them
The key is policy: “not scanned” should never mean “available.”
How should I deliver uploaded files safely (headers, domains, downloads)?
Serve files in a way that prevents browsers from interpreting them as web pages.
Good defaults:
- Set
Content-Disposition: attachmentfor documents - Use a safe, server-chosen
Content-Type(orapplication/octet-stream) - Use opaque storage keys (not user filenames) in URLs
- Prefer a separate download domain for user content when possible
This reduces the risk that an uploaded file turns into a phishing page or script execution.