در این پست به بررسی چند راه کار ساده برای افزایش امنیت وب سایت می پردازیم.
به هیچ وجه نباید به ورودی که از طرف کاربر می آید اطمینان کرد. چه ورودی یک input ساده باشد چه یک درخواست ajax و حتی فایلها! هر داده ای که از کاربر گرفته میشود قبل از نمایش یا انجام کاری در دیتابیس باید چک شود. مثلا داده ورودی یک شماره تلفن است. شماره تلفن چیزی غیر از عدد نیست. مثلا با کد زیر چک میکنیم که واقعا شماره تلفن است یا ورودی دیگر :
$phone = htmlspecialchars( $_POST['phone']); if(preg_match('#^09[0-9]{9}$#' , $phone)){ ... do something }
قبل از نمایش اطلاعات وارد شده توسط کاربر یا استفاده از ورودی کاربر مقدار وارد شده را چک کنید که دارای کدهای جاوااسکریپت و html نباشد.
$phone = htmlspecialchars( $_POST['phone']);
دقت کنید، از این تابع صرفا موقعی استفاده شود که قرار است چیزی در مرورگر نمایش داده شود، و برای ذخیرهسازی نباید از این تابع استفاده کرد.
برای وارد کردن اطلاعات و یا کار با اطلاعات در دیتابیس میتوانید از قابلیت prepared statement در php استفاده کنید.
$email = $_POST['email']; $phone= $_POST['phone']; $mysqli = new mysqli($host,$user,$pass,$db); $sql = "SELECT id, title FROM `phone`=? and `phone`=?" $stmt = $mysqli->prepare($sql); $stmt->bind_param("ss",$email,$phone); $stmt->execute(); $result = $stmt->get_result(); while($res = $result->fetch_assoc){ ... }
استفاده از این روش تا حد زیادی از sql injection جلوگیری میکند.
روش خیلی ساده ای که میتونه کار خرابکارها را یک کمی سختتر کند. اما به معنی ایمن بودن و عدم نیاز به چک کردن داده های ورودی از این روش نیست.
<input type='password' id='email' name='password' autocomplete='off'>
این برای مواقعی میتواند مفید باشد که فرد نفوذگر از طریق ریموت یا مستقیم به دسک تاپ کاربر بتواند متصل شود و بتواند autocomplete های کاربر را مشاهده کند.
رمزها یا داده های حساس را در سمت سرور رمزنگاری کنید و هیچ گاه این کار در سمت کاربر نباید رخ دهد. برای امنیت ارسال اطلاعات میتوانید از 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 میتواند جلوگیری کند. مثلا برای کاربر عادی و کاربر ادمین از دو کاربر دیتابیس متفاوت با سطح دسترسی متفاوت میتوان استفاده کرد.
این فایل جلوی خرابکاری هکر و ربات مخرب را نمیگیرد. اما مسلما دوست ندارید که پنل ادمین یا کاربران در سرویسهایی مثل گوگل برای جستجوگر قابل نمایش باشد.
در بسیاری از موارد ما نیازی به بسیاری از توابع حساس 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
این کار باعث میشود که در صورت اشکال یا تخریب اطلاعات شما بتوانید در مدت زمان کمی سرویس خود را مجددا فعال کنید.
برای جلوگیری از حملات CSRF یکی از کارهایی که علاوه بر ارسال فرمها از طریق درخواست POST میتوانیم انجام دهیم استفاده از input مخفی با مقدار از پیش تعیین شده هست:
$random = create_random_string(); $_SESSION['random'] = $random; echo '<input type="hidden" value="'. $random .'">';
و در موقع دریافت فرم :
$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 اطلاعات کاربر را بارگیری میکند.
بخاطر زیاد شدن مطالب فعلا به این حد بسنده میکنیم. ولی فراموش نکنید هیچ سرور یا سایتی غیرقابل نفوذ نیست. فقط ممکنه کسی هنوز راه نفوذ بهش رو پیدا نکرده باشه.