2010-11-23 99 views
2

其實這是一個兩部分的問題:驗證用戶IP和表格IP:我應該使用ip2long嗎?

首先,ip2long是一個很好的IP驗證器?假設有人在表單中插入IP,並且我想驗證它是正確的。檢查ip2long是否不返回FALSE可以嗎?

第二:您如何看待訪問者的IP並拒絕訪問,如果它不是有效的IP?看着我的訪客的ips,有時候我會發現諸如「1.1 TIBURON」之類的東西。那麼Wtf是什麼?我聽說過'spoofed ip'這個詞,那是什麼?它與垃圾郵件機器人有關嗎?

+0

什麼是數據源? Apache訪問日誌? – stillstanding 2010-11-23 08:53:59

+0

該IP從$ _SERVER獲取並保存到mysql數據庫。 – HappyDeveloper 2010-11-23 09:38:56

回答

0

取決於你要如何徹底驗證是。對格式良好的IP地址進行一個非常簡單的檢查將是一條正則表達式,與/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/一致。 (實際上,SubniC的正則表達式可能好得多)。這會趕上你的1.1。 TIBURON條目,因爲它沒有形成良好。

我不確定ip2long是否檢查此內容,或者只是默默丟棄不看起來像IP的字符串部分。

深入一步,你可以阻止「保留」 IP地址和範圍,如127.0.0.1,255.255.255.255等

您可能還需要添加黑名單過濾掉從可疑的網絡請求,或者您過去遇到麻煩的客戶。

我很好奇,儘管如何入侵那裏 - 一個攻擊者不應該能夠得到這個值到$ _SERVER ['REMOTE_ADDR'],除非他們已經破壞了底層操作系統,或者至少apache (或者你正在運行的任何Web服務器)。

你沒有任何機會閱讀客戶端上的IP(使用javascript)?

1

如果您只需要聲明IP地址格式正確,您可以使用像下圖所示的常規表達式。

編輯:

if (preg_match('/\A(?:^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$)\Z/im', $subject)) { 
    # Successful match 
} else { 
    # Match attempt failed 
} 

如果你想走得更遠,你可以做一個ping到IP發現,如果它是積極的。

關於你的第二個問題,我不知道該說些什麼,我從來沒有見過的「1.1 TIBURON」的事情,

HTH

+0

我不認爲ping是一個好主意。許多路由器/防火牆不響應ping,並阻止入站ping作爲安全措施。不能ping通某些東西並不意味着它不存在。 – tdammers 2010-11-23 09:06:41

+0

正則表達式不適合我,它說「分隔符不能是字母數字或反斜槓」。 \ b的用途是什麼? – HappyDeveloper 2010-11-23 09:45:41

0

我有這段代碼。這已經有一段時間了,我不記得它背後的一些決定,但我向你保證它已經過全面測試
(實際上我只是稍微調整了一下,重命名了變量並添加了評論,所以可能我剛剛打破了它:)

您可能會發現get_ip_addris_private_ip_addr函數有用。
get_ip_addr可以同時使用IP地址或主機名。

<?php 

function get_ip_addr($host){ 
    $long_ipaddr = my_ip2long($host); 
    $host = trim($host); 
    if($long_ipaddr !== false){ 
     $str_ip = long2ip($long_ipaddr); // Because of e.g. 245.254.245 
     return $str_ip; 
    } 

    $ip_addr = @gethostbyname($host); 
    if($ip_addr and $ip_addr != -1 ){ 
     return $ip_addr; 
    } 

    return false; 
} 

function my_ip2long($ipaddr){ 
    $long_ip = ip2long($ipaddr); 
    if($long_ip === false){ 
     return false; 
    } 

    // http://php.net/manual/en/function.ip2long.php says: 
    // Note: 
    // Because PHP's integer type is signed, and many IP addresses 
    // will result in negative integers, you need to use 
    // the "%u" formatter of sprintf() or printf() to get 
    // the string representation of the unsigned IP address. 
    $long_ip = sprintf("%u", $long_ip); 
    return $long_ip; 
} 

function ip2bin($ip){ 
    $octets = explode(".", $ip); 
    foreach($octets as $k => $v){ 
     $octets[$k] = str_pad(decbin($v), 8, "0", STR_PAD_LEFT); 
    } 
    return implode('', $octets); 
} 

function ip_in_range($ip, $prefix, $mask_len){ 
    $ip = ip2bin($ip); 
    $prefix = ip2bin($prefix); 

    $ip = substr($ip, 0, $mask_len); 
    $prefix = substr($prefix, 0, $mask_len); 

    // Watch out! Two numerical strings are converted to integers 
    // when you use ==. This is trouble for long integers. 
    // Using === skips this behaviour 
    return ($ip === $prefix); 
} 


function is_private_ip_addr($ipaddr){ 
    if("localhost" === $ipaddr) return true; 

    $long_ipaddr = my_ip2long($ipaddr); 
    if($long_ipaddr === false){ 
     return false; // Shouldn't be calling this! 
    } 
    // Info below obtained from http://bugs.php.net/bug.php?id=47435#c145655 
    // Not sure why 127.0.0.0/8 isn't mentioned ...? 
    // Also, in IPv6 there's the multicast address range: ff00::/8s 
    // 
    //  IPv4 private ranges 
    //  10.0.0.0/8  // private use network (rfc1918) 
    //  172.16.0.0/12 // private use network (rfc1918) 
    //  192.168.0.0/16 // private use network (rfc1918) 
    // 
    //  IPv4 reserved ranges 
    //  0.0.0.0/8  // "this" network (rfc1700) 
    //  169.254.0.0/16 // link local network (rfc3927) 
    //  192.0.2.0/24 // test net (rfc3330) 
    //  224.0.0.0/4 // Multicast (rfc3171) 
    //  240.0.0.0/4 // Reserved for Future Use (rfc1700) 
    // 
    //  IPv6 Private range 
    //  fc00::/7  // unique-local addresses (rfc4193) 
    //  
    //  IPv6 Reserved ranges 
    //  ::/128   // unspecified address (rfc4291) 
    //  ::1/128  // loopback address (rfc4291) 
    //  fe80::/10  // link local unicast (rfc4291) 
    //  2001:db8::/32 // documentation addresses (rfc3849) 
    //  5f00::/8  // 6Bone 
    //  3ffe::/16  // 6Bone 
    //  ::ffff:0:0/96 // IPv4-Mapped addresses (rfc4291) 
    //  2001:10::/28 // ORCHID addresses (rfc4843) 
    //  ::/0   // default unicast route address 
    // 
    // Anyways, this are the relevant RFCs: 
    // RFC 3330 (Sep 2002), "Special-Use IPv4 Addresses": 
    //        see section 3 for a nice table 
    // RFC 5156 (Apr 2008), "Special-Use IPv6 Addresses" 
    // 

    // Also, this function currently only deals with IPv4 addresses, 
    // since PHP's ip2long simply doesn't support IPv6 anyway. 
    // You can't currently even trust long ints to have 64 bit, 
    // so a 128 bit long int is out of the question. 

    if(ip_in_range($ipaddr, "127.0.0.0", 8)) return true; // Loopback 
    if(ip_in_range($ipaddr, "10.0.0.0", 8)) return true; // Private addresses (Class A range) 
    if(ip_in_range($ipaddr, "172.16.0.0", 12)) return true; // Private addresses (Class B range) 
    if(ip_in_range($ipaddr, "192.168.0.0", 16)) return true; // Private addresses (Class C range) 
    if(ip_in_range($ipaddr, "169.254.0.0", 16)) return true; // "This" network 
    if(ip_in_range($ipaddr, "192.0.2.0", 24)) return true; // "TEST-NET" (documentation and examples) 
    if(ip_in_range($ipaddr, "224.0.0.0", 4)) return true; // Multicast 
    if(ip_in_range($ipaddr, "240.0.2.0", 4)) return true; // Reserved for future use 

    return false; 
} 

您可以考慮在寬鬆的CC BY-SA下發布此代碼。
做任何你想做的事情,但如果你改善它,請在這裏告訴我們。
我正在標記此帖子社區維基。