// 토큰 생성 인터셉터
public class GeneratorInterceptor extends HandlerInterceptorAdapter {
@Override
boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
final String TOKEN_KEY = "token_key";
final HttpSession session = request.getSession();
String tokenValue = RandomStringUtils.randomAlphabetic(40); //랜덤한 토큰값을 생성
if(session.getAttribute(TOKEN_KEY) == null) {
session.setAttribute(TOKEN_KEY, tokenValue);
}
return true;
}
}
<input type="hidden" id="token_key" name="token_key" value="${sessionScope.token_key}"/>
public class CheckInterceptor extends HandlerInterceptorAdapter {
@Override
boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
final String TOKEN_KEY = "token_key";
final String REQUEST_URI = "/sms/sendSMS";
final HttpSession session = request.getSession();
final String REQUEST_URL = request.getRequestURL().toString();
// URI 확인
if(REQUEST_URL.equals(REQUEST_URI)) {
// 헤더라면 아래 처럼 접근
// String csrf_key = request.getHeader("TOKEN_KEY"); //해더에 담긴 키
// 폼데이터
final String requestValue = request.getParameter(TOKEN_KEY); // name 값으로 전달
if(!requestValue.equals(session.getAttribute(TOKEN_KEY).toString())){
session.removeAttribute(TOKEN_KEY);
response.sendError(999); // 특정 상태코드를 보내 이후 리프레시 처리
return false;
}
// 성공해도 일회성 보장을 위해 삭제
session.removeAttribute(TOKEN_KEY);
return true;
}
session.removeAttribute(TOKEN_KEY);
response.sendError(999); // 특정 상태코드를 보내 이후 리프레시 처리
return false;
}
}
@Override
boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
final int MAX_REQUEST_COUNT = 5; //최대 요청 제한 수
final long MAX_TIME = 6000 * 5; //최대 요청 보관 시간(60초 * 5)
final String sessionKey = "AU_" + request.getRequestURI(); // 고유한 세션키
final HttpSession session = request.getSession();
// 세션에서 타임스탬프를 모아둔 리스트를 확인한다.
List<Long> timeStamps = List<Long> session.getAttribute(sessionKey);
if(timeStamps == null) {
timeStamps = new ArrayList<>();
session.setAttribute(sessionKey, timeStamps);
}
// 현재 시간 추가
long curruntTime = System.currentTimeMillis();
timestamps,add(curruntTime);
// 보관 시간 넘은 시간은 삭제해주기
Iterator<Long> iterator = timestamps.iterator();
while (iterator.hasNext()) {
long timestamp = iterator.next();
if (currentTime - timestamp > MAX_TIME) {
iterator.remove();
}
}
// 횟수 넘으면 예외처리, 에러 던지기 등 방어 처리
if(timestamps.size() > MAX_REQUESTS) {
//return false; 등등..
response.senError(403);
throw new Exception("자동화 공격 요청 횟수를 제한합니다.");
}
return true;
}
<mvc:interceptors>
<mvc:interceptor>
<mvc: mapping path="/sms/openSMSView"/>
<bean class="com...interceptor.GeneratorInterceptor"/>
</mvc:interceptor>
<mvc:interceptor>
<mvc: mapping path="/sms/sendSMS"/>
<bean class="com...interceptor.checkInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
스프링3 버전 이후부터는 클래스 파일을 통해 설정을 지원한다. 위 링크 참고!
Reference: