عباس باقری
عباس باقری
خواندن ۸ دقیقه·۲ سال پیش

راهکارهای ساده برای امنیت وب سایت php

در این پست به بررسی چند راه کار ساده برای افزایش امنیت وب سایت می پردازیم.


چک کردن ورودی کاربر

به هیچ وجه نباید به ورودی که از طرف کاربر می آید اطمینان کرد. چه ورودی یک input ساده باشد چه یک درخواست ajax و حتی فایلها! هر داده ای که از کاربر گرفته میشود قبل از نمایش یا انجام کاری در دیتابیس باید چک شود. مثلا داده ورودی یک شماره تلفن است. شماره تلفن چیزی غیر از عدد نیست. مثلا با کد زیر چک میکنیم که واقعا شماره تلفن است یا ورودی دیگر :

$phone = htmlspecialchars( $_POST['phone']); if(preg_match('#^09[0-9]{9}$#' , $phone)){ ... do something }

قبل از نمایش اطلاعات وارد شده توسط کاربر یا استفاده از ورودی کاربر مقدار وارد شده را چک کنید که دارای کدهای جاوااسکریپت و html نباشد.

$phone = htmlspecialchars( $_POST['phone']);
دقت کنید، از این تابع صرفا موقعی استفاده شود که قرار است چیزی در مرورگر نمایش داده شود، و برای ذخیره‌سازی نباید از این تابع استفاده کرد.


استفاده از MySQL Prepared Statements

برای وارد کردن اطلاعات و یا کار با اطلاعات در دیتابیس میتوانید از قابلیت prepared statement در php استفاده کنید.

$email = $_POST['email']; $phone= $_POST['phone']; $mysqli = new mysqli($host,$user,$pass,$db); $sql = &quotSELECT id, title FROM `phone`=? and `phone`=?&quot $stmt = $mysqli->prepare($sql); $stmt->bind_param(&quotss&quot,$email,$phone); $stmt->execute(); $result = $stmt->get_result(); while($res = $result->fetch_assoc){ ... }

استفاده از این روش تا حد زیادی از sql injection جلوگیری میکند.


استفاده از متد پست در ارسال فرمها

روش خیلی ساده ای که میتونه کار خرابکارها را یک کمی سختتر کند. اما به معنی ایمن بودن و عدم نیاز به چک کردن داده های ورودی از این روش نیست.


غیرفعال کردن حالت autocomplete در ورودیهای حساس

<input type='password' id='email' name='password' autocomplete='off'>

این برای مواقعی میتواند مفید باشد که فرد نفوذگر از طریق ریموت یا مستقیم به دسک تاپ کاربر بتواند متصل شود و بتواند autocomplete های کاربر را مشاهده کند.


عدم رمزنگاری یا شکستن رمز در سمت کاربر یا frontend

رمزها یا داده های حساس را در سمت سرور رمزنگاری کنید و هیچ گاه این کار در سمت کاربر نباید رخ دهد. برای امنیت ارسال اطلاعات میتوانید از ssl استفاده کنید. یا اگر نیاز به ذخیره داده در سمت کاربر دارید میتوانید از رمزنگاری متفاوت از سمت سرور استفاده کرد.


رمزنگاری داده های حساس روی دیتابیس

رمزعبور، ایمیل، شماره تلفن، اطلاعات مالی ، داده های شخصی و ... مواردی هستند که نباید مستقیما و بدون رمزنگاری در دیتابیس ذخیره شوند تا اگر دیتابیس نشت پیدا کرد، با این کار جلو استفاده هکر از اطلاعات کاربران گرفته خواهد شد. به دلایلی روشهای عمومی کدگذاری امن نیستند.


عدم ارجاع مستقیم کاربر به صفحات

سعی کنید تا حد امکان کاربر نتواند بطور مستقیم به فایلها دسترسی داشته باشد. مثلا شما تعدادی صفحه دارید برای مثال صفحات زیر :

index.php single.php ontact.php tele.php


هیچگاه به شیوه زیر به فایلها ارجاع ندهید.

https://exam.ir/router.php?page=tele.php

و در کدهای php :

$page = $_GET['page']; include $page;

این شیوه بسیار غلط و نفوذپذیر هست. هرگز از این شیوه برای ارجاع کاربران به فایلها استفاده نشود. روش جایگزین استفاده از htaccess و سوئیچ برای دسترسی به صفحات است. به طور مثال :

https://exam.ir/page/tele

در فایل htaccess :

RewriteRule page$ router.php?page=index RewriteRule page/(.+)$ router.php?page=$1


در فایل php :

$page = $_GET['page']; if($page == 'index'){ inclue 'index.php'; }elseif($page == 'tele'){ inclue 'tele.php'; } ...

یا روش دیگر ارسال همه درخواستها به فایلی مانند index.php است.


عدم ارجاع مستقیم کاربران به فایلها

هیچگاه و به هیچ وجه کاربران را مستقیم به فایلها ارجاع ندهید. یا بر اساس داده ورودی از کاربر فایلی را بارگیری نکنید.

$file = $_POST['file']; fopen($file);


این یک روش غلط برای بارگیری فایل از طرف کاربر میباشد. مثلا کاربر میتوان مقدار http://evil.us/evil.jpg را به عنوان ورودی ارسال کند. یا یکی از فایلهای حساس شما را درخواست کند. سعی کنید فایلها را جوری بارگیری کنید که هیچ گاه فایل غیر مرتبط بارگیری نشود.

همچنین در فایل php.ini میتوانید قابلیت بارگیری فایل از طریق url را غیر فعال کنید.

allow_url_fopen = Off

یا از طریق ایجاد تغییر در فایل httpd.conf :

php_admin_flag allow_url_fopen Off


مطمئن شوید کاربر به پوشه ها دسترسی ندارد.

کاربران نیازی به مشاهده پوشه ها و دایرکتوریهای شما ندارند پس مطمئن شوید هیچگاه کاربران به دایرکتوریها دسترسی ندارند و نمیتوانند لیست فایلهای موجود در دایرکتوریها را مشاهده کنند.


تعویض دوره ای رمزها و اطلاعات حساس سرور :

رمز ، نام کاربری و ... مرتبط با دیتابیس ، پنل ادمین و ... به صورت دوره ای تعویض شوند تا اگر کسی قبلا دسترسی به سیستم و سرور ما پیدا کرده است، مجددا دسترسی او قطع شود.


تعیین محدودیت برای کاربر دیتابیس

کاربر دیتابیس که عموما نیازی به مواردی مثل DROP ، DELETE و بسیاری از قابلیتهای دیگر دیتابیس ندارد. ضمن اینکه بصورت دوره‌ای رمز کاربر دیتابیس را تعویض میکنیم، دسترسی هایی هم که به آن نیاز ندارد از او سلب میکنیم. در محیط کاربری سی پنل براحتی این کار امکان پذیر است.


استفاده از چند کاربر دیتابیس با سطح دسترسی مختلف

روشی که تا حدی از خرابکاری های مرتبط با sql میتواند جلوگیری کند. مثلا برای کاربر عادی و کاربر ادمین از دو کاربر دیتابیس متفاوت با سطح دسترسی متفاوت میتوان استفاده کرد.


استفاده از فایل robots.txt

این فایل جلوی خرابکاری هکر و ربات مخرب را نمیگیرد. اما مسلما دوست ندارید که پنل ادمین یا کاربران در سرویسهایی مثل گوگل برای جستجوگر قابل نمایش باشد.


غیر فعال کردن توابع پی اچ پی حساس

در بسیاری از موارد ما نیازی به بسیاری از توابع حساس php نداریم. میتوان در فایل php.ini این توابع را غیر فعال کرد.

disable_functions = exec, passthru, shell_exec, system, proc_open, popen, curl_exec, curl_multi_exec, parse_ini_file, show_source


ایجاد محدودیت در آپلود فایل

اگر در برنامه شما فایلی آپلود نمیشود. پس در فایل php.ini این قابلیت را از سرور خود حذف کنید :

file_uploads = off

در صورتی که به آپلود فایل نیاز دارید میتوانید حداکثر حجمی برای فایل ورودی در نظر بگیرید.

upload_max_filesize = 10M post_max_size = 16M


بکاپ گیری دوره ای

این کار باعث میشود که در صورت اشکال یا تخریب اطلاعات شما بتوانید در مدت زمان کمی سرویس خود را مجددا فعال کنید.


استفاده از input مخفی در فرمها

برای جلوگیری از حملات CSRF یکی از کارهایی که علاوه بر ارسال فرمها از طریق درخواست POST میتوانیم انجام دهیم استفاده از input مخفی با مقدار از پیش تعیین شده هست:

$random = create_random_string(); $_SESSION['random'] = $random; echo '<input type=&quothidden&quot value=&quot'. $random .'&quot>';


و در موقع دریافت فرم :

$random = $_POST['random']; if($random == $_SESSION['random']){ ... }


استفاده از فریمورکها :

استفاده از فریمورکهای مختلف مزیتی که دارد این است که بسیاری از مشکلات امنیتی کاهش پیدا میکند اما وقتی از یک فریمورکی مانند لاراول استفاده می‌کنید باید دقت کنید چون ممکن است برخی مشکلات امنیتی همچنان وجود داشته باشند و برنامه نویس از آنها غافل باشد.


عدم ذخیره داده های حساس روی کوکی :

نکته اول اینکه هیچ گاه نباید داده های حساس مانند id شماره تلفن ، ایمیل یا موارد مرتبط را روی کوکی ذخیره کنید. همچنین هیچگاه داده ها را بصورت خام و کدگذاری نشده روی کوکی ذخیره نکنید. همچینین با قابلیتهای کوکی مانند httponly و تاریخ انقضا بخوبی آشنا باشید. تا حد زیادی میتواند جلو سو استفاده افراد خرابکار را بگیرید.

دقت کنید برای کوکی چه داده های حساس و چه داده های غیر حساس به هیچ وجه بصورت خام ذخیره انجام ندهید.


امنیت سشن :

برای امنیت در بخش سشن راه های متعددی وجود دارد.

راه کار اول : ذخیره داده ها روی سشن بصورت رمزگذاری شده

راه کار دوم : وابسته کردن سشن ها به ip کاربر

$_SESSION['fingerprint'] = md5($_SERVER['HTTP_USER_AGENT'] . PHRASE . $_SERVER['REMOTE_ADDR']);

راه کار سوم : بازسازی sessoon id به صورت مداوم

session_start(); session_regenerate_id();

راه کار چهارم : جلوگیری از دسترسی اسکریپتها مانند جاوااسکریپت به سشنها

ini_set('session.cookie_httponly', true);

راه کار پنجم : ذخیره اطلاعات سشن در دیتابیس

این راه حل وجود دارد اما بخاطر افزایش پردازش و کند شدن سرعت اجرا سایت و خطرات امنیتی دیگر بهتر است از آن خودداری شود.

بهتر است چهار راه کار اول همزمان با هم مورد استفاده قرار گیرند.


عدم دسترسی کاربر به هر شی موجود در سرور

مطمئن شوید کاربر هیچ گاه بطور مستقیم هیچ دسترسی به هیچ کدام از اشیا سرور را ندارد. چه فایل چه اسکریپت و یا هر چیز دیگر ...

مثلا هیچ گاه فایلی مستقیما و بدون بررسی وارد نشود. یا هیچ ورودی از سمت کاربر بدون چک کردن و صحت سنجی مستقیما مورد استفاده قرار نگیرد و موارد مشابه!

توابع و فایلهای بدون نیاز به اعتبار سنجی :

کدنویسی شما باید جوری باشد که هیچ کدام از فایلها اسکریپت و یا توابع موجود بدون اعتبارسنجی از کاربر به تنهایی قابلیت انجام عمل حساسی را مثلا روی دیتابیس را نداشته باشد. مثلا یک تابع دارید که اطلاعات کاربر را از دیتابیس میگیرد. و به این شکل مورد استفاده قرار میگیرد.

if(user_is_valid){ load_data(user_id); }

فرض کنید این تابع load_data خارج از دستور چک if قرار بگیرد. میتواند مشکلات امنیتی را بوجود بیاورد.

فرض کنید بجای تابع load_data از یک فایل php بنام load_data.php استفاده کنیم. در این صورت برای فراخوانی اطلاعات کاربر دستور زیر را بکار مگیریم :

if(user_is_valid){ load_data.php }


در صورتی که شخص نفوذگر توانست از نقطه ضعف اگاه شد با بارگیری فایل load_data.php اطلاعات کاربر را بارگیری میکند.

بخاطر زیاد شدن مطالب فعلا به این حد بسنده میکنیم. ولی فراموش نکنید هیچ سرور یا سایتی غیرقابل نفوذ نیست. فقط ممکنه کسی هنوز راه نفوذ بهش رو پیدا نکرده باشه.

موارد بیشتر در وب سایت من

امنیت وبمشکلات امنیتیphpاموزش php
برنامه نویس و طراح وب‌سایت
شاید از این پست‌ها خوشتان بیاید