PHP에서 사용자의 정확한 IP 주소를 검색하는 가장 정확한 방법은 무엇입니까?

코리 발루

IP 주소 검색에 사용할 수있는 $ _SERVER 변수 헤더 가 너무 많다는 것을 알고 있습니다 . 위의 변수를 사용하여 사용자의 실제 IP 주소를 가장 정확하게 검색하는 방법 (완벽한 방법은 없음을 잘 알고 있음)에 대한 일반적인 합의가 있는지 궁금합니다.

나는 심층적 인 해결책을 찾기 위해 시간을 보냈고 여러 소스를 기반으로 다음 코드를 생각해 냈습니다. 누군가가 대답에 구멍을 뚫거나 아마도 더 정확한 것에 대해 밝힐 수 있다면 그것을 좋아할 것입니다.

편집에는 @Alix의 최적화가 포함됩니다.

 /**
  * Retrieves the best guess of the client's actual IP address.
  * Takes into account numerous HTTP proxy headers due to variations
  * in how different ISPs handle IP addresses in headers between hops.
  */
 public function get_ip_address() {
  // Check for shared internet/ISP IP
  if (!empty($_SERVER['HTTP_CLIENT_IP']) && $this->validate_ip($_SERVER['HTTP_CLIENT_IP']))
   return $_SERVER['HTTP_CLIENT_IP'];

  // Check for IPs passing through proxies
  if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
   // Check if multiple IP addresses exist in var
    $iplist = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
    foreach ($iplist as $ip) {
     if ($this->validate_ip($ip))
      return $ip;
    }
   }
  }
  if (!empty($_SERVER['HTTP_X_FORWARDED']) && $this->validate_ip($_SERVER['HTTP_X_FORWARDED']))
   return $_SERVER['HTTP_X_FORWARDED'];
  if (!empty($_SERVER['HTTP_X_CLUSTER_CLIENT_IP']) && $this->validate_ip($_SERVER['HTTP_X_CLUSTER_CLIENT_IP']))
   return $_SERVER['HTTP_X_CLUSTER_CLIENT_IP'];
  if (!empty($_SERVER['HTTP_FORWARDED_FOR']) && $this->validate_ip($_SERVER['HTTP_FORWARDED_FOR']))
   return $_SERVER['HTTP_FORWARDED_FOR'];
  if (!empty($_SERVER['HTTP_FORWARDED']) && $this->validate_ip($_SERVER['HTTP_FORWARDED']))
   return $_SERVER['HTTP_FORWARDED'];

  // Return unreliable IP address since all else failed
  return $_SERVER['REMOTE_ADDR'];
 }

 /**
  * Ensures an IP address is both a valid IP address and does not fall within
  * a private network range.
  *
  * @access public
  * @param string $ip
  */
 public function validate_ip($ip) {
     if (filter_var($ip, FILTER_VALIDATE_IP, 
                         FILTER_FLAG_IPV4 | 
                         FILTER_FLAG_IPV6 |
                         FILTER_FLAG_NO_PRIV_RANGE | 
                         FILTER_FLAG_NO_RES_RANGE) === false)
         return false;
     self::$ip = $ip;
     return true;
 }

경고의 말씀 (업데이트)

REMOTE_ADDR여전히 가장 신뢰할 수 있는 IP 주소 소스를 나타냅니다 . $_SERVER여기에 언급 된 다른 변수는 원격 클라이언트가 매우 쉽게 스푸핑 할 수 있습니다. 이 솔루션의 목적은 프록시 뒤에있는 클라이언트의 IP 주소를 확인하는 것입니다. 일반적인 목적을 위해 직접 반환 된 IP 주소와 함께 사용 $_SERVER['REMOTE_ADDR']하고 둘 다 저장하는 것을 고려할 수 있습니다 .

99.9 %의 사용자에게이 솔루션은 귀하의 요구에 완벽하게 부합합니다. 자체 요청 헤더를 삽입하여 시스템을 악용하려는 악의적 인 사용자의 0.1 %로부터 사용자를 보호하지 않습니다. 미션 크리티컬 한 작업을 위해 IP 주소에 의존하는 경우 REMOTE_ADDR프록시 뒤에있는 사용자에게 의존하고 이를 처리하지 마십시오.

알릭스 악셀

다음은 IP 주소를 얻는 더 짧고 깔끔한 방법입니다.

function get_ip_address(){
    foreach (array('HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'REMOTE_ADDR') as $key){
        if (array_key_exists($key, $_SERVER) === true){
            foreach (explode(',', $_SERVER[$key]) as $ip){
                $ip = trim($ip); // just to be safe

                if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) !== false){
                    return $ip;
                }
            }
        }
    }
}

귀하의 코드는 이미 완성 된 것 같습니다. (일반적인 IP 경고를 제외하고) 가능한 버그를 볼 수 없습니다 validate_ip(). 그래도 필터 확장에 의존 하도록 함수를 변경합니다 .

public function validate_ip($ip)
{
    if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) === false)
    {
        return false;
    }

    self::$ip = sprintf('%u', ip2long($ip)); // you seem to want this

    return true;
}

또한 다음에서 HTTP_X_FORWARDED_FOR스 니펫을 단순화 할 수 있습니다.

// check for IPs passing through proxies
if (!empty($_SERVER['HTTP_X_FORWARDED_FOR']))
{
    // check if multiple ips exist in var
    if (strpos($_SERVER['HTTP_X_FORWARDED_FOR'], ',') !== false)
    {
        $iplist = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
        
        foreach ($iplist as $ip)
        {
            if ($this->validate_ip($ip))
                return $ip;
        }
    }
    
    else
    {
        if ($this->validate_ip($_SERVER['HTTP_X_FORWARDED_FOR']))
            return $_SERVER['HTTP_X_FORWARDED_FOR'];
    }
}

이에:

// check for IPs passing through proxies
if (!empty($_SERVER['HTTP_X_FORWARDED_FOR']))
{
    $iplist = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
        
    foreach ($iplist as $ip)
    {
        if ($this->validate_ip($ip))
            return $ip;
    }
}

IPv6 주소의 유효성을 검사 할 수도 있습니다.

이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.

침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제

에서 수정
0

몇 마디 만하겠습니다

0리뷰
로그인참여 후 검토

관련 기사

2017 년에 실제 사용자 IP 주소를 얻는 가장 정확하고 안전한 PHP 방법

복제 된 저장소에서 정의를 확인하는 가장 간단한 방법은 무엇입니까?

Chrome 확장 : PDF 파일에 대한 사용자 정의 UI를 표시하는 방법은 무엇입니까?

Spring Security에서 로그인 한 사용자 정보를 확장하는 방법은 무엇입니까?

Chrome에서 정확한 유니 코드 문자를 검색하는 방법은 무엇입니까?

정확한 셀에서 6 자리 숫자를 모두 검색하는 방법은 무엇입니까?

R의 netcdf에서 래스터를 만드는 가장 정확한 방법은 무엇입니까?

Java8에서 TCP / IP (HTTP가 아님) TLS에 대한 호스트 이름 검사를 사용자 정의하는 방법은 무엇입니까?

문자열 확장에 대한 사용자 정의 초기화를 추가하는 방법은 무엇입니까?

검색 패턴 파일을 사용하여 CSV의 마지막 열에서 정확한 단어를 검색하는 방법은 무엇입니까?

Kotlin의 확장 함수에서 발생한 예외에 대한 사용자 지정 예외 메시지를 제공하는 방법은 무엇입니까?

서버의 적절한 IP 주소를 확인하는 방법은 무엇입니까?

내 웹 사이트에 액세스 한 IP 주소를 확인하는 방법은 무엇입니까?

localstorage (Chrome 확장)에서 검색 할 변수를 정의하는 방법은 무엇입니까?

javaScript RegEx를 사용하여 배열에서 정확하거나 가장 가까운 단어를 검색하는 방법은 무엇입니까?

사용자가 이미 저장한 주소를 확인하는 방법은 무엇입니까?

사용자가 창 크기를 조정 한 경우 창에서 Qt 위젯을 자동으로 확장하는 방법은 무엇입니까?

저장소에서 정확한 패키지 업데이트 만 허용하는 방법은 무엇입니까?

IONIC 서버의 IP 주소를 정의하는 방법은 무엇입니까?

Elasticsearch 정확한 검색을 사용하고 키워드에서 키워드 특수 문자를 무시하는 방법은 무엇입니까?

PHP에서 정규식을 사용하여 정확한 일치를 찾는 방법은 무엇입니까?

C에서 double의 정확한 크기를 보장하는 방법은 무엇입니까?

사용자가 SQL Server의 특정 DB에 대한 쓰기 권한이 있는지 여부를 빠르게 확인하는 방법은 무엇입니까?

net / http.Request.RemoteAddr에서 IP 주소를 얻는 가장 깨끗한 방법은 무엇입니까?

ElasticSearch를 사용하여 문자열 필드에서 정확한 구문을 검색하는 방법은 무엇입니까?

Azure Pipelines를 사용하여 Kubernetes에 대한 자동 크기 조정 (동일한 노드 및 확장 모두)을 설정하는 방법은 무엇입니까?

버전 7.0의 Android 권한 수를 계산하는 가장 정확한 방법은 무엇입니까?

사용자 지정 IP 주소로 Dockernized Django 서버를 시작하는 방법은 무엇입니까?

kibana에서 hybris 사용자 정의 확장 로그를 표시하는 방법은 무엇입니까?

TOP 리스트

  1. 1

    JNDI를 사용하여 Spring Boot에서 다중 데이터 소스 구성

  2. 2

    std :: regex의 일관성없는 동작

  3. 3

    JSoup javax.net.ssl.SSLHandshakeException : <url>과 일치하는 주체 대체 DNS 이름이 없습니다.

  4. 4

    PrematureCloseException : 연결이 너무 일찍 닫혔습니다.

  5. 5

    Xcode10 유효성 검사 : 이미지에 투명성이 없지만 여전히 수락되지 않습니까?

  6. 6

    정점 셰이더에서 카메라에서 개체까지의 XY 거리

  7. 7

    Ionic 2 로더가 적시에 표시되지 않음

  8. 8

    Seaborn에서 축 제목 숨기기

  9. 9

    C #에서 'System.DBNull'형식의 개체를 'System.String'형식으로 캐스팅 할 수 없습니다.

  10. 10

    복사 / 붙여 넣기 비활성화

  11. 11

    ArrayBufferLike의 typescript 정의의 깊은 의미

  12. 12

    Google Play Console에서 '예기치 않은 오류가 발생했습니다. 나중에 다시 시도해주세요. (7100000)'오류를 수정하는 방법은 무엇입니까?

  13. 13

    Kubernetes Horizontal Pod Autoscaler (HPA) 테스트

  14. 14

    jfreecharts에서 x 및 y 축 선을 조정하는 방법

  15. 15

    PRNG 기간보다 순열이 더 많은 목록을 무작위로 섞는 방법은 무엇입니까?

  16. 16

    C # HttpWebRequest 기본 연결이 닫혔습니다. 전송시 예기치 않은 오류가 발생했습니다.

  17. 17

    다음 컨트롤이 추가되었지만 사용할 수 없습니다.

  18. 18

    잘못된 구성 개체입니다. Webpack이 Angular의 API 스키마와 일치하지 않는 구성 개체를 사용하여 초기화되었습니다.

  19. 19

    Android Kotlin은 다른 활동에서 함수를 호출합니다.

  20. 20

    R의 마침표와 숫자 사이에 문자열 삽입

  21. 21

    Assets의 BitmapFactory.decodeStream이 Android 7에서 null을 반환합니다.

뜨겁다태그

보관