CSRF 간소화 설정 사용시 sendRedirect() 호출의 문제점
- 작성자 :
- 박*흠
- 작성일 :
- 2020-11-27 14:43:54
- 조회수 :
- 3,688
- 구분 :
- 공통컴포넌트
- 진행상태 :
- 완료
Q
현재 CSRF 간소화 설정을 사용하는 경우, 접근 방법에 따라 오류가 존재합니다.
게시판의 이전 이슈들을 보니 몇 번 비슷한 질문들이 게시판에 올라왔었지만,
아쉽게도 대부분의 답변 자체는 CSRF 간소화 자체를 사용하는 방법 또는 설정 그 자체에
대한 포커스 위주 인것을 확인할 수 있었습니다.
일단 해당 문제에 대한 가장 근접하게 설명하고 있는 질문은 아래의 글이라고 생각 듭니다.
https://www.egovframe.go.kr/uss/olh/qna/QnaInqireCoUpdt.do?qaId=QA_00000000000017962&menu=5&submenu=3
저 역시 증상이 동일하며, 질문자 분과 동일한 원인으로 예상이 듭니다.
해당 질문을 간단히 요약을 하자면,
CSRF 간소화를 설정하고 form:form 형식 등의 방법으로 input 등에서 _csrf 값을 가질 수 있도록 한 뒤에 보내면
정상적으로 동작을 해야 하나 유독 로그아웃인 egov_security_logout를 호출하는 경우에는 404 문제가 발생하고 있습니다.
분석된 이유는
egov_security_logout를 호출할때 _csrf 값이 전달되어야 하나
EgovSpringSecurityLogoutFilter 필터 등을 경유하는 경우에서는, 메뉴얼 설명에서와 같이
((HttpServletResponse)response).sendRedirect(((HttpServletRequest)request).getContextPath() + "/egov_security_logout");
이렇게 호출하고 있기에 egov_security_logout 에게 _csrf 값을 전달할 수 없다는 것입니다.
제가 아는 선에서, sendRedirect()는 GET 호출을 전제로 하기에 별도의 데이터를 붙일 수 없고
또한 sendRedirect() 함수 자체의 특성상 추가 HEADER를 붙이는 것도 무효화 되기에 불가능 합니다.
따라서 위 링크의 질문자 분의 분석과 같이 sendRedirect()를 사용해서는 정상적인 로그아웃을 할 수 없다는 것에
저역시 공감하는 바입니다.
해당 질문에는 아마도 별도의 답변을 개인적으로 받으신게 아니가 합니다만,
같은 방법으로 호출하는 경우에는 모든 개발자가 실제로 동일한 문제를 겪게 되므로
해당 답변을 공유할 수 있도록 오픈해 주시면 감사하겠습니다.
게시판의 이전 이슈들을 보니 몇 번 비슷한 질문들이 게시판에 올라왔었지만,
아쉽게도 대부분의 답변 자체는 CSRF 간소화 자체를 사용하는 방법 또는 설정 그 자체에
대한 포커스 위주 인것을 확인할 수 있었습니다.
일단 해당 문제에 대한 가장 근접하게 설명하고 있는 질문은 아래의 글이라고 생각 듭니다.
https://www.egovframe.go.kr/uss/olh/qna/QnaInqireCoUpdt.do?qaId=QA_00000000000017962&menu=5&submenu=3
저 역시 증상이 동일하며, 질문자 분과 동일한 원인으로 예상이 듭니다.
해당 질문을 간단히 요약을 하자면,
CSRF 간소화를 설정하고 form:form 형식 등의 방법으로 input 등에서 _csrf 값을 가질 수 있도록 한 뒤에 보내면
정상적으로 동작을 해야 하나 유독 로그아웃인 egov_security_logout를 호출하는 경우에는 404 문제가 발생하고 있습니다.
분석된 이유는
egov_security_logout를 호출할때 _csrf 값이 전달되어야 하나
EgovSpringSecurityLogoutFilter 필터 등을 경유하는 경우에서는, 메뉴얼 설명에서와 같이
((HttpServletResponse)response).sendRedirect(((HttpServletRequest)request).getContextPath() + "/egov_security_logout");
이렇게 호출하고 있기에 egov_security_logout 에게 _csrf 값을 전달할 수 없다는 것입니다.
제가 아는 선에서, sendRedirect()는 GET 호출을 전제로 하기에 별도의 데이터를 붙일 수 없고
또한 sendRedirect() 함수 자체의 특성상 추가 HEADER를 붙이는 것도 무효화 되기에 불가능 합니다.
따라서 위 링크의 질문자 분의 분석과 같이 sendRedirect()를 사용해서는 정상적인 로그아웃을 할 수 없다는 것에
저역시 공감하는 바입니다.
해당 질문에는 아마도 별도의 답변을 개인적으로 받으신게 아니가 합니다만,
같은 방법으로 호출하는 경우에는 모든 개발자가 실제로 동일한 문제를 겪게 되므로
해당 답변을 공유할 수 있도록 오픈해 주시면 감사하겠습니다.
A
안녕하세요.
표준프레임워크센터입니다.
spring security의 csrf 기능을 활성화한경우 모든 post 요청 처리에는 csrf 토큰값이 필요하게 됩니다.
아래 코드와 같이 SecurityContextLogoutHandler 를 이용하여 별도로 로그아웃 처리하실 수 있으니 참조해보시기 바랍니다.
감사합니다.
/**
* 로그아웃
*
* @param model
* @param request
* @param session
* @return
* @throws Exception
*/
@RequestMapping({ "/logout.do" })
public String logout(Model model, HttpServletRequest request, HttpServletResponse response, HttpSession session) throws Exception {
//세션 초기화
session.invalidate();
//기존 로그아웃 URL
//return "redirect:/egov_security_logout";
//spring security csrf 를 활성화 했을때 직접 로그아웃 처리
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null){
new SecurityContextLogoutHandler().logout(request, response, auth);
}
return "redirect:/main.do";
}
표준프레임워크센터입니다.
spring security의 csrf 기능을 활성화한경우 모든 post 요청 처리에는 csrf 토큰값이 필요하게 됩니다.
아래 코드와 같이 SecurityContextLogoutHandler 를 이용하여 별도로 로그아웃 처리하실 수 있으니 참조해보시기 바랍니다.
감사합니다.
/**
* 로그아웃
*
* @param model
* @param request
* @param session
* @return
* @throws Exception
*/
@RequestMapping({ "/logout.do" })
public String logout(Model model, HttpServletRequest request, HttpServletResponse response, HttpSession session) throws Exception {
//세션 초기화
session.invalidate();
//기존 로그아웃 URL
//return "redirect:/egov_security_logout";
//spring security csrf 를 활성화 했을때 직접 로그아웃 처리
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null){
new SecurityContextLogoutHandler().logout(request, response, auth);
}
return "redirect:/main.do";
}