본문 바로가기
IT

[스프링 시큐리티] Spring Security란? (개념, 특징, CSRF, 인증/권한 설정)

by 유나니나노 2024. 4. 26.
반응형

 

Spring Security는 Java 기반의 애플리케이션에 대한 인증 및 접근 제어 기능을 제공하는 프레임워크입니다. 주로 Spring 기반 애플리케이션의 보안을 강화하기 위해 사용되며, 웹 보안과 메서드 수준 보안을 모두 제공합니다.

 

주요 개념

  • 인증(Authentication): 사용자가 누구인지 확인하는 과정입니다. 사용자의 아이디와 비밀번호, 소셜 로그인 정보, 토큰 등을 통해 사용자의 신원을 확인할 수 있습니다.
  • 권한 부여(Authorization): 인증된 사용자가 어떤 리소스에 접근할 수 있는지 결정하는 과정입니다. 예를 들어, 어떤 사용자는 특정 페이지에 접근할 수 있지만, 다른 사용자는 접근할 수 없게 설정할 수 있습니다.
  • CSRF(Cross Site Request Forgery) 보호: 사용자를 속여서 의도치 않은 요청을 보내게 만드는 공격을 방지하는 기능입니다. Spring Security는 CSRF 토큰을 활용하여 이러한 공격으로부터 보호합니다.
  • 세션 관리: 사용자의 세션을 관리하고 세션 고정 공격(Session Fixation), 세션 탈취 공격(Session Hijacking) 등으로부터 보호합니다.

특징

  • 인증 및 권한 부여: Spring Security는 사용자 인증과 사용자가 애플리케이션 내에서 접근할 수 있는 권한을 설정하는 기능을 제공합니다. 이는 애플리케이션의 보안을 강화하는 핵심 요소입니다.
  • 다양한 인증 매커니즘 지원: Spring Security는 폼 기반 인증, HTTP 기본 인증, LDAP, OAuth2 등 다양한 인증 메커니즘을 지원합니다. 이를 통해 개발자는 애플리케이션의 요구사항에 맞는 인증 방식을 유연하게 선택할 수 있습니다.
  • 세밀한 접근 제어: URL 수준 또는 메소드 수준에서 세밀한 접근 제어를 설정할 수 있습니다. @PreAuthorize, @Secured와 같은 어노테이션을 사용하여 특정 역할을 가진 사용자만이 해당 기능에 접근할 수 있도록 제한할 수 있습니다.
  • CSRF 보호: Spring Security는 CSRF 공격으로부터 보호하기 위해 CSRF 토큰을 사용합니다. 이는 웹 애플리케이션을 보다 안전하게 만드는 데 기여합니다.
  • 세션 관리: 세션 고정, 세션 탈취와 같은 공격으로부터 보호하기 위한 강력한 세션 관리 기능을 제공합니다. 세션 관리를 통해 사용자의 세션을 안전하게 유지할 수 있습니다.
  • 확장성 및 커스터마이징: Spring Security는 확장성이 뛰어나 사용자가 필요로 하는 특정 보안 요구사항을 충족시키기 위해 커스터마이징 할 수 있습니다. 커스텀 인증 공급자, 성공/실패 핸들러, 사용자 상세 서비스 등을 자유롭게 구현할 수 있습니다.
  • Spring Framework와의 긴밀한 통합: Spring Security는 Spring Framework와 긴밀하게 통합되어 있어, Spring 기반 애플리케이션의 보안 구현을 간소화합니다.
  • 강력한 커뮤니티 지원 및 문서화: Spring Security는 활발한 커뮤니티 지원과 잘 정리된 문서를 제공합니다. 이를 통해 개발자들은 Spring Security의 다양한 기능을 빠르게 학습하고 문제 해결에 도움을 얻을 수 있습니다.

CSRF (Cross-Site Request Forgery) 보호 방법

CSRF 공격은 사용자가 자신의 의지와는 무관하게 공격자가 조작한 악의적인 요청을 보내도록 만드는 공격입니다. Spring Security는 이러한 공격으로부터 보호하기 위해 CSRF 토큰을 사용하는 방법을 제공합니다.

 

  1. CSRF 토큰 활성화: Spring Security에서 CSRF 보호는 기본적으로 활성화되어 있습니다. 따라서 별도의 설정 없이도 CSRF 보호 기능을 이용할 수 있습니다. 하지만 어떤 이유로 CSRF 보호 기능을 비활성화했더라도, http.csrf().disable() 대신 http.csrf().enable()을 사용하여 다시 활성화할 수 있습니다.
  2. 토큰 포함: 클라이언트 측에서는 모든 POST 요청에 CSRF 토큰을 포함시켜야 합니다. Spring Security는 폼 기반 인증을 사용하는 경우 자동으로 폼에 CSRF 토큰을 추가합니다. 하지만 AJAX 요청을 사용하는 경우, JavaScript를 사용하여 요청 헤더에 CSRF 토큰을 명시적으로 추가해야 합니다.
  3. 토큰 검증: 서버 측에서는 들어오는 모든 요청에 대해 CSRF 토큰을 검증합니다. 이 과정은 Spring Security가 자동으로 처리합니다. 요청에 유효한 CSRF 토큰이 포함되어 있지 않은 경우, Spring Security는 요청을 거부하고 오류를 반환합니다.
  4. 토큰 갱신: CSRF 토큰은 정기적으로 갱신될 수 있습니다. 사용자의 세션이 만료되거나 로그아웃을 할 때 토큰을 갱신하여, 공격자가 이전에 획득한 토큰을 사용하는 것을 방지할 수 있습니다.

인증, 권한 부여 설정

 

1. 의존성 추가

pom.xml 파일에 Spring Security 의존성을 추가해야 합니다.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

 

2. WebSecurityConfigurerAdapter 확장

Spring Security 설정을 커스터마이즈 하기 위해 WebSecurityConfigurerAdapter 클래스를 상속받는 클래스를 생성합니다. 이 클래스에서 인증과 권한 부여의 세부 설정을 할 수 있습니다.

 

**프론트엔드와 백엔드가 분리되어 개발되는 경우**

일반적으로 프론트엔드는 HTML, CSS, JavaScript 등을 사용하여 사용자 인터페이스를 구현하고, 백엔드(Spring Boot를 사용하는 경우)는 REST API를 제공하여 데이터를 주고받습니다. 사용자 정의 로그인 페이지를 프론트엔드에서 따로 만들었다면, Spring Security를 사용하여 인증을 처리하는 방법은 다음과 같습니다.

  1. Spring Security 설정 변경: WebSecurityConfigurerAdapter를 상속받는 클래스에서 configure(HttpSecurity http) 메소드를 오버라이드하여 로그인 페이지 URL을 설정합니다. 하지만, REST API 방식에서는 폼 로그인 대신에 HTTP 기반의 인증 방식을 사용해야 하므로, .formLogin().disable()을 호출하여 기본 로그인 페이지를 비활성화하고, 대신에 .httpBasic() 또는 .oauth2Login() 등을 사용하여 인증을 설정할 수 있습니다.
  2. 로그인 API 구현: 프론트엔드에서 사용자가 입력한 로그인 정보(아이디와 비밀번호 등)를 백엔드로 전송하는 로그인 API를 구현합니다. 이 API는 사용자 인증을 처리하고, 인증 성공 시 JWT 토큰이나 세션 ID 등을 생성하여 프론트엔드로 반환합니다.
  3. 프론트엔드 요청 처리: 프론트엔드는 로그인 API를 호출하여 백엔드로부터 받은 토큰이나 세션 ID를 저장(예: 로컬 스토리지, 쿠키 등)하고, 이후의 모든 요청에 이 정보를 포함하여 서버에 전송합니다. 이를 통해 사용자 인증 상태를 유지합니다.
  4. Security 설정에서 CORS 허용: 프론트엔드와 백엔드가 다른 도메인 또는 포트에서 실행되는 경우, CORS(Cross-Origin Resource Sharing) 문제가 발생할 수 있습니다. WebSecurityConfigurerAdapter를 상속받는 클래스에서 configure(HttpSecurity http) 메서드를 오버라이드하여 .cors()를 추가하고, 필요한 경우 CorsConfigurationSource를 구현하여 CORS를 허용해야 합니다.
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests() // 요청에 대한 사용 권한 체크
                .antMatchers("/", "/home").permitAll() // 누구나 접근 허용
                .antMatchers("/admin/**").hasRole("ADMIN") // ADMIN 역할을 가진 사용자만 접근 가능
                .anyRequest().authenticated() // 나머지 요청들은 권한이 있어야 함
            .and()
            .formLogin() // 폼 로그인 방식 허용
                .loginPage("/login") // 사용자 정의 로그인 페이지
                .permitAll() // 누구나 접근 가능
            .and()
            .logout() // 로그아웃 기능 허용
                .permitAll();
    }
}

 

3. UserDetails 서비스 구현

UserDetailService 인터페이스를 구현하여 사용자 정보를 불러오는 로직을 작성합니다. Spring Security에서는 이 인터페이스의 loadUserByUserName 메서드를 호출하여 사용자의 상세 정보를 가져옵니다.

import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

public class MyUserDetailsService implements UserDetailsService {

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // 실제 환경에서는 여기서 데이터베이스나 다른 서비스를 통해 사용자 정보를 불러와야 합니다.
        return User.withDefaultPasswordEncoder()
                .username("user")
                .password("password")
                .roles("USER")
                .build();
    }
}

 

4. PasswordEncoder 설정

보안을 위해 비밀번호는 항상 암호화되어야 합니다. PasswordEncoder 인터페이스를 사용하여 비밀번호를 암호화할 수 있습니다. BCryptPasswordEncoder는 널리 사용되는 구현체 중 하나입니다.

import org.springframework.context.annotation.Bean;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

 

이러한 기본 단계를 통해 Spring Security에서 인증과 권한 부여를 설정할 수 있습니다. 각 프로젝트의 요구 사항에 따라 더 세부적인 설정이 필요할 수 있으며, Spring Security는 이러한 세부 설정을 지원하는 다양한 옵션과 기능을 제공합니다.

 

 

오늘은 Spring Security에 대해서 알아보았습니다.

Security전에 Spring Boot에 대해서 알아두면 좋으니 참고 부탁드립니다!

2024.04.18 - [IT] - [스프링 부트] Spring Boot란? (개념, MSA, 클라우드, 스트림)

 

[스프링 부트] Spring Boot란? (개념, MSA, 클라우드, 스트림)

Spring Boot는 Java 기반의 오픈 소스 프레임워크로, Spring Framework 위에 구축되었습니다. 그 목적은 Spring 기반의 애플리케이션을 빠르고 쉽게 개발할 수 있게 만드는 것이며, 특히 "production-ready" 즉,

yuna-ninano.tistory.com

반응형