본문 바로가기

SPRING/SpringSecurity

[스프링 시큐리티 완전 정복| 실전 프로젝트 | 회원 인증 시스템] Rest 인증 보안 및 화면 구성

문제 상황

 



Spring Security에서 REST API와 비동기 인증은 주로 JWT(JSON Web Token) 같은 토큰 기반 인증을 사용하여 세션을 유지하지 않는 방식으로 동작한다. 비동기 인증은 웹 페이지의 리프레시 없이 데이터를 송수신할 수 있는 환경, 즉 주로 AJAX 호출이나 REST API 호출에서 자주 사용된다.

 

 

 

 

 


Rest 인증 보안

 

세션 기반 인증에서 비동기 방식

세션 기반 인증에서 비동기 방식으로 동작하는 인증은 주로 세션 쿠키를 통해 이루어진다. 웹 애플리케이션에서 로그인 후 서버가 클라이언트에게 세션 ID를 포함한 쿠키를 전달하고, 클라이언트는 이후 비동기 요청에서 이 쿠키를 계속해서 포함시켜 서버에 인증을 요청한다.

 



1. 세션 기반 인증 흐름

  1. 로그인 요청: 클라이언트는 로그인 폼을 통해 사용자 이름과 비밀번호를 서버로 POST 요청으로 보낸다.
  2. 세션 생성 및 세션 ID 발급: 서버는 Spring Security를 통해 인증을 진행하고, 인증에 성공하면 서버 측에서 세션을 생성하고 클라이언트에게 세션 ID가 포함된 쿠키를 발급한다. 이 쿠키는 JSESSIONID 같은 이름을 가질 수 있다.
  3. 비동기 요청에서 쿠키 사용: 이후 클라이언트는 AJAX 호출이나 다른 비동기 방식으로 REST API 요청을 할 때, 브라우저는 자동으로 이 세션 ID를 쿠키에 포함해 요청한다. 서버는 세션 ID를 통해 사용자가 인증된 상태인지 확인하고 요청을 처리한다.
  4. 서버에서 세션 상태 유지: 서버는 클라이언트의 세션 상태를 메모리나 데이터베이스에 저장하고, 세션 ID를 이용해 사용자를 추적한다. 각 요청 시마다 세션 정보를 참조하여 사용자의 인증 상태를 확인하고 API 요청을 처리한다.

2. Spring Security에서 세션 기반 인증 설정

Spring Security의 기본 설정은 세션 기반 인증이다. 특별한 설정이 없으면 인증 후 자동으로 세션을 생성하고 이를 관리한다.

3. 비동기 요청에서의 쿠키 처리

비동기 요청 시 클라이언트는 세션 ID를 자동으로 서버에 전송할 수 있는데, 이는 브라우저의 기본 쿠키 처리 방식 때문이다. 예를 들어, 다음과 같은 AJAX 요청을 생각해볼 수 있다.

4. 세션 기반 인증의 장점과 단점

  • 장점:
    • 서버에서 세션을 관리하기 때문에 JWT와 달리 클라이언트에서 토큰을 별도로 저장할 필요가 없다.
    • 서버에서 세션 정보를 관리하므로, 세션 만료나 사용자 로그아웃 등의 작업이 비교적 간단하다.
  • 단점:
    • 스케일링 문제: 세션 기반 인증에서는 서버가 모든 세션 정보를 유지해야 하므로 서버가 여러 대로 확장되면 세션 정보를 공유하는 것이 복잡해진다. 이를 해결하기 위해 Redis 같은 중앙 세션 저장소를 사용할 수 있다.
    • 비동기 통신에서의 제약: AJAX 요청 등 비동기 방식에서도 세션을 사용하려면 쿠키 기반으로 동작하므로, CORS나 쿠키 설정 등 추가적인 보안 조치가 필요하다.

5. CSRF 보호와 비동기 요청

세션 기반 인증에서는 CSRF(Cross-Site Request Forgery) 공격에 취약할 수 있다. 특히 비동기 요청을 사용할 때 CSRF 공격에 대비하기 위해 CSRF 토큰을 사용해야 한다. Spring Security는 기본적으로 CSRF 보호를 제공하며, 비동기 요청을 보낼 때 클라이언트가 CSRF 토큰을 함께 전송해야 한다.

 

 


코드 설명

Rest인증은 클라이언트에서 JS로 CSRF값을 직접 전달해줘야 하고 먼저 비활성화 했다.

@Bean
@Order(1)  // SecurityFilterChain의 우선순위를 설정. 숫자가 낮을수록 높은 우선순위로 적용된다.
public SecurityFilterChain restSecurityFilterChain(HttpSecurity http) throws Exception {
    http
        .securityMatcher("api/login")  // 특정 경로(api/login)에만 이 Security 설정을 적용.
        .authorizeHttpRequests(auth -> auth
            // 정적 리소스 경로에 대해 모든 사용자에게 접근을 허용. (css, 이미지, js 파일 등)
            .requestMatchers("/css/**", "/images/**", "/js/**", "/favicon.*", "/*/icon-*").permitAll()
            // 그 외의 모든 요청에 대해서도 접근을 허용.
            .anyRequest().permitAll())
        
        // CSRF 보호 기능을 비활성화. 일반적으로 REST API에서는 CSRF 보호가 필요하지 않기 때문에 비활성화.
        .csrf(AbstractHttpConfigurer::disable)
    ;

    return http.build();  // 설정을 마친 SecurityFilterChain 객체를 반환.
}