0+ 스프링/0+ 스프링 Security

[스프링 시큐리티] 7. 기본 API 및 Filter 이해(CSRF(사이트간 요청 위조))

힘들면힘을내는쿼카 2023. 1. 15. 21:06
728x90
반응형

[스프링 시큐리티] 7. 기본 API 및 Filter 이해(CSRF(사이트간 요청 위조))

해당 포스팅은 인프런에서 스프링 시큐리티 정수원님의 강의를 참고하여 작성했습니다.
스프링 시큐리티 - Spring Boot 기반으로 개발하는 Spring Security - 인프런 | 강의

 

스프링 시큐리티 - Spring Boot 기반으로 개발하는 Spring Security - 인프런 | 강의

초급에서 중.고급에 이르기까지 스프링 시큐리티의 기본 개념부터 API 사용법과 내부 아키텍처를 학습하게 되고 이를 바탕으로 실전 프로젝트를 완성해 나감으로써 스프링 시큐리티의 인증과

www.inflearn.com

 

 

 축하합니다! 아이폰에 당첨되셨습니다.!!!!

여러분은 웹 서핑 중에 아래와 같은 웹사이트에 접속 된 경험이 있을 것입니다.

갑자기 아이폰 당첨이라니?! 이와 같은 웹사이트를 클릭하면 당신은 csrf 에 노출된 것일 수도 있습니다.

csrf란 무엇일까요?

 

CSRF란?

https://nordvpn.com/ko/blog/csrf/

 

크로스 사이트 요청 위조(CSRF)의 의미

크로스 사이트 요청 위조란 무엇일까요? 이 글에서 크로스 사이트 요청 위조의 의미와 방지 방법을 확인해 보세요

nordvpn.com

Cross-Site Request Forgery의 약어로 우리말로 해석하면 악성 웹사이트 공격 유형(크로스 사이트 요청 위조) 입니다.
CSRF는 인증된 사용자의 브라우저에서 사이트가 갖는 신뢰를 악의적인 공격에 사용합니다.
쉽게 이야기하면, 공격자가 당신에게(당신은 특정 웹사이트에 로그인한 상태 입니다.) 인증받은 웹 애플리케이션에 특정 요청을 보내도록 유도하는 공격 행위를 의미합니다.

 

 

그렇다면 XSS란?

XSSCSRF는 사용자의 브라우저를 대상으로 한다는 공통점이 있습니다.
차이점은 XSS는 인증된 세션 없이도 공격을 진행하는 방식이고
CSRF는 사용자의 인증된 세션을 악용하는 공격 방식 입니다.

XSS사용자가 특정 사이트를 신뢰한다는 사실을 이용한 공격 방식이지만,
CSRF웹 애플리케이션이 인증된 사용자의 요청을 신뢰한다는 사실을 이용한 공격 방식입니다.
또한 XSS은 사용자에서 스크립트가 실행되지만 CSRF는 서버에서 스크립트가 실행된다는 차이점이 있습니다.

정리하면!
XSS는 사용자 PC에서 스크립트를 실행해 사용자의 정보를 탈취하는 것을 목적으로 하는 반면,
CSRF요청을 위조함으로써 사용자 몰래 송금과 제품 구입 등 특정 행위를 수행하는 것을 목적으로 합니다.

 

CSRF는 어떻게 공격을 유도할까요?

CSRF 공격 과정

사용자가 온라인 쇼핑몰에 로그인하고 쿠키가 발급되면 사용자의 브라우저는 온라인 쇼핑몰이 신뢰하는 상황입니다.
이때 사용자가 공격자가 보낸 링크를 클릭하게 되면,
사용자의 브라우저에서 공격자의 페이지에 접속하게 되고
아이폰 받기를 누르게 되면 사용자의 브라우저를 통해서 온라인 쇼핑몰에 요청하게 되는 것 입니다.

CSRF 방지

스프링 Security CSRF 토큰 이야기 - 그래서 개발자는 뭘 하면 되죠 | 노란_병아리

 

[스프링 Security] CSRF 토큰 이야기 - 그래서 개발자는 뭘 하면 되죠

CSRF 토큰을 통한 보호 이 글은 Synchronizer Token Pattern에 기반한 CSRF 활용의 빠른 지침이다. Q1. 클라이언트는 어떻게 CSRF 토큰을 얻나요 방법1. 서버가 HTML 렌더링 시 meta 태그에 토큰 집어 넣어 주기

blog.paimon.studio

일반적으로 CSRF 토큰을 통해 요청이 사용자가 전송한 것이 맞는지 확인하거나 재인증을 요구하는 조치를 취하고 있습니다.
그렇다면 스프링 시큐리티는 어떻게 CSRF를 방지 할까요?

CSRF 방지 과정

  • 요청(POST, PUT, PATCH, DELETE)에 랜덤하게 생성된 토큰을 HTTP 파라미터로 요구
  • 요청 시 전달되는 토큰 값과 서버에 저장된 실제 값과 비교한 후 만약 일치하지 않으면 요청은 실패

스프링 시큐리티에서 csrf를 설정하는 방법은 아래와 같습니다.

csrf 토큰을 만들면 유저의 세션에 저장(HttpSessionCsrfTokenRepository)

@EnableWebSecurity
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.authorizeRequests()
                .anyRequest().authenticated();

        http.formLogin();

        http
                .csrf().csrfTokenRepository(httpSessionCsrfTokenRepository());
    }

    @Bean
    public HttpSessionCsrfTokenRepository httpSessionCsrfTokenRepository() {
        return new HttpSessionCsrfTokenRepository();
    }
}

csrf 토큰을 만들면 브라우저 쿠키에 저장(CookieCsrfTokenRepository)

해당 방법은 쿠키csrf 토큰을 담아 보내고 쿠키에서 csrf 토큰을 추출하여 검증하기 때문에 공격자가 사용자의 쿠키를 탈취하면 보안에 문제가 발생할 수 있습니다. 😭

@EnableWebSecurity
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.authorizeRequests()
                .anyRequest().authenticated();

        http.formLogin();

        http
                .csrf().csrfTokenRepository(cookieCsrfTokenRepository());
    }

    @Bean
    public CookieCsrfTokenRepository cookieCsrfTokenRepository() {
        return new CookieCsrfTokenRepository();
    }
}

CSRF 방지 실습

HttpSessionCsrfTokenRepository

  • csrf토큰을 세션에 저장하여 관리하는 방식 입니다.

CsrfFilter에서 토큰을 생성할때 repositroy에 토큰을 저장합니다.
repository의 구현체인 HttpSessionCsrfTokenRepositorysaveToken()에서 HttpSession에 토큰 값을 저장합니다.

MySecurityConfig

@EnableWebSecurity
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http
                .authorizeRequests()
                .anyRequest().permitAll();

        http
                .formLogin();

        http
                .csrf().csrfTokenRepository(httpSessionCsrfTokenRepository());
    }

    @Bean
    public HttpSessionCsrfTokenRepository httpSessionCsrfTokenRepository() {
        HttpSessionCsrfTokenRepository csrfRepository = new HttpSessionCsrfTokenRepository();
        // 기본값이 "org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository.CSRF_TOKEN" 입니다.
        // 기본값이 너무 길어서 따로 설정하는것이 좋습니다.
        csrfRepository.setSessionAttributeName("CSRF_TOKEN");
        return csrfRepository;
    }
}

TestController

import org.springframework.security.web.csrf.DefaultCsrfToken;

@RestController
public class TestController {

    @GetMapping("/csrf")
    public String getOrCreateCsrfToken(HttpServletRequest request) {
        HttpSession session = request.getSession();
        DefaultCsrfToken csrfToken = (DefaultCsrfToken) session.getAttribute("CSRF_TOKEN");

        return csrfToken.getHeaderName()+":"+csrfToken.getToken();
    }

    @PostMapping("/csrf")
    public String getOrCreateCsrfToken() {
        return "HttpSessionCsrfTokenRepository";
    }
}

결과

먼저 GET 요청으로 csrf 토큰을 얻습니다.

 

csrf 토큰을 헤더에 입력한 뒤 POST 요청을 합니다.
이때 헤더는 X-CSRF-TOKEN 입니다.

CookieCsrfTokenRepository

  • csrf토큰을 쿠키에 저장하여 관리하는 방식입니다.

MySecurityConfig

@EnableWebSecurity
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http
                .authorizeRequests()
                .anyRequest().permitAll();

        http
                .formLogin();

        http
                .csrf().csrfTokenRepository(cookieCsrfTokenRepository());
    }

    @Bean
    public CookieCsrfTokenRepository cookieCsrfTokenRepository() {
        return new CookieCsrfTokenRepository();
    }
}

TestController

@RestController
public class TestController {

    @GetMapping("/cookie/csrf")
    public String testGET(HttpServletRequest request) {
        Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
        return cookie.getName()+":"+cookie.getValue();
    }

    @PostMapping("/cookie/csrf")
    public String testPost() {
        return "CookieCsrfTokenRepository";
    }
}

결과

먼저 GET 요청으로 csrf 토큰을 얻습니다.

csrf 토큰을 헤더에 입력한 뒤 POST 요청을 합니다.
이때 헤더는 X-XSRF-TOKEN 입니다.

 

csrf 토큰쿠키에 저장된것을 확인 할 수 있습니다.

 

 

 

728x90
반응형