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 'فشل ✅'}")اختبر فهمك