작성
·
415
0
스프링 시큐리티를 학습한 지 얼마 안되서 부족한 부분이 많아서 궁금한 점이 있어서 질문드립니다.
csrf 를 disable 으로 설정하고 JWT 토큰을 활용하여 엑세스 토큰 유효 시간을 짧게(10분 이면 괜찮을까요..?)설정과 함께 리프레쉬 토큰(30일이면 괜찮을까요..?)을 발급하는 것으로 csrf 공격에 대비가 충분하다고 볼 수 있을까요?
그리고 금융권처럼 보안을 강력하게 요구되지 않은 이용자 빈도가 낮은 개인 쇼핑몰 페이지 같은 실무 환경에서 csrf 에 대해 어떻게 대안을 세우는 것이 가장 적절하고 보편적인 방법이 될까요?
답변 1
0
csrf 를 disable 으로 설정의 대안으로 JWT 토큰을 활용이 적절한 지에 대한 답변 해결 했습니다! 지금 실습 강의 환경처럼 RESTful API 방식인 경우에는 CSRF 토큰 사용하는 것으로 찾았습니다. CSRF 토큰 사용 방식은 API 요청의 헤더에 포함하게 되고, CSRF 토큰을 검증하여 보호하는 것으로 확인했습니다.
스프링 시큐리티에 의해 자동적으로 모든 POST 요청은 CSRF 토큰을 자동으로 생성하고 삽입이 되고, 일반적으로 세션에 저장되며, 요청이 수행될 때마다 토큰을 검증하여 요청이 유효한 지 확인하는 것으로 확인했습니다. 크게 HTTP 헤더, 쿠키, 응답 본문 안에 CSRF 토큰을 포함하여 전송하는 세 가지 방식이 있다는 것으로 학습했습니다. 그 중에서 HTTP 헤더 방식이 가장 일반적인 방식으로 다음과 같이 수행되는 것으로 학습했습니다.
HTTP 헤더
백엔드에서 생성된 CSRF 토큰을 HTTP 응답 헤더에 포함하여 클라이언트에게 전달
프론트엔드는 이 헤더에서 토큰을 읽어와서 API 요청을 할 때 요청 헤더에 포함
가장 일반적인 방법으로 스프링 시큐리티에 의해 기본적으로 CSRF 토큰을 HTTP 응답의 헤더에 포함하여 전달
서버에서 CSRF 토큰을 HTTP 응답 헤더에 포함시키는 코드 (스프링 시큐리티)
import org.springframework.security.web.csrf.CsrfToken;
// CSRF 토큰 생성 후 응답 헤더에 추가
@GetMapping("/csrf-token")
public void getCsrfToken(HttpServletRequest request, HttpServletResponse response) {
CsrfToken csrfToken = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
if (csrfToken != null) {
Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
String token = csrfToken.getToken();
if (cookie == null || token != null && !token.equals(cookie.getValue())) {
cookie = new Cookie("XSRF-TOKEN", token);
cookie.setPath("/");
response.addCookie(cookie);
}
}
}
그리고 JWT 를 사용하더라도 CSRF 공격을 방어하기 위해 별도의 조치는 필요하다고 찾았습니다. JWT는 토큰에 사용자 정보를 포함시키는 방식으로 인증을 수행하며, 보통 HTTP의 인증 헤더에 토큰을 포함시켜 API 요청을 보냅니다. (강의 내용처럼 액세스 토큰과 리프레시 토큰이 해당됩니다.) 그러나 JWT 자체는 CSRF 공격으로부터 보호되지 않습니다.
CSRF 공격은 공격자가 피해자의 세션과 인증 쿠키를 이용하여 악의적인 요청을 보내는 것을 이용하는데, JWT는 세션과 쿠키가 아닌 다른 저장소(일반적으로는 클라이언트의 localStorage나 sessionStorage)에 저장됩니다. 그러므로 CSRF 공격은 기본적으로 JWT에 직접적인 영향을 미치지 않습니다.
스프링 시큐리티에 세션(Session)은 기본적으로 서버의 메모리에 세션을 저장합니다. 쿠키(Cookie) 클라이언트 측에 저장되며, 일반적으로 브라우저의 쿠키 저장소에 저장됩니다. 스프링 시큐리티에서는 인증 쿠키와 세션 쿠키 두 개를 다루고 있습니다.
인증 쿠키:
스프링 시큐리티를 사용하여 사용자를 인증할 때, 일반적으로 사용자의 인증 상태를 나타내는 토큰(예: JWT, 인증 세션 ID 등)을 쿠키에 저장합니다.
이 인증 쿠키는 클라이언트에 의해 저장되고, 인증된 사용자가 다음 요청을 보낼 때마다 함께 서버로 전송됩니다.
세션 쿠키:
스프링 시큐리티는 세션을 서버에 저장하고, 클라이언트에는 세션 식별자를 담은 쿠키를 보낼 수 있습니다.
이 세션 쿠키는 클라이언트가 서버로 요청을 보낼 때마다 함께 전송되고, 서버는 이를 사용하여 세션을 식별하고 관리합니다.
와... 달아주신 답변 지금 저한테 정말 필요한 내용이에요. 너무 큰 도움 됐습니다. 정말 감사합니다 ㅠㅠㅠㅠ 최근에 질문 계속 남겼는데 항상 답변 빠르게 달아주셔서 감사합니다!
마지막 문장의 두 번째에서 말씀해주신
"CSRF토큰을 다른 저장소를 이용해서 보관한다면 가능하긴 합니다."
이 부분에 대해 질문해서 바로 해결하고 싶지만.. 혼자 공부해가지고 좀 더 스프링 시큐리티 학습하는데 중점으로 적용하려고 합니다. ㅎㅎ감사합니다!
음.. 아시겠지만 JWT는 인증을 위해서 사용하고 CSRF는 요청을 처리하기 위해서 사용합니다.
JWT와 CSRF토큰을 고려하려면 우선 서버가 API 서버인가 일반적인 화면을 가진 서비스인지부터 생각해 봐야 합니다.
API 서버의 경우 상태를 유지하지 않는 STATELESS이고 세션을 만들지 않는 것이 맞습니다.
일반적으로 CSRF토큰값은 세션당 하나를 생성하는데.. 세션을 생성하지 않으니 CSRF토큰 값을 서버에서 유지하지 않는 상황이 발생합니다.
물론 CSRF토큰을 다른 저장소를 이용해서 보관한다면 가능하긴 합니다.
또 다른 문제는 API 서버의 경우 화면이 없기 때문에 XSS문제가 태생적으로 발생할 수 없는 것이 정상적인 케이스가 됩니다.