PHP 및 그누보드 환경에서 프록시·CDN 고려한 클라이언트 실제 IP 추출 방법
페이지 정보

본문
프록시 서버나 클라우드플레어(CloudFlare) 환경에서 $SERVER['REMOTEADDR']가 실제 IP 대신 중간 서버 IP를 반환할 때, 실제 방문자 IP를 정확히 식별하고 그누보드 콘텐츠 및 관리자 권한을 제어하는 방법을 안내합니다.
프록시 환경에서 $_SERVER['REMOTE_ADDR']가 실제 IP를 가져오지 못하는 이유
PHP에서 클라이언트의 IP 주소를 확인할 때 흔히 사용하는 $_SERVER['REMOTE_ADDR']는 TCP/IP 레벨에서 요청을 보낸 직접적인 연결 주소를 반환합니다. 일반적인 직접 접속 환경에서는 정상적으로 동작하지만, 프록시 서버나 로드 밸런서(예: NGINX, HAProxy, Cloudflare 등)가 앞단에 배치된 구조에서는 웹 서버가 클라이언트와 직접 통신하지 않고 중간 서버를 거쳐 요청을 받게 됩니다.
이로 인해 $_SERVER['REMOTE_ADDR']는 실제 방문자의 IP 주소가 아니라 요청을 전달한 프록시 서버나 로드 밸런서의 내부 IP 주소를 반환하게 됩니다. 따라서 프록시 환경에서 실제 방문자의 IP를 정확히 식별하려면 HTTP_X_FORWARDED_FOR나 HTTP_CF_CONNECTING_IP 같은 별도의 HTTP 헤더를 함께 확인해야 합니다.
프록시 환경에서 실제 클라이언트 IP 추출 방법
PHP 환경에서 프록시 서버, 로드 밸런서, CDN(예: CloudFlare) 등을 경유하는 경우, 기본 변수인 $_SERVER['REMOTE_ADDR']를 사용하면 방문자의 실제 IP가 아닌 중간 프록시 서버의 IP 주소가 조회됩니다. 이를 해결하기 위해 HTTP_CLIENT_IP, HTTP_X_FORWARDED_FOR 등의 헤더를 우선순위별로 확인하여 실제 클라이언트 IP를 추출할 수 있습니다.
1. 우선순위 로직을 적용한 IP 추출 패턴
다양한 서버 환경과 프록시 헤더를 검사하여 실제 IP를 확보하는 기본적인 PHP 코드 구현 방식은 다음과 같습니다.
function getUserIP() {
// CloudFlare 환경을 사용하는 경우 CF-Connecting-IP 반영 가능
if (isset($_SERVER["HTTP_CF_CONNECTING_IP"])) {
$_SERVER['REMOTE_ADDR'] = $_SERVER["HTTP_CF_CONNECTING_IP"];
$_SERVER['HTTP_CLIENT_IP'] = $_SERVER["HTTP_CF_CONNECTING_IP"];
}
$client = @$_SERVER['HTTP_CLIENT_IP'];
$forward = @$_SERVER['HTTP_X_FORWARDED_FOR'];
$remote = $_SERVER['REMOTE_ADDR'];
if (filter_var($client, FILTER_VALIDATE_IP)) {
$ip = $client;
} elseif (filter_var($forward, FILTER_VALIDATE_IP)) {
$ip = $forward;
} else {
$ip = $remote;
}
return $ip;
}
또한 간단한 조건문이나 삼항 연산자를 활용하여 순차적으로 값을 확인할 수 있습니다.
$client_ip = isset($_SERVER['HTTP_CLIENT_IP'])? $_SERVER['HTTP_CLIENT_IP']: (isset($_SERVER['HTTP_X_FORWARDED_FOR'])? $_SERVER['HTTP_X_FORWARDED_FOR']: $_SERVER['REMOTE_ADDR']);
2. 콤마(,)로 구분된 다중 IP 처리
HTTP_X_FORWARDED_FOR 헤더에는 프록시 체인을 거치면서 여러 개의 IP가 콤마(,)로 구분되어 담길 수 있습니다. (예: 203.0.113.10, 10.0.0.1)
이 경우 목록 중 첫 번째 값이 실제 클라이언트의 IP이므로, 다음과 같이 분리하여 처리해야 합니다.
if (count(explode(',', $client_ip)) == 2) {
$ip0 = explode(',', $client_ip);
$client_ip = $ip0[0];
}
3. 적용 시 주의사항
- 사용자가 사용하는 특정 프록시 서버의 헤더 설정이나 네트워크 구성에 따라 추출 로직이 달라질 수 있습니다.
- 프록시 환경에서 단순히
REMOTE_ADDR만 사용할 경우 서버 IP나 프록시 IP가 수집되므로, 관리자 접근 제어 및 방문자 로그 기록 시 위와 같은 우선순위 로직을 적용해야 합니다.
HTTPXFORWARDED_FOR 헤더의 콤마 구분자 IP 분리 방법
프록시 서버나 로드 밸런서, CDN 환경을 거치며 요청이 전달될 때 HTTP_X_FORWARDED_FOR 헤더에는 여러 개의 IP 주소가 콤마(,)로 나열되어 포함될 수 있습니다. 이 경우 첫 번째로 나오는 IP가 실제 클라이언트의 IP이며, 그 뒤에 나오는 IP들은 경유한 프록시 서버들의 IP입니다.
콤마 구분자 처리 및 첫 번째 IP 추출 로직
여러 IP가 쉼표로 구분되어 있을 때 explode 함수를 사용하여 첫 번째 실제 클라이언트 IP를 정확히 분리할 수 있습니다.
$client_ip = isset($_SERVER['HTTP_CLIENT_IP'])? $_SERVER['HTTP_CLIENT_IP']: (isset($_SERVER['HTTP_X_FORWARDED_FOR'])? $_SERVER['HTTP_X_FORWARDED_FOR']: $_SERVER['REMOTE_ADDR']);
if (count(explode(',', $client_ip)) == 2) {
$ip0 = explode(',', $client_ip);
$client_ip = $ip0[0];
}
또한 문자열 내에 콤마가 포함되어 있는지 확인하고 분할하는 반복문 기반의 정제 처리 예시는 다음과 같습니다.
if (strpos($_SERVER['HTTP_X_FORWARDED_FOR'], ',')!== false) {
$iplist = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
foreach ($iplist as $ip) {
if (validate_ip($ip)) {
return $ip;
}
}
}
주의 사항 및 다음 행동
HTTP_X_FORWARDED_FOR헤더는 클라이언트가 임의로 조작할 수 있는 HTTP 헤더이므로, 헤더 값이 설정된 위치와 방식을 신뢰할 수 있는 환경인지 먼저 확인해야 합니다.- 프록시 서버의 설정이나 구성에 따라 추출 로직이 달라질 수 있으므로 적용 후 실제 접속 IP와 일치하는지 확인하는 검증 단계를 거쳐야 합니다.
CloudFlare 및 프록시 환경에서 실제 클라이언트 IP 추출 방법
클라우드플레어(CloudFlare) CDN이나 프록시 서버, 로드 밸런서를 경유하는 환경에서는 PHP의 기본 변수인 $_SERVER['REMOTE_ADDR']를 사용할 경우 실제 방문자의 IP가 아닌 프록시 서버의 IP 주소가 반환됩니다. 이를 해결하기 위해 표준이 아닌 전용 헤더와 우선순위 로직을 적용해야 합니다.
1. CloudFlare 및 프록시 환경의 IP 추출 원리
- CloudFlare 환경: 클라우드플레어는 실제 방문자 IP를 전달하기 위해
HTTP_CF_CONNECTING_IP헤더를 제공합니다. - 프록시 및 로드 밸런서 환경: 프록시 체인을 통과할 때 원래 클라이언트 IP를 기록하는
HTTP_X_FORWARDED_FOR헤더를 활용합니다. 이 헤더는 콤마(,)로 여러 IP가 구분되어 전달될 수 있으며, 첫 번째 값이 실제 클라이언트의 IP입니다.
2. 실제 IP 추출을 위한 PHP 코드 구현 패턴
getUserIP() 함수를 구현하여 클라우드플레어 전용 헤더(HTTP_CF_CONNECTING_IP)와 프록시 헤더를 순서대로 검증하고 필터링할 수 있습니다.
function getUserIP() {
// Get real visitor IP behind CloudFlare network
if (isset($_SERVER["HTTP_CF_CONNECTING_IP"])) {
$_SERVER['REMOTE_ADDR'] = $_SERVER["HTTP_CF_CONNECTING_IP"];
$_SERVER['HTTP_CLIENT_IP'] = $_SERVER["HTTP_CF_CONNECTING_IP"];
}
$client = @$_SERVER['HTTP_CLIENT_IP'];
$forward = @$_SERVER['HTTP_X_FORWARDED_FOR'];
$remote = $_SERVER['REMOTE_ADDR'];
if (filter_var($client, FILTER_VALIDATE_IP)) {
$ip = $client;
} elseif (filter_var($forward, FILTER_VALIDATE_IP)) {
$ip = $forward;
} else {
$ip = $remote;
}
return $ip;
}
$ip4 = getUserIP();
또한 콤마로 구분된 HTTP_X_FORWARDED_FOR 값을 처리할 때는 아래와 같이 첫 번째 IP를 분리하여 정확한 값을 확보할 수 있습니다.
$client_ip = isset($_SERVER['HTTP_CLIENT_IP'])? $_SERVER['HTTP_CLIENT_IP']: (isset($_SERVER['HTTP_X_FORWARDED_FOR'])? $_SERVER['HTTP_X_FORWARDED_FOR']: $_SERVER['REMOTE_ADDR']);
if (count(explode(',', $client_ip)) == 2) {
$ip0 = explode(',', $client_ip);
$client_ip = $ip0[0];
}
3. 적용 시 주의사항
- 사용자가 사용하는 특정 프록시 서버의 헤더 설정에 따라 추출 로직이 달라질 수 있습니다.
- 프록시 헤더(
X-Forwarded-For등)는 임의로 조작될 수 있는 값이므로, 신뢰할 수 있는 프록시 및 CDN 환경에서만 사용하는 것이 안전합니다.
그누보드에서 실제 클라이언트 IP 기반 콘텐츠 접근 제어 방법
프록시 서버나 CDN(예: 클라우드플레어) 환경에서는 기본 서버 변수인 $_SERVER['REMOTE_ADDR']가 실제 방문자의 IP가 아닌 프록시 서버의 IP를 반환합니다. 따라서 올바른 IP 추출 로직을 거친 뒤 관리자 권한 및 특정 IP 조건을 결합하여 콘텐츠를 제어해야 합니다.
1. 실제 클라이언트 IP 추출하기
프록시 환경에서는 HTTP_X_FORWARDED_FOR 헤더를 확인해야 하며, 콤마(,)로 여러 IP가 구분되어 전달될 경우 첫 번째 값을 실제 클라이언트 IP로 사용합니다.
<?php
// HTTP_X_FORWARDED_FOR 헤더를 쉼표로 분리하여 첫 번째 IP 추출
if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$ipList = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
$client_ip = trim($ipList[0]);
} else {
$client_ip = $_SERVER['REMOTE_ADDR'];
}
?>
2. 그누보드에서 관리자 및 특정 IP 조건에 따른 콘텐츠 제어 예시
추출한 $client_ip 변수와 그누보드의 관리자 판별 변수($is_admin), 회원 정보($member['mb_id'])를 조건문으로 조합하여 특정 사용자에게만 콘텐츠를 노출하거나 제한할 수 있습니다.
<?php
// 특정 IP, 최고/부관리자 여부, 특정 회원 아이디 조건을 모두 만족할 때 콘텐츠 제어
if ($client_ip == "허용할_IP" && $is_admin && $member['mb_id'] == '특정회원') {
echo "관리자 전용 콘텐츠입니다.";
}
?>
상황별 IP 추출 및 제어 판단 기준
| 내 상황 | 우선할 판단 | 다음 행동 |
|---|---|---|
프록시나 로드밸런서를 거쳐 접속 시 REMOTE_ADDR가 내부 IP로 조회되는 경우 | HTTP_X_FORWARDED_FOR 헤더의 우선순위 검사 적용 | 콤마(,) 구분자를 분리하여 첫 번째 IP를 추출하는 로직 구현 |
| 클라우드플레어(CloudFlare) CDN을 적용하여 방문자 IP가 가려지는 경우 | HTTP_CF_CONNECTING_IP 헤더 존재 여부 확인 및 최우선 반영 | 전용 헤더 값을 $_SERVER['REMOTE_ADDR']에 덮어쓰거나 별도 함수로 격리 |
| 그누보드에서 특정 IP 및 관리자 권한에 따라 콘텐츠 제어를 수행하려는 경우 | 확보한 실제 클라이언트 IP 변수와 $is_admin, $member['mb_id'] 조건 조합 | 조건문 검증 로직을 거쳐 접근 제어 및 방문자 기록 기능 연동 |
실전 FAQ
Q. HTTP_X_FORWARDED_FOR 헤더 값에 여러 IP가 콤마로 섞여 있을 때 실제 사용자 IP를 어떻게 확정하나요?
- 답변: 프록시 체인을 거치며 누적된 IP 목록 중 가장 첫 번째에 위치한 IP가 최초 요청을 보낸 실제 클라이언트의 IP입니다.
explode(',', $client_ip)를 통해 배열로 분할한 뒤 첫 번째 인덱스 값([0])을 가져와야 합니다.
Q. 클라우드플레어 환경에서 그누보드 접속자 로그나 관리자 IP 검증이 정상 동작하지 않을 때 대안은 무엇인가요?
- 답변: 클라우드플레어는 표준 헤더 대신
HTTP_CF_CONNECTING_IP를 통해 실제 IP를 전달합니다.common.php상단 또는 별도 클래스 구조를 통해 해당 헤더 값을 기본 서버 변수에 반영하는 전처리 로직을 추가하여 해결할 수 있습니다.
참고자료
기타 참고자료
- phpinfo.kr — PHP - 실제 클라이언트 IP주소 가져오기
- esmartbay.tistory.com — PHP로 클라이언트 IP 정확하게 추출하고 사용자 위치 분석하기
- lemonvita.tistory.com — php HTTPXFORWARDED_FOR 변수를 활용한 클라이언트 IP 확인 방법
- copysource.tistory.com — PHP에서 클라이언트 IP 주소를 가져오는 방법
- sir.kr — CloudFlare 사용시 실제 방문자 IP 및 SSL 사용 여부 파악 - SIR - 개발자 커뮤니티
- sir.kr — CloudFlare 사용시 방문자 IP와 SSL 접속여부 파악하기 - SIR - 개발자 커뮤니티
- hoai.tistory.com — 클라우드 플레어를 사용중인 호스트에서 클라이언트의 ip주소를 알수없나
- aroma-bok.tistory.com — Spring 로그인 시 사용자 IP 정확히 가져오는 방법 (getRemoteAddr vs X-Forwarded-For)
- itmore.tistory.com — JSP X-Forwarded-For 과 getRemoteAddr()차이 :: IT모아
- 이전글웹호스팅 환경별 phpMyAdmin 접속 경로 및 관리 도구 확인 방법 26.09.28
- 다음글PHP urlencode와 rawurlencode 함수의 차이점과 그누보드 적용 가이드 26.09.28
댓글목록
등록된 댓글이 없습니다.