[php] 프록시 서버와 로드 밸런서 환경에서
HTTP_X_FORWARDED_FOR 변수를 활용한 클라이언트 IP 확인
안녕하세요, 개발자 여러분! 오늘은 프록시 서버나 로드 밸런서가 적용된 환경에서 PHP를 사용해 실제 클라이언트의 IP 주소를 안전하고 정확하게 가져오는 방법에 대해 설명해 보겠습니다. 특히 HTTP_X_FORWARDED_FOR 헤더를 활용하는 방법과 주의할 점을 중심으로 자세히 설명드릴게요.
기본적인 IP 주소 가져오기의 문제점
PHP에서 클라이언트의 IP 주소를 가져올 때 흔히 사용하는 방법은 $_SERVER['REMOTE_ADDR'] 변수를 확인하는 것입니다. 이 변수는 요청을 보낸 클라이언트의 IP 주소를 반환해 주는데요, 일반적인 환경에서는 꽤 잘 작동합니다.
$clientIp = $_SERVER['REMOTE_ADDR'];
echo $clientIp; // 예: 192.168.1.1
하지만 프록시 서버나 로드 밸런서(예: NGINX, HAProxy, Cloudflare 등)를 사용하는 환경에서는 이야기가 달라집니다. 이런 경우 REMOTE_ADDR는 실제 클라이언트의 IP가 아니라 프록시 서버나 로드 밸런서의 IP 주소를 반환하게 됩니다. 이는 우리가 원하는 결과가 아니죠. 예를 들어, 실제 사용자의 IP가 203.0.113.10이라도 REMOTE_ADDR는 로드 밸런서의 IP인 10.0.0.1을 보여줄 수 있습니다.
HTTP_X_FORWARDED_FOR 헤더란?
이 문제를 해결하기 위해 등장하는 것이 바로 HTTP_X_FORWARDED_FOR 헤더입니다. 이 헤더는 프록시 서버나 로드 밸런서를 거쳐 요청이 전달될 때, 원래 클라이언트의 IP 주소를 기록해 전달하는 역할을 합니다. $_SERVER['HTTP_X_FORWARDED_FOR']를 통해 이 값을 PHP에서 확인할 수 있습니다.
예를 들어, 클라이언트가 프록시를 통해 요청을 보내면 헤더는 다음과 같이 보일 수 있습니다:
X-Forwarded-For: 203.0.113.10, 10.0.0.1 |
여기서 첫 번째 IP(203.0.113.10)가 실제 클라이언트의 IP이고, 그 뒤에 나오는 IP(10.0.0.1)는 프록시 서버의 IP입니다.
실제 클라이언트 IP 가져오는 코드
이제 HTTP_X_FORWARDED_FOR를 활용해 클라이언트 IP를 가져오는 방법을 코드로 구현해 보겠습니다. 단순히 값을 바로 가져오는 것뿐만 아니라, 안전성을 고려한 처리도 추가해야 합니다.
function getClientIp() {
// HTTP_X_FORWARDED_FOR가 존재하는지 확인
if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
// 여러 IP가 있을 수 있으므로 쉼표로 분리
$ipList = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
// 첫 번째 IP가 실제 클라이언트 IP
$clientIp = trim($ipList[0]);
} else {
// 프록시가 없는 경우 REMOTE_ADDR 사용
$clientIp = $_SERVER['REMOTE_ADDR'];
}
return $clientIp;
}
// 사용 예시
$ip = getClientIp();
echo "클라이언트 IP: " . $ip;
위 코드의 동작 로직은 다음과 같습니다.
HTTP_X_FORWARDED_FOR가 존재하면 그 값을 우선 사용합니다.
여러 IP가 쉼표로 구분되어 있을 수 있으니, explode로 분리해 첫 번째 IP를 가져옵니다.
헤더가 없으면 기본적으로 REMOTE_ADDR를 반환합니다.
주의할 점
이 방법은 강력하지만 몇 가지 주의할 점이 있습니다.
1. 헤더 신뢰성 문제
HTTP_X_FORWARDED_FOR는 클라이언트나 악의적인 프록시가 조작할 수 있는 값입니다. 따라서 이 값을 맹신하기보다는 서버 설정에서 프록시가 제대로 구성되었는지 확인해야 합니다. 예를 들어, 신뢰할 수 있는 프록시나 로드 밸런서만 이 헤더를 추가하도록 제한하는 것이 좋습니다.
2. 값이 비어 있을 경우
모든 환경에서 HTTP_X_FORWARDED_FOR가 전달되지 않을 수 있으니, 대체 값으로 REMOTE_ADDR를 사용하는 로직이 필수입니다.
3. IP 유효성 검사
가져온 IP가 실제 유효한 형식인지 추가로 확인하는 것도 좋은 습관입니다. 아래는 이를 위한 간단한 예제입니다.
function getClientIp() {
if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$ipList = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
$clientIp = trim($ipList[0]);
// IP 형식 유효성 검사
if (filter_var($clientIp, FILTER_VALIDATE_IP)) {
return $clientIp;
}
}
// 유효하지 않으면 REMOTE_ADDR로 대체
return filter_var($_SERVER['REMOTE_ADDR'], FILTER_VALIDATE_IP) ? $_SERVER['REMOTE_ADDR'] : 'Unknown';
}
실무에서의 활용
이 코드는 로깅, 사용자 추적, 보안 정책 적용 등 다양한 상황에서 유용합니다. 예를 들어, 특정 IP에서 비정상적인 요청이 감지되면 차단하거나, 지역별 접속 통계를 낼 때도 활용할 수 있죠. 단, 개인정보 보호법을 준수하기 위해 IP 주소를 수집할 때는 사용자의 동의를 받는 등 법적 요건도 잊지 말아야 합니다.
궁금한 점이 있거나 더 좋은 방법이 있다면 댓글로 공유해 주세요! 다음 포스트에서 또 유용한 팁으로 찾아뵙겠습니다. Happy coding!
그래도 실제 클라이언트의 IP가 안나온다면?
위의 방법대로 조치해도 프록시서버나 로드밸런서단의 IP가 나온다면 Apache의 apache2.conf 파일에서 X-Forwarded-For 속성을 추가하면 됩니다.
필자의 경우 apache2.conf 파일의 경로는 /etc/apache2/apache2.conf 입니다.
서버에 접속 후 아래와 같이 명령어를 써 주면 apache2.conf 파일의 내용을 편집할 수 있습니다.
(vim의 사용법은 별도로 확인해 주세요.)
sudo vim /etc/apache2/apache2.conf
위 명령어를 실행하면 아래와 같은 내용이 나옵니다.
LogFormat "%v:%p %h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined
LogFormat "%{X-Forwarded-For}i %h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %O" common
LogFormat "%{Referer}i -> %U" referer
LogFormat "%{User-agent}i" agent
여기에서
LogFormat "%{X-Forwarded-For}i %h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
이 빨간 부분은 주목해 주세요.
앞 부분에 %{X-Forwarded-For}i 가 추가된 부분입니다.
이렇게 하면 X-Forwarded-For 속성을 사용할 수 있게 됩니다.
'vita_Linux' 카테고리의 다른 글
[PHP] require 함수의 경로 설정 방법 (0) | 2024.11.22 |
---|---|
[Linux] Ubuntu 서버 내의 특정 PHP 파일을 서비스로 실행하기 (0) | 2024.11.21 |
[Linux] Apach php 한국시간으로 변경하기 (0) | 2024.11.21 |
[Mariadb] HeidiSQL에서 AWS RDS mariadb에 접속이 되지 않아요 (1) | 2024.11.20 |
[Linux] Ubuntu 우분투에 아파치2 설치하기 (1) | 2024.11.18 |