Kodax

SQL Injection — الجزء 2: الحماية — الأمن المتقدم

SQL Injection

ما هو SQL Injection؟

حقن أوامر SQL ضارة في استعلامات قاعدة البيانات.

خطورته

- سرقة بيانات كاملة

- تعديل أو حذف البيانات

- تجاوز المصادقة

- تنفيذ أوامر النظام

مثال على الهجوم

كود ضعيف ⚠️

username, password = "admin' --", "anything"   # مدخلات من المستخدم
# ❌ خطأ مزدوج: لصق المدخلات في الاستعلام (حقن SQL) ومقارنة كلمة المرور كنص صريح
query = f"SELECT * FROM users WHERE username='{username}' AND password='{password}'"
print(query)

الهجوم

username: admin' --
password: أي شيء

النتيجة

SELECT * FROM users WHERE username='admin' --' AND password='...'

تم تجاوز التحقق من كلمة المرور!

أنواع SQL Injection

1. Classic: نتائج مباشرة

2. Blind: لا نتائج مباشرة (True/False)

3. Time-based: تأخير زمني

4. Union-based: دمج استعلامات

الوقاية

1. Parameterized Queries ✅

import hashlib
import hmac
import os
import sqlite3

conn = sqlite3.connect(":memory:")
cursor = conn.cursor()
cursor.execute("CREATE TABLE users (username TEXT UNIQUE, salt BLOB, password_hash BLOB)")


def hash_password(password, salt):
    return hashlib.pbkdf2_hmac("sha256", password.encode(), salt, 600_000)


salt = os.urandom(16)
cursor.execute("INSERT INTO users VALUES (?, ?, ?)", ("admin", salt, hash_password("S3cure-Pass", salt)))


def login(username, password):
    # ✅ استعلام معاملي بالاسم فقط — كلمة المرور لا تدخل SQL أبداً
    cursor.execute("SELECT salt, password_hash FROM users WHERE username = ?", (username,))
    row = cursor.fetchone()
    if row is None:
        return False
    # مقارنة الـ hash في الكود بمقارنة ثابتة الزمن
    return hmac.compare_digest(hash_password(password, row[0]), row[1])


print(login("admin", "S3cure-Pass"), login("admin' --", "anything"))

2. ORM ✅

# مع Flask-SQLAlchemy: الـ ORM يمرر القيم كمعاملات تلقائياً — ثم تحقق من الـ hash كما أعلاه
def find_user(User, username):
    return User.query.filter_by(username=username).first()

3. Input Validation

4. Least Privilege (أقل صلاحيات)

5. Web Application Firewall (WAF)

# أمثلة على SQL Injection والحماية
import sqlite3

# ===== الطريقة الخاطئة (ضعيفة) ⚠️ =====
def login_vulnerable(username, password):
    """لا تستخدم هذا أبداً!"""
    conn = sqlite3.connect('users.db')
    cursor = conn.cursor()
    
    # خطر! SQL Injection ممكن
    query = f"SELECT * FROM users WHERE username='{username}' AND password='{password}'"
    cursor.execute(query)
    
    user = cursor.fetchone()
    conn.close()
    return user is not None

# ===== الطريقة الصحيحة (آمنة) ✅ =====
def login_secure(username, password):
    """الطريقة الآمنة باستخدام Parameterized Queries"""
    conn = sqlite3.connect('users.db')
    cursor = conn.cursor()
    
    # آمن! المعاملات محمية
    query = "SELECT * FROM users WHERE username=? AND password=?"
    cursor.execute(query, (username, password))
    
    user = cursor.fetchone()
    conn.close()
    return user is not None

# ===== استخدام ORM (الأفضل) ✅ =====
from sqlalchemy import create_engine, Column, String
from sqlalchemy.orm import sessionmaker, declarative_base

Base = declarative_base()

class User(Base):
    __tablename__ = 'users'
    username = Column(String, primary_key=True)
    password = Column(String)

def login_orm(username, password):
    """الطريقة الأفضل باستخدام ORM"""
    engine = create_engine('sqlite:///users.db')
    Session = sessionmaker(bind=engine)
    session = Session()
    
    # آمن! ORM يحمي تلقائياً
    user = session.query(User).filter_by(
        username=username,
        password=password
    ).first()
    
    session.close()
    return user is not None

# ===== اختبار الضعف =====
def test_injection():
    print("=== اختبار SQL Injection ===")
    
    # محاولة هجوم
    malicious_username = "admin' OR '1'='1"
    malicious_password = "' OR '1'='1"
    
    # الضعيف (سينجح الهجوم)
    # result = login_vulnerable(malicious_username, malicious_password)
    
    # الآمن (سيفشل الهجوم)
    result = login_secure(malicious_username, malicious_password)
    
    print(f"نتيجة محاولة الاختراق: {'نجح ⚠️' if result else 'فشل ✅'}")
اختبر فهمك