[스프링시큐리티] 사이트 간 요청 위조 | 2. CSRF (Cross Site Request Forgery)

Welcome to Seoyun Dev Log·2024년 11월 1일
0

보안

목록 보기
6/18

CSRF

  • 웹 사이트는 사용자가 이미 인증을 받았기 때문에 인증받은 쿠키로 접속을 하면 누가 됐든 인증 받은 상태로 인식한다. 사용자의 브라우저가 자동으로 보낼 수 있는 인증 정보 예를 들어 쿠키나 기본 인증 세션등과 함께 공격용 페이지와 함께 웹사이트로 요청이 된다
  • 위와 같은 공격을 막기위해 스프링시큐리티에서는 CSRF 기능 활성화를 하여 이를 방어한다

  • 데이터를 변경할 수 있는 메서드에 대해서만 CSRF 토큰 검사를 수행한다.
  • 쿠키에 토큰을 요구하는 것은 위험하다.

기능

  • 쿠키나 세션을 사용하지 않는 경우에는 CSRF 기능을 비활성화 하는 것이 효율적이다.
    이유는 POST, DELETE와 같은 검사가 필요한 메서드를 요청할때마다 토큰을 보내주고 관리해야하기 때문에 비효율적일 수 있다.

  • CSRF 기능이 활성화 되어 있을때는 스프링시큐리티에서 form hidden 타임으로 _csrf 토큰값을 보낸다 이를 잘 확인하여 요청 헤더 또는 매개변수에 넣어서 보내도록 해야한다.

CSRF 토큰 유지

스프링시큐리티는 기본적으로 CSRF 토큰이 생성되면 세션에 저장을 한다.

⭐️

  • formLogin의 경우 스프링시큐리티가 input 타입 hidden으로 _csrf 토큰값을 value에 생성해서 서버에 보내준다
  • 기본적으로 CSRF 기능이 켜져 있기 때문에 헤더나 파라미터로 해당 토큰값을 보내줘야한다

1. 세션에 토큰 저장

  • CsrfTokenRespository: 인터페이스
    일회성 토큰이 아닌 발급받은 토큰을 유지하여 영속화하여 사용할 수 있도록 한다.
  • 세션과 토큰 구현체를 통해 토큰을 유지할 수 있다
  • 토큰은 (디폴트)기본적으로 세션에 저장되도록 초기화 된다

헤더와 매개변수로 왔을 때 아래와 같은 이름으로 토큰을 읽는다

  • HTTP 요청 헤더 일 때: X-CSRF-TOKEN
  • 요청 매개변수 일 때 : _csrf

2. 쿠키에 토큰 저장

쿠키는 response에 담아서 브라우저에 저장이 된다
일반 스크립트에서는 읽을 수 없고 http 통신에서만 읽을 수 있다

쿠키는에 토큰을 저장하는 것은 설정하는 방식이 두가지가 있다
둘 중 한가지만 선택해야한다

쿠키로 저장해서 쿠키로 읽는 것
보안을 위해서 스크립트로 읽을 수 없도록 되어있다. http 통신으로만 읽을 수 있다. (선호)
방법1. http.csrf(csrf -> csrf.csrfTokenRepository(repository));

쿠키를 클라이언트(프론트엔드) 자바스트립트로 읽을 수 있도록 설정. 
방법2. http.csrf(csrf -> csrf.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()));
  • 쿠키명 : XSRF-TOKEN

  • 세션과의 차이 : 쿠키명이 다르다


    CSRF 토큰 처리

  • 📌CsrfTokenRequestHandler : 토큰의 유효성을 검사하는 클래스

  • 설정해주지 않아도 스프링시큐리티가 자동으로 디폴트값으로 초기화 된다. 위에서는 설정하는 방법

  • 클라이언트 요청마다 UUID 값으로 생성된 CSRF 토큰값을 난수로 인코팅하는 클래스가 XorCsrfRequestAtttributeHandler(구현체) 이다.
    서버에서 받은 토큰값은 인코딩된 토큰 값이고 원본 토큰 값을 얻기 위해 디코딩한다. 즉 인코딩/디코딩 기능을 가지고 있는 것이고 CsrfTokenRequestHandler는 원본 그대로를 비교한다.

  • 인코딩된 토큰값을 클라이언트에게 보내는 것 (HTML hidden 타입)

  • 토큰 UUID는 기본적으로 세션에 저장된다. 서버에서 받은 토큰값은 인코딩된 값이기 때문에 이를 디코딩하여 원본 토큰 값과 비교를 한다. 이렇게 유효성을 검사하는 것

  • 클라이언트가 보는 값 -> 인코딩 된 토큰값 (actualToken) / 서버에서 만든 원본 토큰값 csrfToken 따라서 인코딩된 값을 디코딩해주는 작업을 한다 CsrfFilter.class

CSRF 토큰 지연 로딩

: 토큰을 매요청마다 가져오는 것이 아니라 세션으로부터 CSRF 토큰이 꼭 필요할때 호출하겠다는 것

  • null로 보내는 경우 모든 지연로딩이 실행되어 값이 반환된다. 따라서 값을 바로 가져오는 것. (성능상 권장하지 않음)
  • SecurityContext가 서플라이어로 감싸서 사용되는 것 처럼 많은 부분이 지연로딩으로 변경되었다.

CSRF 토큰을 springMVC에서 사용하는 방법

기본적으로 세션에서 데이터가 변경되지 않는 메소드 요청을 하는 경우에는 csrf 토큰이 생성되지 않는다.
POST, PUT, DELETE등의 데이터 변경을 요청하는 메소드의 경우에 토큰이 생성되는데
이때도 메소드 검증을 하기전에 csrf를 준비하는 단계에서 request 요청에 csrf토큰으로 지연 로딩으로 저장이된다.
이를 컨트롤러에서 호출하여 사용하는 것

CsrfToken token = HttpServletRequest.getAttribute(CsrfToken.class.getName());
token.getToken();

or

HttpServletRequest.getAttribute("_csrf");

springboot에서 CsrfToken을 매개변수로 받아서 바로 사용할 수 있다.
내부적으로는 위의 코드와 비슷한 맥락으로 실행


CSRF 통합

1. HTML Forms

  • csrf token 값을 hidden 값으로 포함해야한다.
    위 코드를 작성하지 않아도 자동으로 포함하는 뷰가 있다.
    • thymeleaf (최근 뷰를 사용한다면 많이 사용하는 방법)
    • spring 폼 태그 라이브러리

profile
하루 일지 보단 행동 고찰 과정에 대한 개발 블로그

0개의 댓글

관련 채용 정보