ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [스프링] 사용자 IP를 추적하는 방법
    스프링(Spring) 2023. 7. 22. 22:14

     

    특정 글을 작성한 사용자의 IP는 어떻게 추적하는 걸까 의문이 들었다. 이에 대한 여러 방법이 있겠지만 스프링을 사용해야하는

    나로서는 우선 스프링을 기준으로 조사해보기로 결정했다.

     

    가장 간편하게 Chat GPT에게 질문했다.

    게시판 사이트를 만들 때 게시글을 수정했거나 등록한 사용자의 ip를 추적해 MySQL에 기록하려고 해. 스프링을 사용할 예정인데 이럴 때는 어떻게 ip 추적을 구현할 수 있을까?

     

    GPT는 다음과 같은 코드를 예시로 들어줬다.

     

    import org.springframework.web.bind.annotation.*;
    import javax.servlet.http.HttpServletRequest;
    
    @RestController
    public class BoardController {
    
        @PostMapping("/write")
        public String writePost(@RequestBody String postContent, HttpServletRequest request) {
            String clientIp = getClientIp(request);
            
            // 게시글 등록 로직 및 IP 주소 기록 처리
            // ...
            
            return "Post created successfully";
        }
    
        @PutMapping("/edit/{postId}")
        public String editPost(@PathVariable Long postId, @RequestBody String updatedContent, HttpServletRequest request) {
            String clientIp = getClientIp(request);
            
            // 게시글 수정 로직 및 IP 주소 기록 처리
            // ...
            
            return "Post updated successfully";
        }
    
        // HttpServletRequest를 통해 클라이언트의 IP 주소를 추출하는 메서드
        private String getClientIp(HttpServletRequest request) {
            String ipAddress = request.getHeader("X-Forwarded-For");
            if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) {
                ipAddress = request.getHeader("Proxy-Client-IP");
            }
            if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) {
                ipAddress = request.getHeader("WL-Proxy-Client-IP");
            }
            if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) {
                ipAddress = request.getHeader("HTTP_CLIENT_IP");
            }
            if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) {
                ipAddress = request.getHeader("HTTP_X_FORWARDED_FOR");
            }
            if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) {
                ipAddress = request.getRemoteAddr();
            }
            
            return ipAddress;
        }
    }

    코드를 보면 request의 header내 요소들을 이용하는 것 같은데 각각이 어떤 요소인지 살펴보겠다.

    <X-Forwarded-For>

    MDN 공식 문서에 따르면 다음과 같다.

    The X-Forwarded-For (XFF) request header is a de-facto standard header for identifying the originating IP address of a client connecting to a web server through a proxy server.

    "The X-Forwarded-For (XFF) request header는 프록시 서버를 통해 웹서버에 접근하려는 클라이언트가 기반으로 두고 있는 IP주소를 식별하기 위한 실질적인 표준 헤더이다." 정도로 번역이 가능할 거 같다. (쉽게 말해 IP가 어디 것인지 식별하기 위한 용도다)

     

    When a client connects directly to a server, the client's IP address is sent to the server (and is often written to server access logs). But if a client connection passes through any forward or reverse proxies, the server only sees the final proxy's IP address, which is often of little use. That's especially true if the final proxy is a load balancer which is part of the same installation as the server. So, to provide a more-useful client IP address to the server, the X-Forwarded-For request header is used.

    요약하면 클라이언트가 서버에 접근하면 서버에게 IP 주소가 전달되는데 클라이언트가 포워드나 리버스 프록시를 쓴 경우라면 서버 측에서는 최종 프록시의 IP만 보게 된다는 것.

    따라서 클라이언트의 IP를 보기 위해 X-Forwarded-For 요청 헤더가 사용된다.

     

    //X-Forwarded-For 요소
    X-Forwarded-For: <client>, <proxy1>, <proxy2>

     

    가장 오른쪽에 있는 것일 수록 최근에 사용된 프록시이며 가장 왼쪽에 있는 것이 클라이언트의 IP주소라고 한다.

     

    X-Forwared-For를 제외한 다음 것들은 다른 종류의 헤더인 것들로 보인다.

    <Proxy-Client-IP, WL-Proxy-Client-IP>

    WebLogic Connector(mod_wl)에서 사용되는 종류의 헤더들

    <HTTP_CLIENT_IP, HTTP_X_FORWARDED_FOR>

    PHP나 ASP에서 실제 Client IP를 구할 때 사용하는 헤더들

    <getRemoteAddr()>

    오라클 공식 문서에 따르면 java.lang.String클래스의 하위 메서드로서 요청을 보낸 클라이언트나 가장 마지막에 위치한 프록시의 IP 주소를 반환해준다고 한다. 또한 이러한 말도 있다.

    For HTTP servlets, same as the value of the CGI variable REMOTE_ADDR.

    [여기서 CGI(Common Gateway Interface)란?]

    서로 다른 프로토콜을 연동시키는 소프트웨어 게이트웨이의 표준안,

    웹이 없던 시절의 사람들이 사용하던 FTP, Mail과 같은 다른 프로토콜을 웹을 통해 제공받길 원했는데

    웹은 HTTP(HyperText Transfer Protocol)라는 프로토콜을 이용하고 있었다. (프로토콜: 데이터를 주고 받는 통신규약)

    그래서 서로 다른 프로토콜을 변환해야했는데 (HTTP를 다른 프로토콜로, 다른 프로토콜을 HTTP로) 이렇게

    서로 다른 프로토콜을 연동하는 역할을 하는 것을 '소프트웨어 게이트웨이'라고 하며 이것의 표준안을 CGI라고 하는 것이다.

     

     

    그리하여 결론,

    위와 같은 코드를 사용하면 기본적으로 스프링에서 IP를 추적할 수 있는 것이다! 빠밤 :)

     

     

    출처:

    Chat GPT

    https://qaos.com/sections.php?op=viewarticle&artid=194 

    https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For

    https://www.lesstif.com/software-architect/proxy-client-ip-x-forwarded-for-xff-http-header-20775886.html

    https://it-study.tistory.com/37

    https://docs.oracle.com/javaee/6/api/javax/servlet/ServletRequest.html

    '스프링(Spring)' 카테고리의 다른 글

    트위터 소셜로그인 API 2.0 연동하기  (2) 2023.09.20
Designed by Tistory.