웹 : D.F.P으로 필터 만들어보기 : 0331
필터를 적용해보자.
필터는 2버전 3버전 모두 있어서 갈아 끼울 수 있어야한다. 액세서리라고 부르며 데코레이팅 필터 P는 뭐지
암튼 이걸이용하여 보자
필터역할
1. controller기준 전처리 작업(63/66라인 없애기)
2. 보안처리 (인증과 인가 기반의 접근제어 auth)
cross site script 공격 막아보자.
필터를 거쳐도 요청의 일부 성질들이 변경될 뿐 요청은 그대로 유지된다. 요청의 정보도 변경할 수 있지만 그에 맞는 응답결과도 알맞게 변경할 수 있다. << 필터 : 요청과 응답에 대한 전, 후 처리 작업 >>
필터는 액세서리이기 때문에 여러개를 걸수도 있다.
이 여러개의 필터를 묶어서 FilterChain을 형성하여 사슬처럼 엮어 사용한다. 사슬은 순서를 바꾸지 못한다. 순서고정. 요청과 응답의 필터 처리 순서는 역순이다. stack메모리 구조 때문. FILO
필터 사용 이유 : 흐름을 변경하는 역할, 사용자 인증이나 권한체크와 같은 기능 구현 (인증 auth)
필터 생성 방법
자바x servlet의 filter(필터 최상위 객체)를 구현한다.
생성해보면 init과 destroy 메서드가 생성된다. > 서블릿의 형태이다. > 톰캣과 대화한다. > 등록한다.
톰캣에 등록할 때 필터 체인이 형성된다.
- Authentication Filters - 인증
- Logging and Auditing Filters - Log를 이곳에만 남겨서 어플리케이션은 가지지 않도록 할수있다.
- Image conversion Filters - 이미지를 사용용도에 맞게 알아서 변환해주는 것
- Data compression Filters - 요청뿐아니라 응답할때 압축하여 응답의 크기를 줄여 보낼 수 있다.
- Encryption Filters - 암호화 (공통키 : 양쪽이 공통적으로 약속한 키)
- Tokenizing Filters -
- Filters that trigger resource access events
- XSL/T filters
- Mime-type chain Filter
필터도 싱글턴으로 관리된다.
여기에 있는 라이프사이클 메서드도 한번만 실행된다. 라이프 사이클에서 로그 기록햇음
▶FirstFilter
package kr.or.ddit.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 org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import lombok.extern.slf4j.Slf4j;
@Slf4j //롬복에서 지원하는 어노테이션
public class FirstFilter implements Filter {
//어펜더, 로거 레이아웃
//퍼사드 구조
// private Logger log = LoggerFactory.getLogger(FirstFilter.class);
@Override
public void init(FilterConfig filterConfig) throws ServletException {
//debug는 사용 못하므로 info이상의 레벨의 로거를 사용해야함.
log.info("{} 필터가 로딩됨.", this.getClass().getSimpleName()); //메세지 아귀먼트 {}
//어떤 필터가 로딩됐는지 알 수 있음. sysout걷어내자.
}
@Override //http 없다! 상위타입
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
log.info("{} 요청이 필터링됨.", req.getRequestURI());
chain.doFilter(request, response); //요청과 응답의 필터의 경계
log.info("{} 에 대한 요청으로 생성된 응답이 필터링됨.", req.getRequestURI());
}
@Override
public void destroy() {
log.info("{}필터가 소멸됨.", this.getClass().getSimpleName());
}
}
로그만 기록
▶web.xml
서블릿등록 다시 공부하자
<filter>
<filter-name>FirstFilter</filter-name>
<filter-class>kr.or.ddit.filter.FirstFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>FirstFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
▶SecondFilter
무조건 웰컴페이지로 가도록 flow control
@Override //http 없다! 상위타입
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
String uri = req.getRequestURI();
uri = StringUtils.substringAfter(uri, req.getContextPath());
log.info("{} 요청이 필터링됨.", uri);
log.info("{} 에 대한 요청으로 생성된 응답이 필터링됨.", req.getRequestURI());
//흐름을 제어하는 코드
boolean pass = false;
if("/".equals(uri)) {
pass = true;
}else if("/default.jsp".equals(uri)) {
pass = true;
}else if(uri.startsWith("/resources")) {
pass = true;
}else if(uri.startsWith("/includeee")) {
pass = true;
}
if(pass) {
chain.doFilter(request, response); //요청과 응답의 필터의 경계 //체인이 끊기면 어플리케이션이 작동을 안한다.
}else {
resp.sendRedirect(req.getContextPath() + "/");
}
}
▶ThirdFilter
who로 파라미터 받으면 a001로 바꿔버리는 필터
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletRequestWrapper wrapper = new HttpServletRequestWrapper(req) {
//익명객체의 형태로 클래스를 하나 정의해보자.
@Override
public String getParameter(String name) {
if("who".equals(name)) {
return "a001";
}else {
return super.getParameter(name);
}
}
};
log.info("{} 요청이 필터링됨.", req.getRequestURI());
chain.doFilter(wrapper, response); //request -> wrapper
log.info("{} 에 대한 요청으로 생성된 응답이 필터링됨.", req.getRequestURI());
}
이제 진짜 필요한 필터를 만들어보자.
설계
1. 인코딩필터 : CEF
2. 멀티파트필터 : MF
파일관련처리하는 셋터가 리퀘스트에 없다.그래서 랩퍼가 필요하다 wrapper request.
1. 초기화 파라미터로 인코딩을 설정해보자.
초기화 파람 설정.
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>kr.or.ddit.filter.mvc.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
흐어....ㅜㅜ
multipart....
1. 신원확인 - 인증
2. 권한 부여됐는지 확인 - 인가
보호자원에 대한 접근제
1. 무엇을 보호할 것인가? 보호자원에 대한 정의 ▶SecuredResources.properties
2.
3. 자원에 설정된 권한에 맞춰 사람에게도 부여되는 권한
배열대상으로 이진탐색방법으로 검색을해야한다. 그러려면 정렬이 필요.
참고
base64인코딩
https://ko.wikipedia.org/wiki/%EB%8D%B0%EC%9D%B4%ED%84%B0_URI_%EC%8A%A4%ED%82%B4
OWASP
3년에 한번 또는 4년에 한번씩 그동안 가장 많았던 보안 공격, 취약점을 발표한다고 한다.
https://www.appsealing.com/kr/2021%EB%85%84-owasp%EC%9D%98-10%EB%8C%80-%EC%B7%A8%EC%95%BD%EC%A0%90/
2021에 발표한 내용
request는 기본적으로 셋터가 없기 때문에 원본 리퀘스트를 수정하려면 adapter패턴 활용하여 wrapper를 생성한다.
자바시스템에서 표준화된 인증객체 principal