본문 바로가기
Spring/Spring

[Spring] Filter를 이용하여 Request Parameter 조작하기

by J4J 2021. 11. 11.
300x250
반응형

안녕하세요. J4J입니다.

 

이번 포스팅은 filter를 이용하여 request parameter를 조작하는 방법에 대해 적어보는 시간을 가져보려고 합니다.

 

 

 

최근 회사 업무를 수행하다가 클라이언트로부터 전달받은 parameter를 조작해야 되는 상황이 생겼었습니다.

 

대표적인 케이스가 parameter 암호화입니다.

 

보안성을 높이기 위해 클라이언트에서 리소스를 암호화하여 전달하고는 하는데 서버에서 전달받는 리소스마다 복호화하게 될 경우 불필요하고 반복적인 작업이 많아지게 됩니다.

 

이를 보완하고자 request를 조작하는 filter를 등록하여 클라이언트에서는 암호화된 리소스를 전달했지만 스프링의 비즈니스 로직 구간에서 데이터를 전달받았을 땐 복호화가 되어있도록 하여 재사용성을 높이는 방향을 생각하게 되었습니다.

 

 관련된 간단한 설정을 보여드리겠습니다.

 

 

반응형

 

 

Parameter 조작하는 Filter 등록 방법

 

[ 1. Filter 정의 ]

 

package com.spring.rest.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

import com.spring.rest.encryption.AES; // 자체 구현한 AES 복호화 클래스

public class ParamFilter implements Filter {
	
	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		// 초기화할 때 실행
	}
	
	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		
		chain.doFilter(new RequestWrapper((HttpServletRequest)request), response);
	}
	
	private static class RequestWrapper extends HttpServletRequestWrapper {
		
		public RequestWrapper(HttpServletRequest request) {
			super(request);
		}
		
		@Override
		public String[] getParameterValues(String parameter) {
			String values[] = super.getParameterValues(parameter); // 전달받은 parameter 불러오기
			
			if(values == null) {
				return null;
			}
			
			for(int i=0; i<values.length; i++) {
				if(values[i] != null) {
					try {
						values[i] = AES.getInstance().decrypt(values[i]); // parameter 복호화
					} catch(Exception e) {
						e.printStackTrace();
					}
				}
			}
			
			return values;
		}
		
		@Override
		public String getParameter(String parameter) {
			String value = super.getParameter(parameter); // 전달받은 parameter 불러오기
			
			if(value == null) {
				return null;
			}
			
			try {
				value = AES.getInstance().decrypt(value); // parameter 복호화
			} catch(Exception e) {
				e.printStackTrace();
			}
			
			return value;
		}
	}
	
	@Override
	public void destroy() {
		// 종료될 때 실행
	}
}

 

 

 

[ 2. Filter 등록 ]

 

스프링에서는 보통 web.xml에 필터 등록을 하고 스프링부트에서는 자바 설정을 통해 필터를 등록하고는 합니다.

 

어떤 툴을 사용하고 계시는지에 따라 하나만 선택해서 적용해주시면 됩니다.

 

 

 

[ 2-1. 스프링에서 web.xml에 Filter 등록 ]

 

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

	<!-- Param Filter -->
	<filter>
		<filter-name>paramFilter</filter-name>
		<filter-class>com.spring.rest.filter.ParamFilter</filter-class>
	</filter>
	
	<filter-mapping>
		<filter-name>paramFilter</filter-name>
		<url-pattern>/*</url-pattern> <!-- filter 적용 url -->
	</filter-mapping>
</web-app>

 

 

 

[ 2-2. 스프링부트에서 자바 설정으로 Filter 등록 ]

 

package com.spring.rest.config;

import java.util.Arrays;

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.spring.rest.filter.ParamFilter;

@Configuration
public class FilterConfig {
	
	@Bean
	public FilterRegistrationBean<ParamFilter> paramFilter() {
		FilterRegistrationBean<ParamFilter> registrationBean = new FilterRegistrationBean<>(new ParamFilter());
		registrationBean.setUrlPatterns(Arrays.asList("*.do")); // 필터 적용 url
		registrationBean.setOrder(1); // 필터 적용 순서
		
		return registrationBean;
	}
}

 

 

 

 

테스트

 

위의 필터가 정상동작되는지 테스트를 해보겠습니다.

 

테스트는 사용자 request로는 암호화된 name과 age를 전달했을 때 controller에서 데이터를 받아 바로 리턴할 경우 어떤 값이 리턴되는지를 확인해보겠습니다.

 

테스트를 위해 다음과 같이 controller를 구성해보겠습니다.

 

package com.spring.rest.controller;

import java.util.HashMap;
import java.util.Map;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
@CrossOrigin("*")
public class MyController {
	
	@GetMapping("/getData")
	public ResponseEntity<Map<String, Object>> getData(@RequestParam String name, @RequestParam int age) {
		Map<String, Object> resMap = new HashMap<>();
		resMap.put("name", name);
		resMap.put("age", age);
		
		return new ResponseEntity<Map<String,Object>>(resMap, HttpStatus.OK);
	}
}

 

 

 

 

그리고 포스트맨에서 암호화한 데이터를 parameter로 집어넣어 데이터를 전달할 경우 리턴 값을 확인해보겠습니다.

 

실행 결과

 

 

 

암호화가 된 데이터를 전달했지만 리턴값으로는 복호화가 된 것을 확인할 수 있습니다.

 

이렇게 필터를 등록하면 암호화를 하여 데이터를 전달하지 않은 것처럼 코드를 구현할 수 있어서 편리하게 데이터 암복호화를 하여 보안성을 높일 수 있게 됩니다.

 

 

 

 

 

 

 

이상으로 filter를 이용하여 request parameter를 조작하는 방법에 대해 간단하게 알아보는 시간이었습니다.

 

읽어주셔서 감사합니다.

 

 

 

728x90
반응형

댓글