본문 바로가기
코딩 공부/web & Java

[Spring/Web] CSRF

by 현장 2023. 12. 4.

CSRF( Cross Site Request Forgery )

사용자가 자신의 의지와 무관하게 공격자가 의도한 행동을 하여 특정 웹페이지를 보안에 취약하게 한다거나 수정, 삭제 등의 작업을 하게 만드는 공격 방법을 의미합니다. 

 

https://stupidsecurity.tistory.com/18

 

위와 같이 A라는 도메인에서, 희생자가 조작된 요청정보를 포함한 게시물을 사용하였을 경우,  공격자도 권한을 가지게 되어서 A 도메인에서는 이 사용자가 일반 유저인지, 공격자의 악용된 공격인지 구분할 수가 없게 됩니다.

🏷️ CSRF의 특징

▪️ XSS와 함께 웹에서 가장 효과적인 공격방법
▪️ 스크립트가 없어도 공격이 가능한 방법
▪️ 정상 사용자를 통해 공격이 진행되므로 공격자의 정보(IP 등)를 추적하는 것이 불가능
▪️ Session Hijacking과 비슷한 권한을 도용한 공격이라 할 수 있

🏷️ CSRF 방지법

✅ 위조 방지 토큰 사용

특정 권한이 필요한 페이지(EX: 회원 정보 수정 등)는 해당 페이지와 실제 동작이 일어나는 페이지사이에 토큰을 생성해 그 값을 비교하여 토큰이 존재하지 않거나 다른 경우 동작을 허용하지 않는 방법이 있습니다.

Referer 값 이용

프록시 툴, 패킷 등을 통해 확인하면 다른 페이지로 이동할 경우 그전 페이지 정보를 가지고 이동합니다. 이때 전페이지 정보가 없거나, 외부 사이트에서 요청을 한 경우 요청을 처리하지 않는 방법이 있습니다.

캡챠 사용

회원정보 변경, 게시글 작성 등 CSRF의 공격을 막아야 하는 페이지에서 캡챠를 사용해 인증이 가능한 것만 요청을 처리해 주는 방법이 있습니다. 캡챠는 랜덤 이미지를 통해 인증이 되므로 사용자 몰래 요청하는 것이 불가능하다는 것 장점입니다.

🏷️ Spring Security의 CSRF

CSRF protection은 spring security에서 default로 설정되어 있습니다. 즉, protection을 통해 GET요청을 제외한 상태를 변화시킬 수 있는 POST, PUT, DELETE 요청으로부터 보호를 하게 됩니다.

// csrf protection을 적용시 csrf 토큰이 포함되어야 요청을 받음으로 위조 요청을 방지하게 됩니다.
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>

🏷️ Rest API에서의 CSRF

하지만 Rest API를 사용하게 되면 보안 수준을 향상시키는 CSRF를 disable로 세팅합니다.

 

그 이유는 Rest API 를 이용한 서버라면, Session 기반 인증과는 다르게 Stateless 하기 때문에 서버에 인증정보를 보관하지 않습니다. Rest API에서 Client는 권한이 필요한 요청을 하기 위해서는 요청에 필요한 인증 정보를(OAuth2, jwt토큰 등)을 포함시켜야 합니다. 따라서 서버에 인증정보를 저장하지 않기 때문에 굳이 불필요한 csrf 코드들을 작성할 필요가 없게 되었습니다.

✅ 예시

@Configuration
public class BasicAuthenticationSecurityConfiguration {
    // Filter Chain 설정
    // 모든 인증 요청을 인증하게 되는데
    // 모든 요청에 대한 기본적인 인증을 사용
    // CSRF 비활성화 -> Session이 전혀 없도록 하기 위해서
    // Session이 있으려면 반드시 CSRF 활성화
    // 즉 Stateless REST API를 만들려고 하는 것
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        return http
                .authorizeHttpRequests(
                        auth -> auth
                                // 프리플라이트 요청에 대한 액세스 허용
                                .requestMatchers(HttpMethod.OPTIONS, "/**").permitAll() 
                                .anyRequest().authenticated()
                ) // 모든 http 요청이 인증되야 한다.
                .httpBasic(Customizer.withDefaults()) // http 기본 인증을 설정해서 기본 인증으로 설정한다.
                .sessionManagement(                   // 홈페이지 접속하면 인증 로그인 창이 뜨게 된다.
                        session -> session.sessionCreationPolicy
                                (SessionCreationPolicy.STATELESS)) // 상태가 없는 세션을 만듭니다.
                .csrf().disable() // CSRF 비활성화한다.
                .build();

    }
}

 

📖 Reference

개발자꿈나무

회뜨는참치

'코딩 공부 > web & Java' 카테고리의 다른 글

[Java] JUnit  (0) 2023.12.12
[Web] JWT  (1) 2023.12.08
[Spring / Web] CORS  (1) 2023.12.01
[WEB] MPA와 SPA  (0) 2023.11.25
[JPA] @Entity는 기본 생성자를 왜 가져야 하는가?  (0) 2023.11.22