▼ What ?
5주차에 배웠던 내용들을 이어서 마지막으로 '스프링 시큐리티' 라는 것에 대해서 정리해보려고 한다. 스프링 시큐리티 환경설정을 위해 수동으로 'SpringFilterChain' 을 빈(Bean)으로 등록하는 과정에서 '@Configuration' 애너테이션을 사용하는데, 수동/자동으로 빈을 등록하는 과정이 잘 기억나지 않았고 빈에 대한 이해도 아직 부족한 것 같아 다시 찾아보고 공부해보는 시간을 가졌다.
▼ 스프링 시큐리티 (Spring Security)
스프링 시큐리티 ?
- "스프링 시큐리티" 는 스프링 기반 애플리케이션의 권한과 인증을 담당하는 스프링의 하위 프레임워크이다.
➜ 쉽게 말해서 "인증(Authenticate)" 은 로그인을 의미하고, "권한(Authorize)" 은 그렇게 인증된 사용자가 어떤 것까지 할 수 있는지를 의미한다.
스프링 시큐리티를 설치하는 방법
- 이전처럼 build.gradle 파일을 수정해주면 된다.
➜ 스프링 시큐리티와 이와 관련된 타임리프 라이브러리를 사용하도록 설정 !
( 설정 후 "Refresh Gradle Project" 실행 잊지 말기. )
[ /webboard/build.gradle ]
dependencies {
...
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6:3.1.1.RELEASE'
}
스프링 시큐리티 재설정
- 스프링 시큐리티는 아래와 같이 기본적으로 인증(로그인)이 된 사용자만 서비스를 사용 가능하도록 되어있다.
➜ 하지만, 우리는 "WEBBOARD" 라는 게시판 사이트를 만드는 것이기 때문에, 게시만 특성에 따라 로그인 없이도 게시물을 확인할 수 있게 스프링 시큐리티를 추가적으로 설정해줘야 한다 !

- 'SecurityConfig' 라는 클래스를 따로 생성해주자.
[ .../main/java/com/gdsc/webboard/SecurityConfig.java ]
package com.mysite.sbb;
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;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authorizeHttpRequests) -> authorizeHttpRequests
.requestMatchers(new AntPathRequestMatcher("/**")).permitAll())
;
return http.build();
}
}
🔻 스프링 시큐리티의 세부 설정은 SecurityFilterChain 빈(@Bean)을 생성하여 설정할 수 있다.
➜ 다음 코드는 모든 인증되지 않은 요청을 허락한다는 의미로, 로그인을 하지 않더라도 모든 페이지에 접근할 수 있다.
http
.authorizeHttpRequests((authorizeHttpRequests) -> authorizeHttpRequests
.requestMatchers(new AntPathRequestMatcher("/**")).permitAll())
;
@Configuration
- 스프링의 환경설정 파일임을 알려주는 애너테이션인 동시에, "Bean" 을 수동으로 등록하기 위해 꼭 필요한 애너테이션이다 !
➜ 위의 코드에선 스프링 시큐리티의 설정을 위해 사용되었다.
Bean 등록 (참고 자료) - [Spring] Bean (+ Proxy Pattern, CGLIB, Singleton, AOP) — Uykm_Note (tistory.com)
[Spring] Bean
▼ Why ? MVC 패턴을 공부하면서 MVC 구조에서의 ' Model ' 역할을 하는 것이 Bean이라는 것을 알게 되었다. 그리고 이번에 진행하고 있는 "Donggram" 웹 개발 프로젝트에서 팀원이 작성한 코드에서 ' @Bean '
ukym-tistory.tistory.com
@EnableWebSecurity
- 모든 URL 요청이 스프링 시큐리티의 제어를 받도록 만들어주는 애너테이션이다.
( 내부적으로 SpringSecurityFilterChain이 동작하여 URL 필터가 적용된다. )
H2 Console
- H2 콘솔 로그인 시에 아래와 같은 403 에러가 발생한다.
➜ 스프링 시큐리티를 적용하면, "CSRF(Cross Site Request Forgery)" 가 동작하기 때문이다 !
➜ 스프링 시큐리티가 CSRF 토큰을 발행하고 웹 페이지에 폼을 전송시에 해당 토큰을 함께 전송한다.
CSRF(cross site request forgery)는 웹 사이트 취약점 공격을 방지를 위해 사용하는 기술이다. 스프링 시큐리티가 CSRF 토큰 값을 세션을 통해 발행하고 웹 페이지에서는 폼 전송시에 해당 토큰을 함께 전송하여 실제 웹 페이지에서 작성된 데이터가 전달되는지를 검증하는 기술이다.
- 브라우저에서 질문 등록 화면의 소스를 살펴보면 아래와 같은 CSRF 토큰이 발행된 것을 확인할 수 있다.
<input type="hidden" name="_csrf" value="0d609fbc-b102-4b3f-aa97-0ab30c8fcfd4"/>
🔻 H2 콘솔은 스프링과 상관없는 일반 애플리케이션이기 때문에, CSRF 토큰을 발행하는 기능이 없는 H2 콘솔에선 CSRF에 의해 블락당해 403 에러가 발생하는 것이다 !

- 스프링 시큐리티가 CSRF 처리시에 H2 콘솔은 예외로 처리할 수 있도록 수정해주기만 하면 된다.
[ .../main/java/com/gdsc/webboard/SecurityConfig.java ]
...
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authorizeHttpRequests) -> authorizeHttpRequests
.requestMatchers(new AntPathRequestMatcher("/**")).permitAll())
// 추가
.csrf((csrf) -> csrf
.ignoringRequestMatchers(new AntPathRequestMatcher("/h2-console/**")))
;
return http.build();
}
}
- 이젠 CSRF 검증이 예외 처리되어 로그인 기능은 수행되지만, 아래처럼 화면이 깨지는 문제가 발생한다.
➜ 이 또한, 스프링 시큐리티에서 "Clickjacking" 공격을 막기 위해 해당 사이트의 콘텐츠가 다른 사이트에 포함되지 않도록 'X-Frame-Options' 헤더값을 사용하기 때문이다 !
➜ 이 경우도 스프링 시큐리티 설정 파일에서 'X-Frame-Options' 헤더의 값이 'SAMEORIGIN' 으로 설정되도록 수정해주면 된다.
[ .../main/java/com/gdsc/webboard/SecurityConfig.java ]
...
import org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authorizeHttpRequests) -> authorizeHttpRequests
.requestMatchers(new AntPathRequestMatcher("/**")).permitAll())
.csrf((csrf) -> csrf
.ignoringRequestMatchers(new AntPathRequestMatcher("/h2-console/**")))
// 추가
.headers((headers) -> headers
.addHeaderWriter(new XFrameOptionsHeaderWriter(
XFrameOptionsHeaderWriter.XFrameOptionsMode.SAMEORIGIN)))
;
return http.build();
}
}

- 아래처럼 정상 동작하는 것을 확인할 수 있다 !

▼ What ?
5주차에 배웠던 내용들을 이어서 마지막으로 '스프링 시큐리티' 라는 것에 대해서 정리해보려고 한다. 스프링 시큐리티 환경설정을 위해 수동으로 'SpringFilterChain' 을 빈(Bean)으로 등록하는 과정에서 '@Configuration' 애너테이션을 사용하는데, 수동/자동으로 빈을 등록하는 과정이 잘 기억나지 않았고 빈에 대한 이해도 아직 부족한 것 같아 다시 찾아보고 공부해보는 시간을 가졌다.
▼ 스프링 시큐리티 (Spring Security)
스프링 시큐리티 ?
- "스프링 시큐리티" 는 스프링 기반 애플리케이션의 권한과 인증을 담당하는 스프링의 하위 프레임워크이다.
➜ 쉽게 말해서 "인증(Authenticate)" 은 로그인을 의미하고, "권한(Authorize)" 은 그렇게 인증된 사용자가 어떤 것까지 할 수 있는지를 의미한다.
스프링 시큐리티를 설치하는 방법
- 이전처럼 build.gradle 파일을 수정해주면 된다.
➜ 스프링 시큐리티와 이와 관련된 타임리프 라이브러리를 사용하도록 설정 !
( 설정 후 "Refresh Gradle Project" 실행 잊지 말기. )
[ /webboard/build.gradle ]
dependencies {
...
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6:3.1.1.RELEASE'
}
스프링 시큐리티 재설정
- 스프링 시큐리티는 아래와 같이 기본적으로 인증(로그인)이 된 사용자만 서비스를 사용 가능하도록 되어있다.
➜ 하지만, 우리는 "WEBBOARD" 라는 게시판 사이트를 만드는 것이기 때문에, 게시만 특성에 따라 로그인 없이도 게시물을 확인할 수 있게 스프링 시큐리티를 추가적으로 설정해줘야 한다 !

- 'SecurityConfig' 라는 클래스를 따로 생성해주자.
[ .../main/java/com/gdsc/webboard/SecurityConfig.java ]
package com.mysite.sbb;
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;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authorizeHttpRequests) -> authorizeHttpRequests
.requestMatchers(new AntPathRequestMatcher("/**")).permitAll())
;
return http.build();
}
}
🔻 스프링 시큐리티의 세부 설정은 SecurityFilterChain 빈(@Bean)을 생성하여 설정할 수 있다.
➜ 다음 코드는 모든 인증되지 않은 요청을 허락한다는 의미로, 로그인을 하지 않더라도 모든 페이지에 접근할 수 있다.
http
.authorizeHttpRequests((authorizeHttpRequests) -> authorizeHttpRequests
.requestMatchers(new AntPathRequestMatcher("/**")).permitAll())
;
@Configuration
- 스프링의 환경설정 파일임을 알려주는 애너테이션인 동시에, "Bean" 을 수동으로 등록하기 위해 꼭 필요한 애너테이션이다 !
➜ 위의 코드에선 스프링 시큐리티의 설정을 위해 사용되었다.
Bean 등록 (참고 자료) - [Spring] Bean (+ Proxy Pattern, CGLIB, Singleton, AOP) — Uykm_Note (tistory.com)
[Spring] Bean
▼ Why ? MVC 패턴을 공부하면서 MVC 구조에서의 ' Model ' 역할을 하는 것이 Bean이라는 것을 알게 되었다. 그리고 이번에 진행하고 있는 "Donggram" 웹 개발 프로젝트에서 팀원이 작성한 코드에서 ' @Bean '
ukym-tistory.tistory.com
@EnableWebSecurity
- 모든 URL 요청이 스프링 시큐리티의 제어를 받도록 만들어주는 애너테이션이다.
( 내부적으로 SpringSecurityFilterChain이 동작하여 URL 필터가 적용된다. )
H2 Console
- H2 콘솔 로그인 시에 아래와 같은 403 에러가 발생한다.
➜ 스프링 시큐리티를 적용하면, "CSRF(Cross Site Request Forgery)" 가 동작하기 때문이다 !
➜ 스프링 시큐리티가 CSRF 토큰을 발행하고 웹 페이지에 폼을 전송시에 해당 토큰을 함께 전송한다.
CSRF(cross site request forgery)는 웹 사이트 취약점 공격을 방지를 위해 사용하는 기술이다. 스프링 시큐리티가 CSRF 토큰 값을 세션을 통해 발행하고 웹 페이지에서는 폼 전송시에 해당 토큰을 함께 전송하여 실제 웹 페이지에서 작성된 데이터가 전달되는지를 검증하는 기술이다.
- 브라우저에서 질문 등록 화면의 소스를 살펴보면 아래와 같은 CSRF 토큰이 발행된 것을 확인할 수 있다.
<input type="hidden" name="_csrf" value="0d609fbc-b102-4b3f-aa97-0ab30c8fcfd4"/>
🔻 H2 콘솔은 스프링과 상관없는 일반 애플리케이션이기 때문에, CSRF 토큰을 발행하는 기능이 없는 H2 콘솔에선 CSRF에 의해 블락당해 403 에러가 발생하는 것이다 !

- 스프링 시큐리티가 CSRF 처리시에 H2 콘솔은 예외로 처리할 수 있도록 수정해주기만 하면 된다.
[ .../main/java/com/gdsc/webboard/SecurityConfig.java ]
...
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authorizeHttpRequests) -> authorizeHttpRequests
.requestMatchers(new AntPathRequestMatcher("/**")).permitAll())
// 추가
.csrf((csrf) -> csrf
.ignoringRequestMatchers(new AntPathRequestMatcher("/h2-console/**")))
;
return http.build();
}
}
- 이젠 CSRF 검증이 예외 처리되어 로그인 기능은 수행되지만, 아래처럼 화면이 깨지는 문제가 발생한다.
➜ 이 또한, 스프링 시큐리티에서 "Clickjacking" 공격을 막기 위해 해당 사이트의 콘텐츠가 다른 사이트에 포함되지 않도록 'X-Frame-Options' 헤더값을 사용하기 때문이다 !
➜ 이 경우도 스프링 시큐리티 설정 파일에서 'X-Frame-Options' 헤더의 값이 'SAMEORIGIN' 으로 설정되도록 수정해주면 된다.
[ .../main/java/com/gdsc/webboard/SecurityConfig.java ]
...
import org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authorizeHttpRequests) -> authorizeHttpRequests
.requestMatchers(new AntPathRequestMatcher("/**")).permitAll())
.csrf((csrf) -> csrf
.ignoringRequestMatchers(new AntPathRequestMatcher("/h2-console/**")))
// 추가
.headers((headers) -> headers
.addHeaderWriter(new XFrameOptionsHeaderWriter(
XFrameOptionsHeaderWriter.XFrameOptionsMode.SAMEORIGIN)))
;
return http.build();
}
}

- 아래처럼 정상 동작하는 것을 확인할 수 있다 !
