سطح B: زره امنیتی (خنثیسازی XSS و بررسی عدد)
در سطح A، جلوی ورودیهای خالی را گرفتیم. اما مشکل اصلی (حمله XSS) همچنان پابرجاست. ما به ورودی کاربر اجازه دادیم که به عنوان کد HTML/JavaScript اجرا شود. در این سطح، زره امنیتی خود را میپوشیم.
محتوای آموزشی
۱. حمله XSS چیست؟
XSS مخفف **Cross-Site Scripting** است. این حمله زمانی اتفاق میافتد که یک مهاجم، کدهای سمت-مشتری (مثل JavaScript) را به یک صفحه وب «تزریق» میکند تا در مرورگر کاربران دیگر اجرا شود. هدف میتواند دزدیدن اطلاعات (مثل کوکیهای لاگین) یا تغییر ظاهر سایت برای فریب کاربر باشد.
کاری که ما در ابتدای کلاس با <script>alert(...)</script> انجام دادیم، سادهترین نوع حمله XSS بود.
۲. راهحل: پاکسازی (Sanitization) با htmlspecialchars()
راهحل این نیست که جلوی کاربر را بگیریم که کاراکتر < را تایپ کند. شاید نام شرکت کاربر " باشد! راهحل این است که این کاراکترها را «خنثی» کنیم.
تابع htmlspecialchars() دقیقاً همین کار را میکند. این تابع، کاراکترهای خاص HTML را به «موجودیتهای HTML» (HTML Entities) بیخطر تبدیل میکند:
<تبدیل میشود به<(که در مرورگر < نمایش داده میشود اما تگ نیست)>تبدیل میشود به>(که در مرورگر > نمایش داده میشود اما تگ نیست)&تبدیل میشود به&"(دابل کوتیشن) تبدیل میشود به"'(سینگل کوتیشن) تبدیل میشود به'
قانون طلایی: هرگز، هرگز، هرگز دادهای که از کاربر میگیرید را مستقیماً در HTML با echo چاپ نکنید، مگر اینکه قبلاً آن را از htmlspecialchars() عبور داده باشید.
۳. اعتبارسنجی نوع: is_numeric()
مشکل دیگر: در ماشین حساب گام ۴، اگر کاربر به جای عدد "10"، کلمه "ده" را وارد میکرد چه؟ PHP سعی میکرد "ده" را به عدد تبدیل کند (که 0 میشود) و محاسبات غلط از آب در میآمد.
تابع is_numeric() بررسی میکند که آیا یک متغیر، یک عدد یا یک «رشته عددی» (مثل "123") هست یا خیر.
is_numeric(123); // true
is_numeric("123"); // true
is_numeric("123.45"); // true
is_numeric("123a"); // false
is_numeric("ده"); // false
کارگاه عملی: ایمنسازی کامل فرم
بیایید کد سطح A را برداریم و آن را در برابر XSS ایمن کنیم:
<?php
$message = "";
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$clean_name = trim($_POST['user_name']);
if (empty($clean_name)) {
$message = "<div class='alert alert-danger'>لطفاً نام خود را وارد کنید.</div>";
} else {
// *** این خط تغییر کرده ***
// ۱. اول داده را برای چاپ، امن میکنیم
$safe_name_to_print = htmlspecialchars($clean_name);
// ۲. حالا از نسخه امن شده در خروجی استفاده میکنیم
$message = "<div class='alert alert-success'>سلام، " . $safe_name_to_print . "! خوش آمدی.</div>";
}
}
?>
<!-- ... بخش HTML فرم ... -->
خروجی و تحلیل:
حالا اگر کاربر کد <script>alert(1)</script> را وارد کند، `alert` اجرا **نمیشود**. بلکه کاربر در خروجی این متن را میبیند:
ما با موفقیت حمله را خنثی کردیم! کد مخرب، به یک متن بیخطر تبدیل شد.
تمرین شما
صورت تمرین: امنسازی ماشین حساب
ماشین حساب خودپردازش (smart_calc.php) گام ۴ را بردارید و آن را با دانش هر دو سطح A و B ایمن کنید.
منطق PHP شما باید:
- چک کند که فرم با
POSTارسال شده باشد. - هر دو ورودی
num1وnum2راtrim()کند. - چک کند که هیچکدام
empty()**نیستند**. - سپس چک کند که هر دو
is_numeric()**هستند**. - **اگر همه اینها درست بود:** محاسبه را انجام دهد و نتیجه را چاپ کند.
- **در غیر این صورت:** (مثلاً اگر خالی بود، یا "abc" وارد شده بود) یک پیام خطای مناسب چاپ کند (مثلاً:
"لطفاً هر دو فیلد را با مقادیر عددی معتبر پر کنید.").
(چالش اضافی: خروجی اعداد را هم از htmlspecialchars() عبور دهید. اگرچه اعداد معمولاً خطرناک نیستند، اما این یک «عادت خوب» امنیتی است.)
باشگاه ذهن: اعتبارسنجی در مقابل پاکسازی
چالش شما: ما در این سطح با دو مفهوم روبرو شدیم: is_numeric() و htmlspecialchars(). این دو، نماینده دو رویکرد متفاوت هستند:
- اعتبارسنجی (Validation): یعنی «بررسی» داده. آیا داده با قوانین ما مطابقت دارد؟ (مثال: آیا این عدد است؟) اگر نه، آن را رد میکنیم.
- پاکسازی (Sanitization / Escaping): یعنی «تمیز کردن» داده. ما داده را میپذیریم، اما آن را طوری تغییر میدهیم که برای استفاده در یک زمینه خاص (مثل HTML) بیخطر باشد. (مثال: تبدیل
<به<).
وظیفه: یک پرامپت برای هوش مصنوعی بنویسید و از او بخواهید:
- تفاوت Validation و Sanitization را با یک مثال ساده در دنیای واقعی (خارج از برنامهنویسی) توضیح دهد. (مثال: نگهبان دم در (Validation) در مقابل بازرسی و بستهبندی وسایل (Sanitization)).
- توضیح دهد که برای یک فیلد «ایمیل»، کدام رویکردها باید به ترتیب اعمال شوند؟ (راهنمایی: اول Validate میکنیم که فرمت ایمیل درست باشد، سپس Sanitize میکنیم تا برای چاپ در HTML امن باشد).