পাঠ ২২ · ৬০-এর মধ্যে · মডিউল ৫
Home / Courses / Cybersecurity & Ethical Hacking / A04 ইনসিকিউর ডিজাইন

A04: ইনসিকিউর ডিজাইন

OWASP A04: Insecure design
৭ মিনিট পড়া মধ্যবর্তী · Intermediate Python কোডসহ সম্পূর্ণ বাংলায়

এই পাঠে যা শিখবেন

  • Insecure Design কীভাবে একটি ইমপ্লিমেন্টেশন বাগ থেকে ভিন্ন — সমস্যাটা লজিকের পরিকল্পনায়, টাইপিং ভুলে নয়
  • বিজনেস-লজিক ফ্ল কীভাবে বাস্তব আর্থিক ক্ষতির কারণ হতে পারে (নেগেটিভ-কোয়ান্টিটি উদাহরণ)
  • থ্রেট মডেলিং কী, এবং কেন এটি কোড লেখার আগে করতে হয়
  • একটি ইনসিকিউর ও সিকিউর চেকআউট ফাংশনের পাশাপাশি তুলনা — কোড সহ

১ · Insecure Design আসলে কী — এবং কেন এটি একটি নতুন ক্যাটাগরি

OWASP Top 10-এর ২০২১ সংস্করণে Insecure DesignInsecure Designনিরাপত্তা নিয়ন্ত্রণ (security control) সম্পূর্ণ অনুপস্থিত বা অকার্যকর থাকার একটি ক্যাটাগরি — যার শিকড় কোডিং পর্যায়ে নয়, বরং ডিজাইন পর্যায়ে। নামে একটি সম্পূর্ণ নতুন ক্যাটাগরি যুক্ত হয়। আগের অনেক ক্যাটাগরি (যেমন L20-এর SQL Injection) একটি ইমপ্লিমেন্টেশন বাগ — কোড ঠিকভাবে লেখা হলে সমস্যাটাই থাকত না। কিন্তু Insecure Design সম্পূর্ণ ভিন্ন স্তরের সমস্যা: এখানে কোডটি ঠিক যেভাবে ডিজাইন করা হয়েছিল সেভাবেই কাজ করছে — সমস্যা হলো, ডিজাইনের সময়ই কেউ নিরাপত্তার দিকটি চিন্তা করেনি।

মূল পার্থক্য

একটি বাগ ফিক্স করা যায় কোড ঠিক করে। কিন্তু একটি ডিজাইন ত্রুটি ঠিক করতে হলে প্রায়ই পুরো ফিচারটাই পুনর্বিবেচনা করতে হয় — কারণ "নিরাপদ" এবং "অনিরাপদ" সংস্করণ দুটোই একই লজিক অনুযায়ী নিখুঁতভাবে কাজ করছে বলে মনে হয়, যতক্ষণ না কেউ একটি অস্বাভাবিক ইনপুট দিয়ে দেখায় যে সেই লজিকটাই অসম্পূর্ণ ছিল।

২ · বাস্তব উদাহরণ — নেগেটিভ-কোয়ান্টিটি চেকআউট এক্সপ্লয়েট

কল্পনা করুন একটি ই-কমার্স চেকআউট ফ্লো, যেখানে মোট বিল হিসাব হয় সহজভাবে — total = quantity × price_per_unit। ডেভেলপার হয়তো ধরে নিয়েছেন ব্যবহারকারী সবসময় একটি ধনাত্মক সংখ্যা (যেমন ১, ২, ৫) পাঠাবে — ফলে সার্ভার-সাইডে কখনো quantity > 0 যাচাই করার কোড লেখাই হয়নি। কিন্তু একজন আক্রমণকারী API রিকোয়েস্টে সরাসরি quantity = -5 পাঠালে কী হবে? গণিত অনুযায়ী total হয়ে যায় ঋণাত্মক — অর্থাৎ দোকান উল্টো আক্রমণকারীকে "টাকা ফেরত" দিচ্ছে বা তার অ্যাকাউন্টে ক্রেডিট যোগ করছে।

এটি কোনো ইনজেকশন বা মেমরি-করাপশন বাগ নয় — এটি একটি Business Logic FlawBusiness Logic Flawঅ্যাপ্লিকেশনের ব্যবসায়িক নিয়ম/প্রবাহে (যেমন মূল্য হিসাব, ছাড়, লিমিট) এমন একটি ত্রুটি যা কোনো প্রযুক্তিগত বাগ ছাড়াই অপব্যবহারযোগ্য। — সিস্টেম ঠিক যা করতে বলা হয়েছিল তাই করছে, কিন্তু কেউ কখনো ভাবেননি "নেগেটিভ সংখ্যা এলে কী হবে?"

৩ · থ্রেট মডেলিং — ডিজাইন পর্যায়ের প্রতিরক্ষা

Insecure Design ঠেকানোর প্রধান হাতিয়ার হলো থ্রেট মডেলিংThreat Modelingকোড লেখা শুরুর আগে, ডিজাইন পর্যায়ে, সিস্টেমেটিকভাবে প্রশ্ন করা — "এখানে কী ভুল হতে পারে? কে এটি অপব্যবহার করতে পারে? কীভাবে?" — একটি সহজ কিন্তু শক্তিশালী অভ্যাস: কোড লেখা শুরুর আগেই দলগতভাবে বসে জিজ্ঞাসা করা, "এই ফিচারে কী ভুল হতে পারে?" চেকআউট ফ্লোর ক্ষেত্রে এই প্রশ্নটি করলেই কেউ না কেউ জিজ্ঞাসা করত — "quantity যদি ঋণাত্মক হয়?" — এবং সেই মুহূর্তেই সমাধান (server-side validation) ডিজাইনেই লেখা হয়ে যেত।

  • সম্পদ চিহ্নিত করুন — কী সুরক্ষা দরকার (এখানে: মূল্য/বিলিং লজিক)।
  • সম্ভাব্য অপব্যবহার তালিকা করুন — নেগেটিভ ইনপুট, চরম মান (extreme values), অপ্রত্যাশিত ক্রম।
  • প্রতিটির জন্য নিয়ন্ত্রণ ডিজাইন করুন — সার্ভার-সাইড ভ্যালিডেশন, সীমা (limits), deny-by-default।
  • যাচাই করুন — টেস্টিং-এ ইচ্ছাকৃতভাবে "খারাপ" ইনপুট দিয়ে দেখুন নিয়ন্ত্রণগুলো কাজ করছে কি না।
ফিচার ডিজাইন শুরু Feature design থ্রেট মডেলিং বাদ = A04 দুর্বলতা "কী ভুল হতে পারে?" = নিরাপদ ডিজাইন
একই ফিচার — শুধু ডিজাইন পর্যায়ে থ্রেট মডেলিং করা হয়েছে কি না, সেটাই ঠিক করে দেয় এটি নিরাপদ নাকি A04 দুর্বলতা।

৪ · কোড ডেমো — ইনসিকিউর বনাম সিকিউর চেকআউট

নিচের কোড সেলটি সম্পূর্ণ স্যান্ডবক্সড — এটি একটি ভুয়া ইন-মেমরি "প্রাইস ক্যালকুলেটর" নিয়ে কাজ করছে, কোনো বাস্তব পেমেন্ট গেটওয়ে বা ডেটাবেস স্পর্শ করছে না। প্রথম ফাংশনটি (checkout_insecure) কোনো ভ্যালিডেশন ছাড়াই ইনপুট গ্রহণ করে — ঠিক যেভাবে একটি বাস্তব A04 দুর্বলতা কাজ করে।

Python
PRICE_PER_UNIT = 500  # টাকা, প্রতি ইউনিট

def checkout_insecure(quantity):
    # ইনসিকিউর ডিজাইন: quantity ধনাত্মক কি না তা কখনো যাচাই করা হয়নি
    total = quantity * PRICE_PER_UNIT
    return total

def checkout_secure(quantity):
    # সিকিউর ডিজাইন: থ্রেট মডেলিং থেকে আসা সার্ভার-সাইড বিজনেস-লজিক নিয়ন্ত্রণ
    if quantity <= 0:
        raise ValueError("quantity অবশ্যই ধনাত্মক (positive) সংখ্যা হতে হবে")
    total = quantity * PRICE_PER_UNIT
    return total

# আক্রমণকারী নেগেটিভ quantity পাঠানোর চেষ্টা করছে
attacker_quantity = -5

print("== ইনসিকিউর ভার্সন ==")
result_insecure = checkout_insecure(attacker_quantity)
print(f"quantity={attacker_quantity} পাঠানো হলো -> বিল হলো {result_insecure} টাকা")
print("(ঋণাত্মক বিল মানে দোকান উল্টো আক্রমণকারীকে ক্রেডিট দিয়ে দিচ্ছে!)")

print()
print("== সিকিউর ভার্সন ==")
try:
    result_secure = checkout_secure(attacker_quantity)
    print(f"quantity={attacker_quantity} গৃহীত হলো -> বিল {result_secure} টাকা")
except ValueError as e:
    print(f"রিকোয়েস্ট প্রত্যাখ্যান করা হলো: {e}")

print()
valid_quantity = 3
result_valid = checkout_secure(valid_quantity)
print(f"বৈধ quantity={valid_quantity} -> বিল {result_valid} টাকা (স্বাভাবিকভাবে গৃহীত)")

    
লক্ষ্য করুন — checkout_insecure-এ কোনো "বাগ" নেই, ঠিক যেভাবে লেখা হয়েছে ঠিক সেভাবেই এটি চলছে। সমস্যাটা কোডে নয়, ডিজাইনে — কেউ কখনো ভাবেননি "নেগেটিভ সংখ্যা এলে কী হবে?" এই একটি প্রশ্নের অভাবই একটি সম্পূর্ণ A04 দুর্বলতা তৈরি করে দিতে পারে।
checkout_secure কোনো নতুন "সিকিউরিটি ফিচার" যোগ করেনি — এটি শুধু থ্রেট মডেলিং সেশনে ওঠা একটি সাধারণ প্রশ্নের উত্তরকে সরাসরি কোডে রূপান্তরিত করেছে। এটাই দেখায় কেন থ্রেট মডেলিং ব্যয়বহুল বা জটিল হতে হয় না — এটি মূলত একটি নিয়মিত প্রশ্ন-জিজ্ঞাসার অভ্যাস।

৫ · Insecure Design বনাম অন্যান্য OWASP ক্যাটাগরির সম্পর্ক

Insecure Design প্রায়ই অন্যান্য ক্যাটাগরির সাথে ওভারল্যাপ করে — যেমন L18-এর Broken Access Control-ও প্রায়ই একটি ডিজাইন-স্তরের সিদ্ধান্তের ফল (কখনো ভাবা হয়নি "প্রতিটি রিকোয়েস্টে owner চেক করতে হবে")। পার্থক্যটা হলো ফোকাস: A04 নির্দিষ্টভাবে সেই ক্যাটাগরিতে পড়ে যেখানে মূল সমস্যাটি একটি অনুপস্থিত ব্যবসায়িক-লজিক বা স্থাপত্যগত নিয়ন্ত্রণ — কোনো একক কোডিং বাগ নয়।

মূল কথা · Key takeaway

Insecure Design মনে করিয়ে দেয় যে সিকিউরিটি একটি "পরে যোগ করার" ফিচার নয় — এটি ডিজাইনের প্রথম দিন থেকেই চিন্তাভাবনার অংশ হতে হবে। "এখানে কী ভুল হতে পারে?" — এই একটি প্রশ্ন নিয়মিতভাবে জিজ্ঞাসা করাই থ্রেট মডেলিং-এর পুরো সারমর্ম, এবং এটিই সবচেয়ে সাশ্রয়ী নিরাপত্তা বিনিয়োগ — বাগ প্রোডাকশনে যাওয়ার আগেই ধরা পড়ে।

ভাবনার প্রশ্ন

প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।

প্র ০১ Insecure Design কেন একটি সাধারণ "কোডিং বাগ" থেকে ভিন্ন — এবং কেন এটি ফিক্স করা প্রায়ই বেশি কঠিন?

একটি সাধারণ কোডিং বাগে (যেমন একটি off-by-one error), কোড যেভাবে ডিজাইন করা হয়েছিল সেভাবে চলছে না — একটি লাইন ঠিক করলেই সমাধান। কিন্তু Insecure Design-এ কোড ঠিক যেভাবে ডিজাইন করা হয়েছিল সেভাবেই চলছে — সমস্যাটা হলো ডিজাইনটাই অসম্পূর্ণ ছিল। ফিক্স করতে প্রায়ই পুরো ফিচারের লজিক পুনর্বিবেচনা করতে হয়, নতুন এজ-কেস চিন্তা করতে হয়, এবং কখনো কখনো ব্যবসায়িক সিদ্ধান্ত (যেমন "রিফান্ড পলিসি কী হবে") নতুন করে নিতে হয় — যা একটি এক-লাইনের কোড ফিক্সের চেয়ে অনেক বেশি সময়সাপেক্ষ।

প্র ০২ থ্রেট মডেলিং কোডিং শুরুর আগে করা কেন এত গুরুত্বপূর্ণ — কোডিং-এর পরে করলে সমস্যা কী?

কোডিং শুরুর আগে থ্রেট মডেলিং করলে "কী ভুল হতে পারে" প্রশ্নের উত্তর সরাসরি ডিজাইনেই লেখা হয়ে যায় — অতিরিক্ত খরচ প্রায় শূন্য। কোডিং-এর পরে করলে (বা একেবারেই না করলে) একটি দুর্বলতা হয় প্রোডাকশনে পৌঁছে যায় (real-world exploit ও ক্ষতির ঝুঁকি), অথবা পরে ধরা পড়লেও পুরো ফিচার রিফ্যাক্টর করতে হয় — যা কোডিং-এর আগে একটি সাধারণ আলোচনার চেয়ে বহুগুণ বেশি ব্যয়বহুল ও সময়সাপেক্ষ।

প্র ০৩ নেগেটিভ-কোয়ান্টিটি ছাড়া Insecure Design-এর আরেকটি বাস্তব উদাহরণ ভাবুন — কোন ফিচারে কী প্রশ্ন করা উচিত ছিল?

উদাহরণ: একটি পাসওয়ার্ড-রিসেট ফিচার যেখানে ডিজাইনে কখনো ভাবা হয়নি "একজন ইউজার কতবার রিসেট-কোড রিকোয়েস্ট করতে পারবে?" — সীমাহীন রিকোয়েস্ট অনুমোদিত থাকায় একজন আক্রমণকারী হাজার হাজার রিসেট-কোড জেনারেট করিয়ে ব্রুট-ফোর্স করার সুযোগ পায় (ties to L25/L30)। সঠিক প্রশ্নটি ছিল: "একজন ইউজার প্রতি ঘণ্টায় সর্বোচ্চ কতবার রিসেট রিকোয়েস্ট করতে পারবে, এবং তার পরে কী হবে?" — এই প্রশ্নের উত্তর ডিজাইনেই লেখা থাকলে rate-limiting স্বাভাবিকভাবেই কোডে চলে আসত।

অনুশীলন

  1. চিন্তা করুন: একটি "কুপন কোড" ফিচার ডিজাইন করার সময় থ্রেট মডেলিং করলে কোন কোন প্রশ্ন করা উচিত (উদাহরণ: একই কুপন কতবার ব্যবহার করা যাবে)?

    সম্ভাব্য প্রশ্ন: একই কুপন কি একই ইউজার একাধিকবার ব্যবহার করতে পারবে? কুপনের কোনো মেয়াদ শেষ তারিখ আছে কি? একাধিক কুপন কি স্ট্যাক (একসাথে যোগ) করা যাবে, এবং সেক্ষেত্রে ছাড় কি ১০০%-এর বেশি হয়ে যেতে পারে? এই প্রশ্নগুলোর উত্তর ডিজাইনেই নির্ধারণ না করলে, আক্রমণকারী কুপন রিপিট করে বা স্ট্যাক করে কার্যত বিনামূল্যে পণ্য নেওয়ার সুযোগ পেতে পারে — ঠিক নেগেটিভ-কোয়ান্টিটি উদাহরণের মতোই একটি বিজনেস-লজিক ফ্ল।

  2. পরীক্ষা করুন: উপরের কোড সেলে attacker_quantity-এর মান 0 করে Run চেপে দেখুন — checkout_secure কী প্রতিক্রিয়া দেখায়?

    0-ও quantity <= 0 শর্তে পড়ে যায়, তাই checkout_secure এটিকেও প্রত্যাখ্যান করবে (ValueError রেইজ করবে)। এটি গুরুত্বপূর্ণ, কারণ শুধু নেগেটিভ সংখ্যা নয় — শূন্য কোয়ান্টিটির অর্ডারও অর্থহীন এবং সম্ভাব্য অপব্যবহারযোগ্য (যেমন কোনো সিস্টেম শূন্য-মূল্যের অর্ডারকে ভুলভাবে "সফল পেমেন্ট" হিসেবে গণনা করলে)। ভালো থ্রেট মডেলিং শুধু "নেগেটিভ" নয়, সব সীমারেখা-মান (boundary values) বিবেচনা করে।

আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ

পূর্ববর্তী পাঠ
A03: কমান্ড ইনজেকশন ও অন্যান্য ইনজেকশন