@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf().disable();
return http.build();
}
Spring Security 코드를 작성하면서 CSRF 공격에 대비를 하지 않고 이를 비활성화시켜도 되는지에 대한 의문이 들었다. 이에 대해 잘 모른 채로 보안 코드를 작성하는 것은 옳지 않다고 생각되어서 CSRF 보안 코드를 왜 비활성화시키는지 찾아 정리해 보았다.
1. CSRF(Cross-Site Request Forgery)
1.1 Cookie & Session
CSRF를 알아보기 앞서 쿠키와 세션에 대한 간단한 이해가 필요하다.
사용자가 특정 서버에 로그인하면 일반적으로 아래과 같은 작업들이 수행된다.
- 서버는 로그인 시 인증된 사용자의 정보를 세션(session)에 저장하고, 이를 찾을 수 있는 sessionID을 만든다.
- 서버는 저장된 세션 정보를 클라이언트(브라우저)가 사용할 수 있도록 sessionID를 Set-Cookie 헤더에 담아서 전달한다.
- 클라이언트(브라우저)는 전달된 sessionID를 쿠키에 저장한다.
- 클라이언트(브라우저)는 해당 도메인을 가진 서버로 요청 시 쿠키에 저장된 sessionID를 자동으로 전달한다.
- 서버는 쿠키에 담긴 sessionID를 통해 인증된 사용자인지 여부를 확인한다.
1.2 CSRF 전제 조건과 공격 과정
CSRF 공격을 시도하기 위해선 아래와 같은 몇 가지 조건이 필요하다.
- 사용자가 보안이 취약한 서버로부터 이미 인증을 받은 상태여야 한다.
- 쿠키 기반으로 서버 세션 정보를 획득할 수 있어야 한다.
- 공격자는 서버를 공격하기 위한 요청 방법에 대해 미리 파악하고 있어야 한다. 예상치 못한 파라미터가 있으면 불가능하다.
위와 같은 조건이 만족되면 다음과 같은 과정을 통해 CSRF 공격이 수행된다.
- 사용자는 보안이 취약한 서버에 로그인한다.
- 로그인 이후 서버에 저장된 세션 정보를 사용할 수 있는 sessionID가 사용자 브라우저 쿠키에 저장된다.
- 공격자는 서버에 인증된 브라우저의 사용자가 악성 스크립트 페이지를 누르도록 유도한다.
- 게시판에 악성 스크립트를 게시글로 작성하여 관리자 혹은 다른 사용자들이 게시글을 클릭하도록 유도한다.
- 메일 등으로 악성 스크립트를 직접 전달하거나, 악성 스크립트가 적힌 페이지 링크를 전달한다.
- ··· 등 여러 방법
- 사용자가 악성 스크립트가 작성된 페이지 접근시 쿠키에 저장된 sessionID는 브라우저에 의해 자동적으로 함께 서버로 요청된다.
- 서버는 쿠키에 담긴 sessionID를 통해 해당 요청이 인증된 사용자로부터 온 것으로 판단하고 처리한다.
2. CSRF disable 설정
이렇게 보안 수준을 향상시키는 CSRF 보안 코드를 disable 하는 이유가 뭘까? spring security documentation에는 non-browser clients 만을 위한 서비스라면 csrf를 disable 해도 좋다고 나와있다.
Spring Security 프레임워크는 기본적으로 CSRF 공격에 대한 방지를 수행한다.
이전에 많이 사용했던 MVC 구조는 세션과 쿠키를 통해 사용자 인증을 수행했기 때문에 CSRF 공격에 취약했다.
Stateful 한 서비스를 제공하기 위해 인증된 사용자 정보를 세션에 저장하고, 세션 ID가 쿠키에 저장되기 때문에 문제가 발생했던 것이다.
No cookies = No CSRF
브라우저에 저장되는 쿠키가 CSRF 공격의 매개체이기 때문에 쿠키가 없으면 CSRF 공격도 없다.
최근 많이 사용하는 REST API 방식은 세션 기반 인증과는 다르게 클라이언트가 권한이 필요한 요청을 하기 위해서는 요청에 필요한 인증 정보(OAuth2, JWT 토큰 등)를 포함시켜야 하는 stateless 의 특성을 갖고 있기 때문에 CSRF 공격에 대한 방어 설정을 비활성화해도 되는 것이다.
참고
'Back-end' 카테고리의 다른 글
[Spring Boot] DB Schema 및 Data 초기화 schema.sql data.sql (0) | 2023.02.19 |
---|---|
[AWS] SpringBoot + gradle 프로젝트(jar) EC2 서버 배포 (0) | 2023.02.11 |
[Spring Boot] RestController, ResponseEntity란? (0) | 2023.01.20 |
[Spring Boot] H2 설치, Spring Boot H2 연결 (0) | 2023.01.18 |
[git] .gitignore 사용법, gitignore 적용하기 (0) | 2023.01.18 |