[SpringBoot] 스프링 시큐리티+타임리프로 회원가입/로그인/로그아웃 구현하기 - (1)

최가희·2022년 7월 31일
0

SpringBoot

목록 보기
7/13
post-thumbnail

스프링 시큐리티 설치

build.gradle 파일에 관련 의존성을 추가한다.

dependencies {
    ...
    // 스프링 시큐리티
    implementation 'org.springframework.boot:spring-boot-starter-security'
    // 스프링 시큐리티 관련 타임리프 라이브러리
    implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5'
}

이렇게 스프링 시큐리티를 설치하고 서버를 돌리면 다음과 같은 로그인 화면이 나타난다.

로그인 없이도 게시물을 조회할 수 있게 하기 위해서는 시큐리티 설정을 해야 한다.

시큐리티 설정

SecurityConfig.java

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.authorizeRequests().antMatchers("/**").permitAll();
        return http.build();
    }
  • @Configuration
    스프링의 환경설정 파일임을 의미하는 어노테이션
  • @EnableWebSecurity
    모든 요청 URL이 스프링 시큐리티의 제어를 받도록 만드는 어노테이션으로, 이 어노테이션을 사용하면 내부적으로 SpringSecurityFilterChain이 동작하여 URL 필터가 적용된다.
  • 스프링 시큐리티의 세부 설정은 SecurityFilterChain 빈을 생성하여 설정할 수 있다.

그러나 스프링 시큐리티를 적용하면 h2 콘솔 로그인 시 다음과 같은 403 Forbidden 오류가 발생한다.

스프링 시큐리티를 적용하면 CSRF 기능이 동작하기 때문이다.

+) CSRF(Cross Site Request Forgery)
웹 사이트 취약점 공격을 방지하기 위해 사용하는 기술. 스프링 시큐리티가 CSRF 토큰 값을 세션을 통해 발행하고, 웹 페이지에서는 폼 전송 시에 해당 토큰을 함께 전송하여 실제 웹 페이지에서 작성된 데이터가 전달되는지 검증한다.

질문 등록 화면을 열고 브라우저의 소스보기 기능을 이용하여 코드를 확인해보면, 다음과 같이 input 엘리먼트가 form 태그 밑에 자동으로 생성된 것을 확인할 수 있다.

<input type="hidden" name="_csrf" value="0d609fbc-b102-4b3f-aa97-0ab30c8fcfd4"/>

스프링 시큐리티에 의해 CSRF 토큰이 자동 생성된 것이다. 즉, 스프링 시큐리티는 이렇게 발행한 CSRF 토큰의 값이 정확한지 검증하는 과정을 거치는데, 만약 CSRF 값이 없거나 임의의 CSRF 값을 강제로 만들어 전송하는 악의적인 URL 요청이 발생하면 스프링 시큐리티가 블록킹한다.

h2 콘솔은 이와 같은 CSRF 토큰을 발행하는 기능이 없기 때문에 403 에러가 발생하는 것이다. (h2 콘솔은 스프링과 상관없는 일반 애플리케이션이기 때문이다.)

스프링 시큐리티가 CSRF 처리 시 h2 콘솔은 예외로 처리할 수 있도록 설정 파일을 수정한다.

SecurityConfig.java

...

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{
        // 모든 인증되지 않은 요청을 허락
        http.authorizeRequests().antMatchers("/**").permitAll()
        		/* 추가된 부분 */
                .and()
                .csrf().ignoringAntMatchers("/h2-console/**");
                /* 추가된 부분 end*/
        return http.build();
    }
}

이렇게 수정하고 나서 다시 h2 콘솔에 접속하면, CSRF 검증은 예외 처리되어 로그인은 되지만 또 다음처럼 화면이 깨져보인다. h2 콘솔 화면이 frame 구조로 작성되었기 때문인데, 스프링 시큐리티는 사이트의 콘텐츠가 다른 사이트에 포함되지 않도록 하기 위해 X-Frame-Options 헤더값을 사용하여 이를 방지한다. (clickjacking 공격을 막기위해 사용)

다음과 같이 설정 파일을 수정한다.

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.header.writers.frameoptions.XFrameOptionsHeaderWriter;

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{
        // 모든 인증되지 않은 요청을 허락
        http.authorizeRequests().antMatchers("/**").permitAll()
                .and()
                    .csrf().ignoringAntMatchers("/h2-console/**")
                 /* 추가된 부분 */
                .and()
                    .headers()
                    .addHeaderWriter(new XFrameOptionsHeaderWriter(XFrameOptionsHeaderWriter.XFrameOptionsMode.SAMEORIGIN));
                 /* 추가된 부분 end */
        return http.build();
    }
}

URL 요청 시 X-Frame-Options 헤더값을 SAMEORIGIN으로 설정하면 frame에 포함된 페이지가 페이지를 제공하는 사이트와 동일한 경우에는 계속 사용할 수 있다.
무슨 말이지?

이제 다시 h2 콘솔로 로그인하면 정상 동작하는 것을 확인할 수 있다.


참고

점프 투 스프링부트

0개의 댓글