[Spring Security] Spring Security Configuration 와 BCrypt 암호화 메서드
이전에 JWT가 무엇인지 알고, 인가 인증에 대해서 글을 기록해뒀다.
이번에는, 스프링에서 보안을 위해 쓰이는 Spring Security에 대해서 알아보고, 이를 어떻게 사용해볼 수 있는지 알아보겠다.
2024.07.17 - [Spring] - [Spring] 인증, 인가 그리고 JWT
[Spring] 인증, 인가 그리고 JWT
Spring security를 이용하여 프로젝트에 보안 시스템을 구성할때 내가 JWT에 대한 전문지식이 부족한 것을 깨달았다. 그래서 포스팅을 해보며, JWT와 Spring security에 대해서 확실한 지식을 쌓고자 한
jinnocode.tistory.com
Spring Seucurity란?
Spring Security는 인증, 권한 관리 그리고 데이터 보호 기능을 포함하여 웹 개발 과정에서 필수적인 사용자 관리 기능을 구현하는데 도움을 주는 Spring의 강력한 프레임워크이다.
일반적으로 회원가입, 로그인, 필터링 등 여러가지 보안 관련한 기능을 개발자에게 요구하는데 이는 다양하게 작업되어 많은 시간들을 요구한다. 이에 Spring Security는 발자들이 보안 관련 기능을 효율적이고 신속하게 구현할 수 있도록 도와준다.
개발 구조가 스프링이라는 생태계에서 적용하기 매우 편리하고, 사실 IOC/DI 같은 패턴을 녹여가며 인가/인증 부분을 개발하기가 어렵다. 하지만 해당 프레임워크의 기능들을 사용하면 효율적인 개발이 가능해질 것이다.
Spring Security의 동작원리
Client가 특정 요청을 날리면 요청이 서블릿 컨테이너(Servlet Container)라는 Tomcat Container를 지나서 스프링부트 어플리케이션에 도달하게 된다. 그 때, 서블릿 컨테이너는 여러가지 필터를 가지고 있다. 이때, 스프링 시큐리티를 의존성으로 채택하게 된다면, 해당 요청을 스프링 시큐리티가 필터에서 가로채게 된다.
이때, 스프링 시큐리티는 여러가지 인가에 관한 작업을 수행할 수 있다.
- 해당 경로의 접근은 누구에게 열려있는지
- 로그인이 완료된 사용자인지
- 어떠한 Role을 갖고 있는지
이러한 점들을 체크해 검증을 하게된다. 이러한 과정을 인가작업이라고 한다.
Spring Security Configuration
그렇다면 이를 적용하는 Configuration 파일을 메인 경로 밑에 패키지를 생성해서 작성해보자.
package com.example.testsecurity.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{
http
.authorizeHttpRequests((auth) -> auth
.requestMatchers("/", "/login").permitAll()
.requestMatchers("/admin").hasRole("ADMIN")
.requestMatchers("/my/**").hasAnyRole("ADMIN", "USER")
.anyRequest().authenticated()
);
return http.build();
}
}
먼저, Configuration 파일임을 알리는 @Configuration을 붙여준다.
@EnableWebSecurit는 스프링 시큐리티를 활성화하고 웹 보안 설정을 구성하는데 사용한다. 해당 어노테이션을 사용함으로써 웹 보안 설정을 활성화하고, 다양한 보안 기능을 추가할 수 있다.
해당 코드에서 .requestMathcers를 통해 특정 url에 들어오는 요청들에 대해서 인가작업을 수행할 수 있다.
.permitAll()을 사용하면 모두 사용 가능하고,
.hasRole("ADMIN") 은 ADMIN의 권한을 가지고 있는 사용자들만 접근이 가능하다는 것이고,
.hasAnyRole("ADMIN","USER")은 ADMIN, USER에게만 접근이 가능하다는 뜻이다.
.anyRequest().authenticated()은 그 외 요청들은 모두 인증이 되어야 한다는 뜻이다.
Spring Security은 버전 마다 Configuration 파일 형식이 다른데, 3.1.X 버전 부터는 람다식을 사용해야한다.
버전마다 달라지는 작성 방법은
https://github.com/spring-projects/spring-security
GitHub - spring-projects/spring-security: Spring Security
Spring Security. Contribute to spring-projects/spring-security development by creating an account on GitHub.
github.com
스프링 시큐리티 깃허브를 보고 바뀐 버전에 맞게 구현해보자.
Form Login
위 코드는 특정 경로로 요청을 제어 하는 역할을 했다. 만약, 내가 로그인을 하지 않고, "/admin"등의 경로로 요청을 하면 액세스 권한 거부 페이지가 뜨게 된다. 그런데 우리가 원하는 것은 이러한 딱딱한 웹이 아니고, 로그인 페이지로 바뀌는 친절한 웹을 원한다.
package com.example.testsecurity.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{
http
.authorizeHttpRequests((auth) -> auth
.requestMatchers("/", "/login").permitAll()
.requestMatchers("/admin").hasRole("ADMIN")
.requestMatchers("/my/**").hasAnyRole("ADMIN", "USER")
.anyRequest().authenticated()
);
http
.formLogin((form) -> form
.loginPage("/loginPage")
.defaultSuccessUrl("/members")
.failureUrl("/loginFail")
.usernameParameter("userid")
.passwordParameter("passwd")
.loginProcessingUrl("/login_page")
.permitAll()
);
return http.build();
}
}
그래서 위와 같은 코드를 추가해준다.
- .loginPage : 로그인 화면의 Url을 설정해준다. (시작화면 지정)
- .defaultSuccessUrl : 로그인이 성공했을 때 보여준느 디폴트 경로를 지정해준다.
- .failureUrl : 로그인이 실패했을 때 보여주는 url을 지정해준다.
- .usernameParameter : 웹의 username의 파라미터 값을 지정해준다.
- .passwordParameter : 웹의 password의 파라미터 값을 지정해준다.
- .loginProcessingUrl : 웹 로그인 창의 액션을 지정해준다.
SecurityConfig에서 loginProcessingUrl() 메서드를 작성해주면 해당 Url로 요청이 될 시 SpringSecurity가 직접 알아서 로그인 과정을 진행해준다. 결과적으로 /login 에 해당하는 코드가 컨트롤러에 없어도 된다는 점이다.
매우 편리하지만, 이 과정에서 UserDetails가 필요하기에 따로 이를 구현한 클래스를 만들어줘야한다.
.csrf
csrf란 사이트 간 요청 위조를 의미한다. 이는 웹 사이트의 취약점 중 하나인데, 이러한 문제점을 막기 위해 방지 설정이 스프링 시큐리티에는 기본적으로 설정되어 있다. 이러한 기능 때문에 요청을 할 때 csrf 토큰도 같이 보내주어야 정상적으로 작동을 하는데, 개발 환경에서는 이러한 설정을 꺼두는 것이 편하다.
http
.csrf((auth) -> auth.disable());
해당 코드를 configuration 파일에 추가하여 잠시 꺼두고 개발을 진행하자.
위 토큰을 이용하여 csrf에 대한 보안 설정을 하는 것은 다음에 알아보도록 하자.
BCrypt 암호화
스프링 시큐리티는 사용자 인증(로그인)시 비밀번호에 대해 단방향 해시 암호화를 진행하여 저장되어 있는 비밀번호와 대조한다.
따라서 회원가입시 비밀번호 항목에 대해서 암호화를 진행해야 한다.
스프링 시큐리티는 암호화를 위해 BCrypt Password Encoder를 제공하고 권장한다. bcrypt는 블로피시 암호에 기반을 둔 암호화 해시 함수로서 가장 널리쓰이는 암호화 방법이다.
따라서 해당 클래스를 return하는 메소드를 만들어 @Bean으로 등록하여 사용하면 된다.
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
해당 코드를 설정 파일에 빈 등록하여 사용하면 된다.