개발 메모장

[Java] 공공데이터 - IP 확인 API 사용하기 본문

Java

[Java] 공공데이터 - IP 확인 API 사용하기

yyyyMMdd 2025. 3. 6. 15:34
728x90

#. 보안과 관련하여 해외에서 접속하는 IP에 대한 점검을 해야할 필요성을 느꼈습니다.


#. 해외 IP를 확인하는 방법은 외부 라이브러리, 정부 제공 API 등 처리방법이 있습니다.


#. 서비스 중인 프로젝트는 특정된 대상만이 사용하도록 되어있기에 더더욱 해외에서 접속할 일은 없기 때문에 아래와 같이 정부 제공 API를 적용하였습니다.


#. 이는 일일 트래픽 10,000건까지만 제공하므로 더 필요한 경우 웹사이트에 따라 증가시키길 바랍니다.


#. API 사용하기

 

  • 참고문서를 다운받아 필요한 내용에 대한 API URL을 확인합니다.

  • 아래와 같이 목록에서 원하는 내용을 선택한 뒤 활용신청 버튼을 눌러 API KEY를 발급받습니다.

 

  • 요청하는 값을 넣어 처리해보면 아래와 같이 데이터를 리턴 받습니다.


#. 구현하기 - Java Script

 

  • 처음엔 HttpServletRequest > getRemoteAddr 메서드를 이용해 보았으나 내부 IP를 사용하는 경우 국가코드가 해외로 확인되는 경우가 있었습니다.

  • 정확한 확인을 위해선 공인 IP를 호출하여 체크 해야 했고 아래와 같이 구현하였습니다.

  • 자바스크립트를 이용해 공인IP 확인이 가능한 url을 Fetch에 넣어 값을 응답받고 핸들러로 보내 처리하는 방법입니다.

  • 접속 시 공인 IP를 확인할 수 있는 웹사이트를 참고하시길 바랍니다.
function fetchPublicIPAndSubmit() {
	fetch('https://checkip.amazonaws.com') //https://api64.ipify.org
		.then(response => response.text())
		.then(ip => {
			ip = ip.trim();

			if ($('#client_ip').length === 0) {
				$('<input>').attr({
					type: 'hidden',
					id: 'client_ip',
					name: 'client_ip',
					value: ip
				}).appendTo('form');
			} else {
				$('#client_ip').val(ip);
			}
		})
		.catch(error => {
			console.error('IP 호출 실패 : ', error);
		})
		.finally(() => {
			// IP 호출 실패해도 로그인 폼 제출 진행
			submitLoginForm();
		});
}

function submitLoginForm() {
	var url = '<c:out value="${url}" />';
	$("form").attr("action", url);
	$("form").submit();
}

 

- 해당 웹사이트로 연결해서 응답을 받고 그 값을 hidden 태그에 넣어 form을 보낼 때 함께 보내는 방법입니다.


#. 구현하기 - Handler

 

  • 로그인 페이지에서 아래와 같이 AuthenticationSuccessHandler를 상속받아 처리하는 메서드를 만들어줍니다.

  • NONE을 KR과 함께 넣은 이유는 127.0.0.1이나 가상IP의 경우 국가코드가 NONE으로 나오기 때문에 그렇습니다.

  • 분기에 통과되지 못하면 로그를 만드는 메서드로 넘어가 로그파일을 떨구는 방식으로 만들었으니 해당 부분은 원하는 방법에 맞게 처리하시면 됩니다. (로그 생성, 로그파일 만들기, 첫 페이지로 이동 등)
public class LoginSuccessHandler implements AuthenticationSuccessHandler {
	public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
            Authentication authentication) throws IOException, ServletException {
			
		String publicIp = request.getParameter("client_ip");
		ipChecker(publicIp);
	}
	
	private void ipChecker(String ip) throws IOException {
    	User user = SecurityUtils.getUser();
    	
    	StringBuilder urlBuilder = new StringBuilder("http://apis.data.go.kr/B551505/whois/ip_address"); // URL
        urlBuilder.append("?" + URLEncoder.encode("serviceKey","UTF-8") + "발급받은 키");
        urlBuilder.append("&" + URLEncoder.encode("query","UTF-8") + "=" + ip); 
        urlBuilder.append("&" + URLEncoder.encode("answer","UTF-8") + "=" + URLEncoder.encode("json", "UTF-8")); // 응답형식(XML/JSON) 을 지정(없으면 XML으로 응답)
        
        URL url = new URL(urlBuilder.toString());
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod("GET");
        conn.setRequestProperty("Content-type", "application/json");
        BufferedReader rd;
        
        if(conn.getResponseCode() >= 200 && conn.getResponseCode() <= 300) {
            rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
        } else {
            rd = new BufferedReader(new InputStreamReader(conn.getErrorStream()));
            System.out.println("API 호출 실패 (응답 코드: " + conn.getResponseCode() + ")");
            return;
        }
        
        StringBuilder sb = new StringBuilder();
        String line;
        
        while ((line = rd.readLine()) != null) {
            sb.append(line);
        }
        rd.close();
        conn.disconnect();

        try {
        	JSONParser parser = new JSONParser();
        	JSONObject jsonObj = (JSONObject) parser.parse(sb.toString());
        	JSONObject response = (JSONObject) jsonObj.get("response");
        	JSONObject whoIs = (JSONObject) response.get("whois");
        	
        	String countryCode = (String) whoIs.get("countryCode");
        	
        	if(!"KR".equals(countryCode) && !"NONE".equals(countryCode)) {
        		CreateLogFile.createLog(user.getUserId(), "strange_IP", "");
        	}
        } catch (Exception e) {
		e.printStackTrace();
	}
    }
}

#. 로그 파일을 생성하는 메서드를 통해 아래와 같이 생성된 것을 확인할 수 있습니다.

 

 

===========================================================
틀린 내용이 있거나 이견 있으시면 언제든 가감 없이 말씀 부탁드립니다!

참조 : https://www.data.go.kr/data/15094277/openapi.do

===========================================================

728x90