티스토리 뷰
서블릿 필터를 이용해서 XSS나 SqlInjection을 어떻게 처리하는지 잘 나와있는 블로그들이 있어 정리해본다.
Filter란?
Servlet 2.3 Specifacation(해당 링크 문서의 챕터 6에 나와있음)에 추가된 대표적인 기능 중 하나가 필터이다.
스펙에는 아래와 같이 설명되어 있다.
A filter is a reusable piece of code that transforms either the content of an HTTP request or response and can also modify header information.
HTTP Request 또는 HTTP Response 내용을 수정할 수 있고, HTTP 헤더 정보 또한 수정할 수 있는 재사용 가능한 코드 조각
그림으로 보면 다음과 같다.
위의 그림에서 보여지듯이, 필터는 HTTP 요청이 서블릿으로 가기 전에 먼저 맞닥뜨리는 놈이다. 한 가지 짚고 넘어가면, Spring MVC의 인터셉터는 HTTP 요청이 DispatcherServlet으로 들어온 후에 처리가 되는 것이고, 필터는 아에 서블릿으로 들어가기 전에 처리되는 것이다.
필터는 아래의 그림과 같이 여러 개를 둘 수 있는데, 이를 필터 체인이라고 부른다.
위와 같이 필터 체인을 구성할 경우, 첫 번째 필터는 클라이언트의 HTTP 요청을 입력 값으로 받지만, 두 번째 필터 이후 부터는 그 전 필터로부터 필터링된 요청 값을 입력 값으로 받는다.
과거에는 이러한 필터를 이용해서 인증(Authentication)과 권한(Authorization)을 체크하는 용도로 많이 사용하였다.
그 뒤로는 필터 대신 Spring 프레임워크의 인터셉터를 이용하는 방식이 많이 사용되었고, 최근에는 OAuth를 이용한 방식을 많이 사용한다.
인증/권한 방식의 변화
필터는 인증/권한 체크 외에도 XSS 방어와 같이 클라이언트의 요청에 대해 필터링이 필요하다면 사용될 수 있다.
필터를 통한 HTTP 요청/응답 값 변환
서블릿으로 요청 값을 전달하기 위해서는 ServletRequest 인터페이스의 구현체를 이용한다. 대개 서블릿으로의 요청은 HTTP 프로토콜을 사용하기 때문에 ServletRequest 인터페이스의 구현체 중 하나인 HttpServletRequest 클래스를 이용한다.
필터는 요청/응답 값을 변경하는게 목적이므로, 변환된 요청/응답 값을 담기 위한 HttpServletRequestWrapper 클래스를 제공한다.
출처: https://pangtrue.tistory.com/249
구현
출처: https://offbyone.tistory.com/32
1. web.xml 에서 필터를 등록합니다. /WEB-INF/web.xml 파일 입니다.
<filter>
<filter-name>firstFilter</filter-name>
<filter-class>com.tistory.pentode.filter.FirstFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>firstFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
필터를 /* 에 맵핑 했습니다.
이것은 필터가 servlet, jsp 뿐만 아니라 모든 자원의 요청에도 호출 된다는 것을 의미합니다.
2. 필터를 정의합니다.
src/main/java/com/tistory/pentode/filter/FirstFilter.java 파일 입니다. 이 필터에서는 하는 작업은 다음과 같습니다.
- 필터 등록시 설정한 초기 파라미터로 POST 요청 데이터의 인코딩을 지정합니다.
- 요청 정보에 대한 추가 처리를 위해 HttpServletRequestWrapper 를 사용하여 HttpServletRequest에서 필요한 메소드를 오버라이딩 합니다.
- 출력되는 응답 정보를 변형하기 위해서 HttpServletResponseWrapper 를 이용하여 출력을 모으는 작업을 합니다.
- (핵심) TestRequestWrapper에 입력파라미터에서 <와>를 제거하는 메소드가 정의되어있습니다.
public class FirstFilter implements Filter {
private static final Logger logger = LoggerFactory.getLogger(FirstFilter.class);
private String encoding;
/**
* init 함수는 컨텍스트 로드시 호출됩니다.
*/
@Override
public void init(FilterConfig config) throws ServletException {
logger.info("init call");
// web.xml 에서 필터 등록시 정의했던 파라미터를 가져옵니다.
this.encoding = config.getInitParameter("encoding");
}
/**
* 필터 실행 부분 입니다.
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// Controller 처리 전에 처리를 수행 하는곳 입니다.
// 파라미터 값으로 POST 데이터의 인코딩을 지정합니다.
request.setCharacterEncoding(this.encoding);
// 요청과 응답에 필요한 처리를 수행할 Wrapper를 생성합니다.
ServletRequest requestWrapper = new TestRequestWrapper((HttpServletRequest) request);
ServletResponse responseWrapper = new TestResponseWrapper((HttpServletResponse) response);
logger.info("before doFilter");
// 다음 필터의 호출, 실제 자원의 처리를 합니다.
chain.doFilter(requestWrapper, responseWrapper);
// 응답에 대한 처리를 하는곳 입니다.
logger.info("after doFilter");
// 응답 래퍼를 이용하여 출력을 모두 대문자로 변형합니다.
if(response.isCommitted() == false) {
response.getWriter().write(responseWrapper.toString().toUpperCase());
}
}
/**
* destroy 는 컨텍스트가 종료될 때 호출됩니다.
*/
@Override
public void destroy() {
logger.info("destroy call");
}
/**
* 요청 래퍼 입니다.
*/
class TestRequestWrapper extends HttpServletRequestWrapper {
public TestRequestWrapper(HttpServletRequest request) {
super(request);
}
/**
* 입력 파라미터에서 <, > 를 제거 합니다.
*/
@Override
public String getParameter(String name) {
String value = super.getParameter(name);
if(value == null) value = "";
return value.replaceAll("[<>]", "");
}
}
/**
* 응답 래퍼 입니다.
*/
class TestResponseWrapper extends HttpServletResponseWrapper {
protected CharArrayWriter charWriter;
public TestResponseWrapper(HttpServletResponse response) {
super(response);
charWriter = new CharArrayWriter();
}
/**
* 출력을 나중에 수정할 수 있도록 모아둡니다.
*/
@Override
public PrintWriter getWriter() throws IOException {
return new PrintWriter(charWriter);
}
@Override
public String toString() {
return charWriter.toString();
}
}
}
- http://localhost:8080/pentode/filter.do?param=<test> 로 요청시, 위의 필터 요청처리-> 자원의처리(컨트롤러)-> 필터 응답처리 순으로 됩니다. 결과적으로 <test>가 test로 변환됩니다.
'FrameWork > Spring' 카테고리의 다른 글
REST API 버전관리 필요성과 그 방법 (0) | 2022.01.22 |
---|---|
ElasticSearch 대신 OpenSearch 사용기, 그리고 예제 (3) | 2021.12.17 |
SQL Injection '처리' 해야될까...? - 1 (0) | 2021.06.24 |
스프링 DL(Dependency Lookup)/DI(Dependency Injection) (0) | 2021.06.22 |
CORS 과정과 처리 (0) | 2021.06.08 |
- Total
- Today
- Yesterday
- 개발중캐시삭제
- 백준퇴사
- 선언적트랜잭션 #noRollbackFor #@Transactional
- script버전
- C++
- 퇴사
- 백준
- C# java 차이점
- 프론트엔드개발자
- 프론트엔드
- c#
- html꿀팁
- 백준14501
- html
- 런타임에러
- 캐시삭제
- boj
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 |