쿠키나 세션을 사용하지 않는 경우에는 CSRF 기능을 비활성화 하는 것이 효율적이다.
이유는 POST, DELETE와 같은 검사가 필요한 메서드를 요청할때마다 토큰을 보내주고 관리해야하기 때문에 비효율적일 수 있다.
CSRF 기능이 활성화 되어 있을때는 스프링시큐리티에서 form hidden 타임으로 _csrf 토큰값을 보낸다 이를 잘 확인하여 요청 헤더 또는 매개변수에 넣어서 보내도록 해야한다.
스프링시큐리티는 기본적으로 CSRF 토큰이 생성되면 세션에 저장을 한다.
⭐️
헤더와 매개변수로 왔을 때 아래와 같은 이름으로 토큰을 읽는다
쿠키는 response에 담아서 브라우저에 저장이 된다
일반 스크립트에서는 읽을 수 없고 http 통신에서만 읽을 수 있다
쿠키는에 토큰을 저장하는 것은 설정하는 방식이 두가지가 있다
둘 중 한가지만 선택해야한다
쿠키로 저장해서 쿠키로 읽는 것
보안을 위해서 스크립트로 읽을 수 없도록 되어있다. http 통신으로만 읽을 수 있다. (선호)
방법1. http.csrf(csrf -> csrf.csrfTokenRepository(repository));
쿠키를 클라이언트(프론트엔드) 자바스트립트로 읽을 수 있도록 설정.
방법2. http.csrf(csrf -> csrf.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()));
쿠키명 : XSRF-TOKEN
세션과의 차이 : 쿠키명이 다르다
📌CsrfTokenRequestHandler : 토큰의 유효성을 검사하는 클래스
설정해주지 않아도 스프링시큐리티가 자동으로 디폴트값으로 초기화 된다. 위에서는 설정하는 방법
클라이언트 요청마다 UUID 값으로 생성된 CSRF 토큰값을 난수로 인코팅하는 클래스가 XorCsrfRequestAtttributeHandler(구현체) 이다.
서버에서 받은 토큰값은 인코딩된 토큰 값이고 원본 토큰 값을 얻기 위해 디코딩한다. 즉 인코딩/디코딩 기능을 가지고 있는 것이고 CsrfTokenRequestHandler는 원본 그대로를 비교한다.
인코딩된 토큰값을 클라이언트에게 보내는 것 (HTML hidden 타입)
토큰 UUID는 기본적으로 세션에 저장된다. 서버에서 받은 토큰값은 인코딩된 값이기 때문에 이를 디코딩하여 원본 토큰 값과 비교를 한다. 이렇게 유효성을 검사하는 것
클라이언트가 보는 값 -> 인코딩 된 토큰값 (actualToken) / 서버에서 만든 원본 토큰값 csrfToken 따라서 인코딩된 값을 디코딩해주는 작업을 한다 CsrfFilter.class
: 토큰을 매요청마다 가져오는 것이 아니라 세션으로부터 CSRF 토큰이 꼭 필요할때 호출하겠다는 것
기본적으로 세션에서 데이터가 변경되지 않는 메소드 요청을 하는 경우에는 csrf 토큰이 생성되지 않는다.
POST, PUT, DELETE등의 데이터 변경을 요청하는 메소드의 경우에 토큰이 생성되는데
이때도 메소드 검증을 하기전에 csrf를 준비하는 단계에서 request 요청에 csrf토큰으로 지연 로딩으로 저장이된다.
이를 컨트롤러에서 호출하여 사용하는 것
CsrfToken token = HttpServletRequest.getAttribute(CsrfToken.class.getName());
token.getToken();
or
HttpServletRequest.getAttribute("_csrf");
springboot에서 CsrfToken을 매개변수로 받아서 바로 사용할 수 있다.
내부적으로는 위의 코드와 비슷한 맥락으로 실행