Django-তে এসকিউএল ইনজেকশন প্রতিরোধের উপায়

Django ফ্রেমওয়ার্কে ORM, RawSQL এবং ডাটাবেস কার্সর ব্যবহারের মাধ্যমে এসকিউএল ইনজেকশন প্রতিরোধ ও কোডবেস সুরক্ষার ব্যবহারিক গাইড।

Django ORM এবং র এসকিউএল কোয়েরি ডিফেন্সিভ শিল্ড নির্দেশক বিমূর্ত গ্রাফিক

পাইথনভিত্তিক জনপ্রিয় ওয়েব ফ্রেমওয়ার্ক Django তার বিল্ট-ইন নিরাপত্তার জন্য সুপরিচিত। Django-এর Object-Relational Mapper (ORM) স্বয়ংক্রিয়ভাবে কুয়েরি প্যারামিটারাইজ করে filter(), exclude() বা get() মেথডের মাধ্যমে ডাটাবেসকে এসকিউএল ইনজেকশন থেকে সুরক্ষিত রাখে। এই সুবিধার কারণে অনেক ডেভেলপার ভুলবশত মনে করেন Django অ্যাপ্লিকেশন পুরোপুরি এসকিউএল ইনজেকশনমুক্ত।

বাস্তবে যখন ডেভেলপাররা র এসকিউএল (Raw SQL), ডায়নামিক ফিল্টারিং কিংবা পুরোনো extra() মেথড ব্যবহার করেন, তখন গুরুতর নিরাপত্তা ত্রুটি দেখা দেয়।

এসকিউএল ইনজেকশনের মূল হুমকি মডেল বুঝতে আমাদের এসকিউএল ইনজেকশন পরিচিতি ও প্রতিরোধ নির্দেশিকা পড়ে দেখতে পারেন। এছাড়া নোড ব্যাকএন্ডের ক্ষেত্রে Node.js ও Express-এ এসকিউএল ইনজেকশন প্রতিরোধ গাইড দেখতে পারেন।

এই গাইডে আমরা আলোচনা করব Django অ্যাপ্লিকেশনে কীভাবে এসকিউএল ইনজেকশন প্রবেশ করে এবং তা নির্মূলের সর্বোত্তম উপায় কী।

Django অ্যাপ্লিকেশনে এসকিউএল ইনজেকশন কেন ঘটে

Django ORM সাধারণ কোয়েরিতে ইনপুট স্বয়ংক্রিয়ভাবে স্যানিটাইজ করে:

# নিরাপদ: Django ORM স্বয়ংক্রিয়ভাবে প্যারামিটারাইজ করে
users = User.objects.filter(username=request.POST.get('username'))

এখানে ইনপুট সরাসরি কোয়েরি কোড হিসেবে মূল্যায়িত হয় না। তবে নিচের ক্ষেত্রগুলোতে ইনজেকশন দুর্বলতা তৈরি হতে পারে:

১. RawSQL-এ পাইথন এফ-স্ট্রিং (f-strings) ব্যবহার

কাস্টম কুয়েরি লেখার জন্য যখন ডেভেলপাররা RawSQL কিংবা Manager.raw() মেথডে স্ট্রিং কনক্যাটেনেশন বা f-string ব্যবহার করেন:

# বিপজ্জনক: স্ট্রিং ইন্টারপোলেশনের কারণে এসকিউএলআই ঝুঁকি তৈরি হয়
from django.db.models.expressions import RawSQL

user_input = request.GET.get('order_by', 'id')
# ভুল পদ্ধতি:
users = User.objects.annotate(
    val=RawSQL(f"SELECT score FROM leaderboards WHERE category = '{user_input}'", [])
)

যদি user_input-এ আক্রমণকারী ' OR 1=1 -- ইনজেক্ট করে, তবে সম্পূর্ণ কুয়েরির আচরণ বদলে যায়।

২. অবচিত (Deprecated) QuerySet.extra() ব্যবহার

পূর্বে অতিরিক্ত এসকিউএল শর্ত যুক্ত করার জন্য extra() ব্যবহার করা হতো। যেহেতু এটি সহজেই আন-প্যারামিটারাইজড ইনপুট কোয়েরিতে ঢুকিয়ে দেয়, তাই Django কোর টিম একে অবচিত ঘোষণা করেছে:

# বিপজ্জনক: extra() মেথডে স্ট্রিং ইন্টারপোলেশন
Entry.objects.extra(where=[f"headline = '{request.GET.get('title')}'"]) # কখনোই করবেন না

Manager.raw() দিয়ে নিরাপদ র কোয়েরি

জটিল অ্যানালিটিক্যাল কুয়েরির ক্ষেত্রে যখন ওআরএম যথেষ্ট হয় না, তখন Model.objects.raw() মেথডের সাথে params আর্গুমেন্ট ব্যবহার করতে হবে:

# নিরাপদ: params ব্যবহার করে Model.raw()
from myapp.models import Product

def get_products_by_category(category_name):
    query = """
        SELECT id, name, price, stock 
        FROM myapp_product 
        WHERE category = %s AND active = %s
    """
    params = [category_name, True]
    
    # Django ডাটাবেস ড্রাইভার দিয়ে %s সুরক্ষিতভাবে বাইন্ড করে
    return Product.objects.raw(query, params)

[!IMPORTANT] আর্গুমেন্টগুলোকে সবসময় একটি লিস্ট বা টাপল হিসেবে params-এ পাঠাতে হবে। কুয়েরি টেক্সটে সরাসরি পাইথন ফরম্যাটিং বা f-string ব্যবহার করা সম্পূর্ণ নিষিদ্ধ।

ডাটাবেস কার্সর (connection.cursor) ব্যবহারে সতর্কতা

মডেলের সাথে সরাসরি সম্পর্কিত নয় এমন অপারেশনের ক্ষেত্রে Django-এর ডাটাবেস কার্সর ব্যবহার করার সঠিক নিয়ম:

# নিরাপদ: প্যারামিটারাইজড কুয়েরিসহ connection.cursor()
from django.db import connection

def get_user_statistics(tenant_id, min_purchases):
    query = """
        SELECT user_id, COUNT(*) as total_orders, SUM(amount) as total_spent
        FROM orders
        WHERE tenant_id = %s
        GROUP BY user_id
        HAVING COUNT(*) >= %s
    """
    
    with connection.cursor() as cursor:
        cursor.execute(query, [tenant_id, min_purchases])
        results = cursor.fetchall()
        
    return results

এখানে %s হলো ডাটাবেস প্লেসহোল্ডার। cursor.execute() কুয়েরি এবং ভ্যালু আলাদাভাবে পাঠায়, ফলে কোনো ক্ষতিকর ইনপুট কোড হিসেবে কার্যকর হতে পারে না।

ডায়নামিক order_by ক্লজ সুরক্ষিত রাখা

ইউআরএল প্যারামিটার থেকে ইউজার যদি ডাটা সর্টিং ফিল্ড নির্বাচন করতে পারে, তবে সেক্ষেত্রেও নিয়ন্ত্রণ রাখা জরুরি:

# বিপজ্জনক: সরাসরি ইউজার ইনপুট order_by-তে দেওয়া
sort_field = request.GET.get('sort', 'created_at')
articles = Article.objects.order_by(sort_field) # ইন্টারনাল মডেল পাথ ফাঁস হতে পারে

এর পরিবর্তে একটি নির্দিষ্ট হোয়াইটলিস্ট (Whitelist) ডিকশনারি বা সেট ব্যবহার করুন:

# নিরাপদ: অনুমোদিত ফিল্ডের হোয়াইটলিস্ট
ALLOWED_SORT_FIELDS = {
    'date': '-created_at',
    'title': 'title',
    'views': '-view_count',
}

sort_key = request.GET.get('sort', 'date')
order_clause = ALLOWED_SORT_FIELDS.get(sort_key, '-created_at')

articles = Article.objects.order_by(order_clause)

কোডবেসের দীর্ঘমেয়াদী স্থায়িত্ব ও টিম রিভিউ কালচার গড়ে তুলতে আমাদের ক্লিন কোড ও কোড রিভিউ নীতিমালা দেখুন।

সচরাচর যেসব ভুল পরিলক্ষিত হয়

সাধারণ ভুল ঝুঁকি সমাধান
QuerySet.extra() ব্যবহার আন-প্যারামিটারাইজড এসকিউএল ইঞ্জেকশন স্ট্যান্ডার্ড ওআরএম অ্যানোটেশন বা RawSQL সাথে params ব্যবহার করুন
RawSQL-এ f-string ফরম্যাটিং প্যারামিটার টিউপল বাইপাস হওয়া কুয়েরি ভ্যালু দ্বিতীয় params আর্গুমেন্টে আলাদা পাঠান
কলাম নেমে ইউজার ইনপুট বিশ্বাস করা আইডেন্টিফায়ারে ইনজেকশন পাইথন set বা dict দিয়ে কলামের নাম হোয়াইটলিস্ট করুন
cursor.execute-এ সরাসরি স্ট্রিং বসানো ডাটাবেস এক্সিকিউশনে ক্ষতিকর কোড রান দ্বিতীয় প্যারামিটারে লিস্ট বা টাপল হিসেবে ভ্যারিয়েবল দিন
প্রোডাকশনে DEBUG = True রাখা ডাটাবেস স্কিমা ও এরর ফাঁস প্রোডাকশনে DEBUG = False নিশ্চিত করুন এবং ইন্টারনাল লগ ব্যবহার করুন

Django সিকিউরিটি চেকলিস্ট

প্রোডাকশনে কোড পুশ করার আগে নিচের ধাপগুলো নিশ্চিত করুন:

  • সম্পূর্ণ কোডবেসে কোনো QuerySet.extra() মেথড ব্যবহার করা হয়নি।
  • সকল cursor.execute() কলে দ্বিতীয় আর্গুমেন্ট হিসেবে params পাঠানো হয়েছে।
  • সর্টিং ও ফিল্টারিং প্যারামিটারগুলো অনুমোদিত হোয়াইটলিস্ট দ্বারা নিয়ন্ত্রিত।
  • প্রোডাকশন settings.py-তে DEBUG = False রয়েছে।
  • ডাটাবেস ইউজারের কাছে অপ্রয়োজনীয় টেবিল ড্রপ বা অল্টার করার অধিকার নেই।

সারসংক্ষেপ

Django ফ্রেমওয়ার্কের নিজস্ব ওআরএম এসকিউএল ইনজেকশনের বিরুদ্ধে দারুণ প্রতিরোধ ব্যবস্থা দেয়। অবচিত মেথডগুলো বর্জন করে র কুয়েরি এবং কার্সরে params আর্গুমেন্ট মেনে চললে এবং ফিল্ড নেমে হোয়াইটলিস্ট ব্যবহার করলে Django অ্যাপ্লিকেশনের ডাটাবেস সম্পূর্ণ নিরাপদ রাখা সম্ভব।

তথ্যসূত্র: Django Documentation on Performing Raw SQL Queries, OWASP Django Security Checklist, CWE-89: SQL Injection (মূল্যায়ন নভেম্বর ২০২৬)।

আরও পড়ুন

Node.js ও Express-এ এসকিউএল ইনজেকশন প্রতিরোধের উপায়

Node.js এবং Express ব্যাকএন্ডে pg, mysql2, কোয়েরি বিল্ডার ও ওআরএম ব্যবহারের মাধ্যমে এসকিউএল ইনজেকশন নির্মূলের ব্যবহারিক গাইড।

নিরাপত্তা•৫ মিনিটে পড়া

এসকিউএল ইনজেকশন: কীভাবে কাজ করে ও প্রতিরোধের উপায়

এসকিউএল ইনজেকশন (SQLi) দুর্বলতার আক্রমণ কৌশল, ক্লাসিক্যাল বনাম ব্লাইন্ড এসকিউএলআই এবং প্যারামিটারাইজড কোয়েরি ব্যবহারের সম্পূর্ণ গাইড।

নিরাপত্তা•৪ মিনিটে পড়া