تصور کن یه روز عادی رو میگذرونی و توی کافی شاپ محبوبت نشستی و مشغول چک کردن شبکههای اجتماعی و ایمیلات هستی. همون لحظه، یهو با یه مشکل مواجه میشی: حسابت هک شده! حالا سوال اینجاست، چطور این اتفاق افتاده؟ پاسخ ممکنه در یک نوع حمله به نام SQL Injection باشه. در این مقاله قصد داریم تا به صورت کامل و جامع درباره SQL Injection صحبت کنیم. آماده ای؟ بزن بریم!
برگردیم به اواخر دهه 90، زمانی که اینترنت تازه داشت پا میگرفت و وب سایتها ساده و ابتدایی بودن. اون روزها کسی فکرش رو نمیکرد که یک روز حملات سایبری به این شدت گسترش پیدا کنن. SQL، یک زبان پرسش و جستجوی پایگاه داده است که به برنامه نویسان این امکان رو میده تا دادهها رو مدیریت و دستکاری کنن.
اما خیلی زود، هکرها فهمیدن که میتونن از همین زبان پرسش برای نفوذ به سیستمها استفاده کنن. اولین حملات SQL Injection زمانی رخ داد که توسعه دهندگان، بدون در نظر گرفتن امنیت، دادههای ورودی کاربران رو مستقیم به پایگاه داده میفرستادن. این باعث شد که هکرها بتونن کدهای SQL مخرب رو وارد کنن و به دادههای حساس دسترسی پیدا کنن.

حالا بریم سراغ اصل مطلب. SQL Injection یا به اختصار SQLi یک نوع حمله تزریقی است که به مهاجم این امکان رو میده تا کدهای SQL مخرب رو به یک برنامه وارد کنه. این کدها میتونن به مهاجم اجازه بدن تا به دادههای حساس دسترسی پیدا کنه، دادهها رو تغییر بده یا حتی سیستم رو به طور کامل نابود کنه.
حمله SQL Injection یکی از نگرانیهای اصلی در توسعه اپلیکیشنهای وب هست. درواقع این حمله زمانی رخ میده که اپلیکیشن، ورودیهای مخرب یک کاربر رو قبول کنه و اونها رو به عنوان بخشی از دستورات SQL برای جستجو در پایگاه داده استفاده کنه.
مهاجم میتونه کاراکترها و کلمات کلیدی کنترلی SQL مثل کوتیشن تکی (‘)، کوتیشن دوتایی (“)، علامت مساوی (=)، نظر (- -) و غیره رو تزریق کنه تا ساختار پرسش رو تغییر بده. استفاده از این کاراکترهای کنترلی با دستورات متداول SQL مثل SELECT، FROM، DELETE و غیره، امکان دسترسی یا بازیابی عناصر داده ای از سرور پایگاه داده پشتیبان رو فراهم میکنه.
برای موفقیت یک حمله، اپلیکیشن وب باید کدهای مخرب از طرف مهاجم رو در دستور SQL قرار بده. این کدهای مخرب معمولاً از یک منبع غیرمطمئن میان، ولی بعضی وقتها پایگاههای داده داخلی سیستم هم میتونن منبع دادههای مخرب باشن. وقتی که دستورات مخرب SQL در برابر یک پایگاه داده پشتیبان اجرا میشن، مهاجم میتونه پایگاه داده رو تغییر بده یا بهش دسترسی پیدا کنه. این بستگی به این داره که مهاجم چطور دادههای مخرب رو طراحی کرده باشه.
با توجه به این توضیحات، همیشه باید دقت کنیم که ورودیهای کاربران رو اعتبارسنجی کنیم و از منابع غیرمطمئن دوری کنیم تا از حملات SQL Injection جلوگیری کنیم.
تصور کن یه روز به دادگاه رفتی و یه نفر به اسم باب قراره جلوی قاضی ظاهر بشه. وقتی باب داره فرمهای قبل از دادگاه رو پر میکنه، به جای اسمش مینویسه "Bob is free to go". وقتی قاضی به پرونده اش میرسه و بلند میخونه "حالا نوبت باب است که بره"، مأمور دادگاه هم باب رو آزاد میکنه چون قاضی اینو گفته.
SQL Injection هم تقریباً همین شکلی کار میکنه. این حمله زمانی رخ میده که یه فیلد پرسش SQL که قراره فقط یه نوع داده خاص مثل یه عدد رو قبول کنه، به جای اون اطلاعات غیرمنتظره ای مثل یه فرمان رو دریافت میکنه. وقتی این فرمان اجرا میشه، از محدودههای تعیین شده خارج میشه و میتونه رفتارهای مخربی رو به دنبال داشته باشه. این فیلد پرسش معمولاً از داده هایی که توی یه فرم روی یه صفحه وب وارد شده، پر میشه.
بیایید یه مقایسه ساده بین دستورات SQL معمولی و مخرب داشته باشیم:
توی این دستور SQL معمولی، رشته studentId وارد یه دستور SQL میشه. هدف اینه که توی لیست دانش آموزان دنبال دانش آموزی بگردیم که studentId وارد شده رو داره. وقتی پیدا شد، اطلاعات اون دانش آموز برگردونده میشه. به زبان ساده، دستور میگه "برو این کاربر رو پیدا کن و اطلاعاتش رو بهم بده".
کد ممکنه چیزی شبیه این باشه:
studentId = getRequestString("studentId");
lookupStudent = "SELECT * FROM students WHERE studentId = " + studentId;اگه یه دانش آموز، ID خودش رو به صورت 117 توی یه فرم وب وارد کنه که نوشته "لطفاً شماره دانشجویی خود را وارد کنید"، نتیجه دستور SQL اینجوری میشه:
SELECT * FROM students WHERE studentId = 117;این دستور، رکورد مربوط به دانش آموز با studentId 117 رو برمی گردونه، که دقیقاً همون چیزی هست که توسعه دهنده API انتظار داره.
توی این مثال، یه مهاجم به جای وارد کردن یه عدد، یه فرمان SQL یا منطق شرطی رو توی فیلد ورودی وارد میکنه. مثلاً شماره دانشجویی رو اینجوری وارد میکنه:
117 OR 1=1حالا به جای اینکه پرسش توی جدول دنبال ID مشابه بگرده، میاد چک میکنه ببینه آیا 1 برابر 1 هست یا نه. همونطور که میدونی، این شرط همیشه درسته، بنابراین نتیجه این میشه که پایگاه داده تمام اطلاعات جدول دانش آموزان رو به مهاجم برمی گردونه.
SELECT * FROM students WHERE studentId = 117 OR 1=1;حملات SQL Injection با هدف قرار دادن رابط برنامه نویسی کاربردی (API) یا رابط نرم افزاری که سرور از طریق اون درخواستها رو دریافت میکنه و پاسخ میده، انجام میشه. ابزارهای متداولی وجود دارن که به مهاجمین اجازه میدن به صورت خودکار یه وب سایت رو جستجو کنن و فرمها رو پیدا کنن و سعی کنن انواع مختلفی از دستورات SQL رو وارد کنن تا به جواب هایی که توسعه دهندگان وب سایت انتظارش رو ندارن، برسن و از پایگاه داده سوءاستفاده کنن.
حملات SQL Injection آسونه و جالب اینجاست که جلوگیری ازش هم نسبتاً راحته اگه اصول درست توسعه رعایت بشه. واقعیت اینه که مهلتهای فشرده، توسعه دهندگان بی تجربه و کدهای قدیمی معمولاً منجر به کیفیت و امنیت متغیر کدها میشه. یه فیلد آسیب پذیر توی هر فرم یا نقطه پایانی API در یه وب سایت که به یه پایگاه داده دسترسی داره، ممکنه برای ایجاد یه آسیب پذیری کافی باشه.
SQL Injection به خاطر تواناییش در دسترسی به دادههای حساس و تغییر اون ها، بسیار خطرناکه. برای مثال، یه هکر میتونه با استفاده از SQL Injection، اطلاعات کارتهای اعتباری مشتریان یک فروشگاه آنلاین رو بدزده یا حتی تمام دادههای یک پایگاه داده رو حذف کنه.
بیایید یک مثال ساده از SQL Injection رو بررسی کنیم. این مثال نشون میده که چطور یک مهاجم میتونه از یک آسیب پذیری SQL Injection استفاده کنه تا امنیت اپلیکیشن رو دور بزنه و به عنوان مدیر سیستم وارد بشه.
اسکریپت زیر یک شبه کد هست که روی یک سرور وب اجرا میشه. این یک مثال ساده از احراز هویت با استفاده از نام کاربری و رمز عبور هست. پایگاه داده نمونه ما دارای یک جدول به نام users با ستونهای username و password هست.
# تعریف متغیرهای POST
uname = request.POST['username']
passwd = request.POST['password']
# پرسش SQL آسیب پذیر به SQLi
sql = "SELECT id FROM users WHERE username='" + uname + "' AND password='" + passwd + "'"
# اجرای دستور SQL
database.execute(sql)فیلدهای ورودی در اینجا آسیب پذیر به حمله SQL Injection هستند. یک مهاجم میتونه از دستورات SQL در ورودی استفاده کنه تا دستور SQL که توسط سرور پایگاه داده اجرا میشه رو تغییر بده. مثلاً میتونه یک ترفند با استفاده از کوتیشن تکی انجام بده و فیلد passwd رو به این صورت تنظیم کنه:
password' OR 1=1در نتیجه، سرور پایگاه داده پرسش SQL زیر رو اجرا میکنه:
SELECT id FROM users WHERE username='username' AND password='password' OR 1=1'به خاطر وجود عبارت OR 1=1، شرط WHERE همیشه درسته و اولین id از جدول users برگردونده میشه، که معمولاً id مدیر سیستم هست. به این ترتیب، مهاجم نه تنها احراز هویت رو دور میزنه بلکه به سطح دسترسی مدیر سیستم هم دست پیدا میکنه. اونها همچنین میتونن بقیه دستور SQL رو با استفاده از نظرات کنترل کنن:
-- MySQL, MSSQL, Oracle, PostgreSQL, SQLite
' OR '1'='1' --
' OR '1'='1' /*
-- MySQL
' OR '1'='1' #
-- Access (با استفاده از کاراکترهای null)
' OR '1'='1' %00
' OR '1'='1' %16یکی از رایجترین انواع SQL Injection استفاده از عملگر UNION هست. این عملگر به مهاجم اجازه میده نتایج دو یا چند پرسش SELECT رو با هم ترکیب کنه. این تکنیک به نام union-based SQL Injection شناخته میشه.
مثال زیر از این تکنیک استفاده میکنه.
درخواست HTTP زیر یک درخواست عادی هست که یک کاربر قانونی ارسال میکنه:
GET http://example.com/artists.php?artist=1 HTTP/1.1
Host: example.comپارامتر artist آسیب پذیر به SQL Injection هست. در زیر، محموله ی مخرب پرسش رو به گونه ای تغییر میده که به دنبال رکوردی غیرموجود بگرده. مقدار در رشته پرسش URL رو به -1 تنظیم میکنه. البته میتونه هر مقدار دیگری باشه که در پایگاه داده وجود نداره. اما مقدار منفی انتخاب خوبی هست چون شناسهها در پایگاه داده به ندرت عدد منفی هستند.
GET http://example.com/artists.php?artist=-1 UNION SELECT 1, 2, 3 HTTP/1.1
Host: example.comدر SQL Injection، عملگر UNION معمولاً برای افزودن یک پرسش SQL مخرب به پرسش اصلی که توسط اپلیکیشن وب اجرا میشه، استفاده میشه. نتیجه پرسش تزریقی با نتیجه پرسش اصلی ترکیب میشه. این به مهاجم اجازه میده تا مقادیر ستونها از جداول دیگر رو به دست بیاره.
مثال زیر نشون میده که چطور یک محموله SQL Injection میتونه برای به دست آوردن دادههای معنادارتر از این سایت عمداً آسیب پذیر استفاده بشه:
GET http://example.com/artists.php?artist=-1 UNION SELECT 1, pass, cc FROM users WHERE uname='test' HTTP/1.1
Host: example.comبه این ترتیب، مهاجم میتونه اطلاعات حساس مثل کلمات عبور و شماره کارتهای اعتباری رو از پایگاه داده استخراج کنه.

تنها راه مطمئن برای جلوگیری از حملات SQL Injection، اعتبارسنجی ورودیها و استفاده از Parametrized Query، شامل Prepared Statementها است. کد اپلیکیشن هرگز نباید ورودیها رو مستقیم استفاده کنه. توسعه دهنده باید تمام ورودیها رو پاک سازی کنه، نه فقط ورودیهای فرمهای وب مثل فرمهای ورود. باید عناصر بالقوه مخرب مثل کوتیشن تکی رو حذف کنه. همچنین بهتره که نمایش خطاهای پایگاه داده در مد Production خاموش باشه. خطاهای پایگاه داده میتونن با SQL Injection استفاده بشن تا اطلاعات بیشتری از پایگاه داده به دست بیاد. در ادامه مواردی برای جلوگیری آورده ایم.
یکی از بهترین راهها برای جلوگیری از SQL Injection استفاده از پارامترهای آماده سازی شده است. این روش به شما این امکان رو میده تا دادههای ورودی کاربران رو جدا از کدهای SQL نگه داری و از اجرای کدهای مخرب جلوگیری کنی.
# Python example using SQLite
import sqlite3
conn = sqlite3.connect('example.db')
c = conn.cursor()
username = 'user'
password = 'pass'
# Use prepared statements
c.execute("SELECT * FROM users WHERE username = ? AND password = ?", (username, password))ORMها ابزاری هستن که به شما این امکان رو میدن تا با استفاده از زبانهای برنامه نویسی شیءگرا با پایگاه داده کار کنی. این ابزارها به طور خودکار کدهای SQL رو ایجاد میکنن و جلوی اجرای کدهای مخرب رو میگیرن.
# Python example using SQLAlchemy
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
engine = create_engine('sqlite:///example.db')
Session = sessionmaker(bind=engine)
session = Session()
# Use ORM to query the database
user = session.query(User).filter_by(username='user', password='pass').first()همیشه ورودیهای کاربران رو اعتبارسنجی کن و مطمئن شو که هیچ داده مخربی وارد سیستم نمیشه. از توابع و ابزارهای مختلف برای تمیز کردن و فیلتر کردن دادهها استفاده کن.
دسترسی کاربران به پایگاه داده رو محدود کن و فقط به اونها اجازه بده تا به داده هایی که نیاز دارن دسترسی داشته باشن. این کار میتونه جلوی بسیاری از حملات رو بگیره.
به تیم توسعه ات آموزش بده که چطور از SQL Injection جلوگیری کنن و اهمیت امنیت رو براشون توضیح بده. هر چقدر تیم توسعه ات بیشتر با این نوع حملات آشنا باشه، بهتر میتونه جلوی اونا رو بگیره.

برای جلوگیری از حملات SQL Injection و افزایش امنیت اپلیکیشن ها، استفاده از روشهای معتبر و مطمئن بسیار اهمیت داره. در اینجا چند نمونه کد رو بررسی میکنیم که به شما نشون میده چطور میتونید از تکنیکهای مختلف برای حفاظت از دادهها استفاده کنید.
استفاده از پارامترهای آماده سازی شده یکی از بهترین روشها برای جلوگیری از حملات SQL Injection است. در این روش، ابتدا قالب کلی دستور SQL تعریف میشه و سپس مقادیر ورودی به عنوان پارامتر به اون اضافه میشن. این کار باعث میشه که دادههای ورودی به عنوان کد SQL تفسیر نشن.
<?php
$servername = "localhost";
$username = "username";
$password = "password";
$dbname = "myDB";
// ایجاد اتصال
$conn = new mysqli($servername, $username, $password, $dbname);
// بررسی اتصال
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
$user = $_POST['username'];
$pass = $_POST['password'];
// استفاده از پارامترهای آماده سازی شده
$stmt = $conn->prepare("SELECT * FROM users WHERE username = ? AND password = ?");
$stmt->bind_param("ss", $user, $pass);
$stmt->execute();
$result = $stmt->get_result();
if ($result->num_rows > 0) {
echo "Login successful!";
} else {
echo "Invalid username or password.";
}
$stmt->close();
$conn->close();
?>در این کد، ابتدا اتصال به پایگاه داده ایجاد میشه و سپس از پارامترهای آماده سازی شده برای اجرای پرسش SQL استفاده میشه. این روش باعث میشه که مقادیر ورودی به عنوان داده، و نه به عنوان کد، در نظر گرفته بشن.
استفاده از ORM (Object-Relational Mapping) یک روش دیگه برای جلوگیری از حملات SQL Injection است. ORM به شما اجازه میده تا به جای نوشتن مستقیم کد SQL، از توابع و متدهای زبان برنامه نویسی برای ارتباط با پایگاه داده استفاده کنید.
from django.db import models
class User(models.Model):
username = models.CharField(max_length=100)
password = models.CharField(max_length=100)
# Query using Django ORM
user = User.objects.filter(username='user', password='pass').first()در این کد، از Django ORM برای اجرای پرسش SQL استفاده شده. این روش به طور خودکار ورودیهای کاربر رو اعتبارسنجی میکنه و جلوی حملات SQL Injection رو میگیره.
اعتبارسنجی ورودیها یکی از مهمترین روشها برای جلوگیری از حملات مختلفه. در اینجا یک نمونه کد JavaScript رو میبینید که ورودیهای کاربر رو پاک سازی میکنه تا از اجرای کدهای مخرب جلوگیری بشه.
function sanitizeInput(input) {
const map = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": ''',
"/": '/',
};
const reg = /[&<>"'/]/ig;
return input.replace(reg, (match)=>(map[match]));
}
let userInput = '<script>alert("Hacked by 7Learn!")</script>';
let safeInput = sanitizeInput(userInput);
console.log(safeInput); // <script>alert("Hacked by 7Learn!")</script>این کد، ورودی کاربر رو بررسی و کاراکترهای خاص رو به معادلهای HTML اونها تبدیل میکنه. این کار باعث میشه که ورودی به عنوان کد HTML یا JavaScript تفسیر نشه و به عنوان متن ساده نمایش داده بشه.

SQL Injection با تزریق کدهای SQL مخرب به یک برنامه عمل میکنه و به مهاجم این امکان رو میده تا به دادههای حساس دسترسی پیدا کنه یا اونها رو تغییر بده.
برای تست آسیب پذیری SQL Injection، میتونی از ابزارهای امنیتی مختلفی استفاده کنی یا به صورت دستی کدهای مخرب رو در ورودیهای سایت وارد کنی و ببینی آیا اجرا میشن یا نه.
فریم ورکهای مختلفی مثل Django، Ruby on Rails و ASP.NET به جلوگیری از SQL Injection کمک میکنن، زیرا این فریم ورکها از روشهای امنتری برای مدیریت پایگاه داده استفاده میکنن.
خیر، وب سایت هایی که به درستی ایمن شده باشن و از روشهای امن کدنویسی استفاده کنن، به احتمال کمتری به حملات SQL Injection دچار میشن.
برای افزایش امنیت وب سایت در برابر SQL Injection، باید از روشهای پارامترهای آماده سازی شده استفاده کنی، از ORMها استفاده کنی، دادههای ورودی رو اعتبارسنجی کنی و دسترسی کاربران به پایگاه داده رو محدود کنی.
SQL Injection یکی از خطرناکترین و رایجترین روشهای نفوذ به سیستم هاست که میتونه اطلاعات حساس کاربران رو به خطر بندازه و باعث دزدی اطلاعات بشه. با این حال، با استفاده از روشهای صحیح کدنویسی و پیاده سازی ابزارهای امنیتی، میتونی به راحتی از این حملات جلوگیری کنی. امنیت وب سایتها یکی از مهمترین مسائل در دنیای امروز هست و باید همیشه به اون توجه داشته باشیم تا کاربرانمون در امنیت کامل باشن.
به یاد داشته باش، دنیای اینترنت مثل یک جنگل پر از شکارچی هاست و تو باید همیشه آماده و مجهز باشی تا از خودت و اطلاعاتت محافظت کنی. امیدوارم این مقاله برات مفید بوده باشه و بتونی ازش برای افزایش امنیت وب سایت هات استفاده کنی. موفق باشی!
دوره الفبای برنامه نویسی با هدف انتخاب زبان برنامه نویسی مناسب برای شما و پاسخگویی به سوالات متداول در شروع یادگیری موقتا رایگان شد: