JWT 토큰과 CSRF 공격

Alex·2025년 1월 15일
0

CS를 공부하자

목록 보기
12/74

스프링 시큐리티-JWT를 사용할 때 CSFR를 막는 설정을 disable을 했다.

CSRF에 대해 좀더 자세하게 조사해봤다.

CSRF(Cross Site Request Forgery)는 공격자가 이용자 권한을 도용해서 요청을 보내는 것을 말한다. SNS에서 광고성 혹은 유해한 게시글을 업로드할 수 있는 것이다. 혹은 은행에서 계좌이체를 해서 금전적인 피해를 줄 수도 있다.

조건은 다음과 같다.

  • 이용자가 피싱 사이트에 접속할 것
  • 위조 요청을 보낼 사이트에 이용자가 로그인을 한 상태일 것

피싱사이트에서 이용자에게 특정한 요청을 보내게하면, 그 요청안에 담긴 Credentials를 가져와서 해당 회원인척 할 수 있는 것이다.

@Configuration
@EnableWebSecurity
public class SecurityConfig {

	@Bean
	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
		http
			// ...
			.csrf(Customizer.withDefaults());
		return http.build();
	}
}

스프링시큐리티 설정만 해주면 csrf 문제가 해결 가능하다고 한다.

스프링은 어떻게 CSRF 문제를 해결할까?

내부적으로 csrf 필터가 있다.

1) 우선 DeferredCsrfToken가 로드되는데, 나중에 실제 CSRF 토큰을 불러올 수 있도록 CsrfTokenRepository에 참조를 보관한다.

2) CsrfTokenRequestHandler가 DeferredCsrfToken으로부터 생성된 CSRF 토큰 공급자를 받는다

3) 들어온 요청이 CSRF 보호가 필요한지 확인한다. 보호가 필요없다면 다음 필터로 진행되고, 필요하면 검증단계를 진행한다.

4) 저장된 토큰을 DeferredCsrfToken에서 불러오고, 클라이언트가 제공한 실제 CSRF 토큰과 비교한다.

5) 토큰이 일치하면 계속 처리, 토큰이 불일치하거나 없으면 거절한다.

악성 사이트는 이 토큰을 탈취하지못한다.

그 이유는

  • 서버는 정상적인 폼에 랜덤 토큰을 포함시킨다
  • 악성 사이트는 Same Origin Policy 때문에 원래 사이트의 응답을 읽을 수 없고, 토큰 값을 알 수 없다.
  • 서버는 모든 상태 변경 요청에서 이 토큰을 확인한다.

JWT 토큰을 사용할 때는 왜 CSRF설정을 disable할까?

CSRF 토큰을 대신할 수 있는 JWT 토큰을 사용하기 때문에 비활성화를 해도 되는 것으로 보인다.

CSRF With Stateless REST API

여길 보면 JWT를 사용하는 여러 방법들에 대한 설명이 나온다.

브라우저 전역변수

우선, JWT를 브라우저 전역변수로 설정하는 방식이다. 그러면, CSRF나 XSS 어택에서 안전하다.

브라우저에서는 유지되지만 새로고침을 하거나 브라우저를 닫으면 토큰이 사라진다. 그래서 불편하다.

브라우저 로컬스토리지

브라우저 localStorage에 저장하는 방식이다. 이 방식은 쿠키와 달리, 브라우저가 자동으로 요청과 함께 보내지 않는다.

CSRF 공격시 자동으로 토큰이 전송되지 않아 이에 악용할 수가 없다. 다만, XSS에는 취약한데, 자바 스크립트 코드로 브라우저 스토리지에 접근해서 토큰을 탈취 할 수 있기 때문이다.

XSS 공격은 JSON으로 데이터를 주고받기만 하는 API 서버에서는 걱정하지 않아도 된다고 한다. XSS 공격 대상이 되는 HTML 페이지를 응답하지 않기 때문이다.

쿠키 저장방식

서버는 쿠키를 브라우저에 설정할 수 있다. 그러면, 브라우저는 이 쿠키를 매번 요청을 보낼 때마다 자동으로 함께 보낸다.

HttpOnly 플래크를 설정해서 자바 스크립트로 이 쿠키에 접근하지 못하게하고, XSS 공격도 막을 수 있다. HTTPS only 설정도 해서 보안 수준을 높일 수 있다.

다만, CSRF에 취약하기에 이 부분은 주의해야 한다.

추가 공부

Do I need CSRF token if I'm using Bearer JWT?

브라우저에서 Bearer 헤더를 붙여서 인증정보를 보내는 거라면 CSRF 공격에 대해서는 안전하다. 다만, 서버 사이드에서 Bearer 토큰이 없다면 쿠키로 fall back이 되도록 설정되지 않게 해야한다

Generally, CSRF happens when a browser automatically adds headers (i.e: Session ID within a Cookie), and then made the session authenticated. Bearer tokens, or other HTTP header based tokens that need to be added manually, would prevent you from CSRF.

일반적으로 CSRF는 브라우저가 자동으로 헤더를 넣을 때 이 값을 사용하는 것이고, Bearer token처럼 직접 넣어주어야 하는건 CSRF에서 안전하다고 한다.

결론은

  • JWT를 헤더에 보내고, Bearer Token방식으로 헤더에 넣어서 요청에 보내면 CSRF 공격에서 안전하다.
  • 다만, XSS에는 안전하지 않으므로 별도의 보안 장치가 필요하다.
profile
답을 찾기 위해서 노력하는 사람

0개의 댓글