حفرهء امنیتی کدهای بدست آوردن IP واقعی کاربر

اینطور کدها که IP رو از HTTP_CLIENT_IP و HTTP_X_FORWARDED_FOR (و امثالهم)، یعنی هدرهای HTTP، میگیرن، حفرهء امنیتی ایجاد میکنن:

<?php

function getRealIpAddr()
{
if (!empty($_SERVER['HTTP_CLIENT_IP'])) //check ip from share internet
{
$ip=$_SERVER['HTTP_CLIENT_IP'];
}
else
if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) //to check ip is pass from proxy
{
$ip=$_SERVER['HTTP_X_FORWARDED_FOR'];
} else
{
$ip=$_SERVER['REMOTE_ADDR'];
} return $ip;
}
echo 'Your real IP is: ', getRealIpAddr();

?>

این کد اغلب برای محدود کردن دسترسی بر اساس IP استفاده میشه، درحالیکه هر سایتی که از این کد استفاده کنه این قابلیت رو به هکر میده که IP خودش رو براحتی جعل کنه.
خب با این حساب این کد دیگه به چه دردی میخوره؟
همون REMOTE_ADDR به تنهایی که بهتر بود! چون حداقل قابل جعل نیست و حداقل کاربر برای دور زدنش با نیاز به و محدودیتهای پراکسی ها مواجه هست.

این کد فقط برای مقاصد Logging احتمالا بدرد میخوره و نه بیشتر. چون به IP هایی که بدست میده اطمینان کافی نیست از نظر امنیتی.
البته یک وقت هست که براتون حفاظت فقط در برابر کاربران عادی که نهایت استفاده از پراکسی و اینطور چیزها رو بلدن، و نه هکرهای واقعی، مهمه، اونوقت فرق میکنه.
وگرنه حدس زدن/تست کردن اینکه یه سایتی از این کد استفاده میکنه برای یک هکر حرفه ای اونقدر هم سخت نیست و براحتی هم میتونه ازش سوء استفاده کنه. گذشته از اینکه در پروژه های بازمتن قابل استفاده نیست. کلا هم که استفاده ازش باوجود آگاهی از این حفره، میشه «امنیت از طریق تیرگی».

جایی که از این کد برای تشخیص IP کاربر جهت اعمال محدودیت هایی استفاده بشه (مثلا محدودیت تعداد ثبت نام از یک IP در یک بازهء زمانی مشخص)، هکر میتونه ازش سوء استفاده کنه و اون محدودیت ها رو براحتی دور بزنه؛ چون میتونه با ست کردن هدرهای HTTP مربوطه، هر IP ای رو که میخواد بعنوان IP خودش معرفی کنه. اینطوری حتی میتونه خودش رو بجای کاربران دیگری جا بزنه و کاری کنه تا دسترسی اونا به سایت ما قطع بشه.
استفاده از این متغییرها که مقدار اونا از هدرهای HTTP گرفته میشه باعث میشه که هر کس بتونه حتی بدون استفاده از پراکسی یک IP جعلی به سیستم معرفی کنه بعنوان IP خودش. اونم هر IP دلخواه (نه IP واقعی هر پراکسی که در کنترل کاربر نیست).

ضمنا اون کسی که از این کد استفاده میکنه فکر میکنه حتما یک رشته با فرمت IP میگیره، بنابراین احتمال زیاد موقع درج اون رشته در کوئری های SQL اونو Escape نمیکنه.
اما مشکل همینجاست که با این کد، هکر میتونه دقیقا هر رشته ای رو با هر فرمتی، یعنی حتی شامل دستورات SQL و کاراکترهای خاص اون، بجای IP خودش ست کنه. بنابراین باگ SQL Injection هم در بقیه کد خیلی از استفاده کنندگان از این کد وجود خواهد داشت!

تست آنلاین هم صورت گرفت.
من نمونه اون کد حفره دار رو روی سایت خودم گذاشتم تا هرکس میخواد تست کنه: http://hamidreza-mz2.tk/real_ip.php

با این کد هم میتونید جعل IP رو تست کنید:

<?php

$service_port = getservbyname('www', 'tcp');

$target='hamidreza-mz2.tk';
$fake_ip='1.1.1.1';

$address = gethostbyname($target);

$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($socket < 0) {
echo "socket_create() failed: reason: " . socket_strerror($socket) . "\n";
}

$result = socket_connect($socket, $address, $service_port);
if ($result < 0) {
echo "socket_connect() failed.\nReason: ($result) " . socket_strerror($result) . "\n";
}

$in = "GET /real_ip.php HTTP/1.1\r\n";
$in .= "Host: $target\r\n";
$in .= "X-FORWARDED-FOR: $fake_ip\r\n";
$in .= "X_FORWARDED_FOR: $fake_ip\r\n";
$in .= "CLIENT-IP: $fake_ip\r\n";
$in .= "CLIENT_IP: $fake_ip\r\n";
$in .= "Connection: Close\r\n\r\n";
$out = '';

socket_write($socket, $in, strlen($in));

header('Content-type: text/plain');

while ($out = socket_read($socket, 2048)) {
echo $out;
}

socket_close($socket);

?>

عملا با این حفره نه تنها جعل IP، بلکه SQL Injection و حتی در مواردی XSS میشه انجام داد. چون اون افرادی که از این کدها استفاده میکنن فکر میکنن حتما یک چیزی با فرمت IP دریافت میکنن، و در نتیجه نه موقع درج در کوئری اون رو Escape میکنن و نه موقع درج در متن صفحه HTML (مثلا موقع مشاهده لاگ ها از طریق اینترفیس برنامشون) اون رو مثلا از تابع htmlspecialchars عبور میدن.

7 دیدگاه در “حفرهء امنیتی کدهای بدست آوردن IP واقعی کاربر

  1. سلام من یک سوال دارم میخوام فایلهای php را روی ویندوزسرور 2003 اجرا کنم امکان استفاده از fastCGI هست ؟ چگونه؟ لطفا

  2. nokte jalebie, man test nakardam vali aya service haye mese google code ro ham mishe ba proxy dor zad?
    age na pas ina chetor ip fake ro tashkis midan!?

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

    • راه حل چی؟ میخوای IP واقعی کاربر رو تضمینی بگیری؟ خب درواقع تاحالا هیچ راه تضمینی نداره از طریق وب. اگر طرف حرفه ای باشه بالاخره میتونه IP واقعی خودش رو به روشی پنهان کنه و دست شما هم بهش نرسه. این ساختار و طراحی وب و مسائل امنیت و Privacy اون بوده تاحالا. امنیت که فقط امنیت سرور و برنامه های شما نیست، بلکه امنیت و Privacy کاربران هم یک معیار کلیدی بوده در طراحی پروتکل ها و ساختار اینترنت.

    • بستگی داره!
      بستگی به این داره که چه نوع کاربردی از هرچیزی بخوای بگیری.
      بستگی به تمام منطق و جزییات هر کاربرد و برنامه ای.
      بستگی به شرایط هر برنامه ای و هدفی.
      بستگی داره که فرضهای ضروری شما چی باشن.
      بستگی داره که کسی بتونه سوء استفاده ای بکنه یا نه.
      شما باید با دو فرض جعلی و غیرجعلی بودن اطلاعات مورد نظر، منطق برنامه رو چک کنی ببینی چه اتفاقاتی خواهد افتاد و حداکثر چه خسارتی ممکنه ببار بیاد یا نیاد. هم برای کاربر و هم برای برنامهء شما.
      باید تمام حالات و ترکیبات ممکن رو تحلیل کرد.

      مثلا، گوگل اگر بخواد درخواستها از ایران رو بلاک کنه، میتونه از اون هدرهای قابل جعل هم برای شناسایی کشور کاربر استفاده کنه؛ البته علاوه بر REMOTE_ADDR و بعد از REMOTE_ADDR. چرا؟ چون اگر طرف این هدرها (مثل X_FORWARDED_FOR) رو جعل هم کرده باشه و ست کردن این هدر کار یک پراکسی واقعی نبوده باشه، نهایتش گوگل فقط اون درخواست رو بلاک نمیکنه؛ یعنی هیچ مشکل امنیتی برای گوگل پیش نمیاد. گوگل طبیعتا باید اول مقدار REMOTE_ADDR رو چک بکنه و بهش بر اون هدرهای قابل جعل اولویت بده. یعنی اگر مقدار REMOTE_ADDR میگفت که کاربر از ایرانه، ولی HTTP_X_FORWARDED_FOR میگفت که کاربر از ایران نیست، گوگل کاربر رو بلاک میکنه. اگر REMOTE_ADDR میگفت که کاربر از ایران نیست، ولی HTTP_X_FORWARDED_FOR میگفت کاربر از ایرانه، گوگل بازهم باید درخواست رو بلاک کنه، چون کسی نمیاد خودش به HTTP_X_FORWARDED_FOR مقداری بده که بلاک بشه، پس حتما این هدر توسط یک پراکسی ست شده.

      اما یه وقت هست که از HTTP_X_FORWARDED_FOR فقط برای بلاک کردن بعضی IP ها بعلت رفتار خاصی که از اون IP ها سرمیزنه (بطور مثال تعداد زیادی تلاش لاگین اشتباه) میخوایم استفاده کنیم. خب اولا که در اینجا هم باید اول REMOTE_ADDR چک بشه و بهش بر HTTP_X_FORWARDED_FOR اولویت داده بشه، اما دوما اصلا نباید IP موجود در HTTP_X_FORWARDED_FOR رو معیار قرار بدیم و بلاک کنیم، چون هکر ممکنه این IP رو جعل کرده باشه و میتونه مخصوصا سعی کنه IP دیگران و کاربران واقعی سایت شما رو به این وسیله در سایت شما بلاک کنه؛ مگر اینکه شما براتون این قضیه مهم نباشه یا راهکاری دیگری براش داشته باشید یا بهرصورت بخاطر نیازهای بالای امنیتی و غیره مجبور به این کار باشید (باید درنظر بگیرید که چقدر ریسک بلاک شدن عمدی IP کاربران واقعی شما وجود داره و چقدر این قضیه براتون مهمه و میتونه خودش مشکل امنیتی باشه و باعث دردسر و خسارت بشه).

      البته کلا بلاک کردن IP میتونه دردسرآفرین باشه. چون یک IP در شرایط مختلفی میتونه توسط چند یا تعداد زیادی کاربر استفاده بشه؛ بطور همزمان یا غیرهمزمان.

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

پاسخ دهید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

*

شما می‌توانید از این دستورات HTML استفاده کنید: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>