티스토리 뷰

스프링 시큐리티 : 스프링 기반 웹 애플리케이션의 "인증과 권한을 담당하는 스프링의 하위 프레임워크"

인증(authenticate) : 로그인과 같은 사용자의 신원을 확인하는 프로세스

권한(authrize) : 인증된 사용자가 어떤 일을 할 수 있는지 (어떤 접근 권한이 있는지) 관리하는 것

 

 

스프링 부트는 회원가입과 로그인을 도와주는 스프링 시큐리티를 사용할 수 있다.

스프링 시큐리티로 회원가입과 로그인을 구현할 것이다.

 

스프링 시큐리티 설치하기

1) build.gradle 파일에 스프링 시큐리티 설치

dependencies {
	//스프링 시큐리티
	implementation 'org.springframework.boot:spring-boot-starter-security'
	//타임리프 템플릿 엔진과, 스프링 시큐리티를 함께 사용할 때 필요한 타임리프 확장기능
	implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6'
}

 

 

스프링 시큐리티 설정하기

1) 설치 후 localhost:8080 접속하여 아래와 같은 화면이 뜨는걸 확인한다.

 

스프링 시큐리티는 인증되지 않은 사용자가 웹 서비스에 접근 시, "사용자 인증을 위해" 로그인 화면을 띄운다.

이러한 시큐리티의 기본 기능을 꺼두도록 설정을 바꾸어야 한다.

왜냐하면 게시물 조회 같은 기능의 경우, 로그인을 하지 않아도 사용할 수 있어야 하기 때문이다.

 

 

 

2) 스프링 시큐리티 설정을 담당할 SecurityConfig.java 파일을 작성하고 스프링 시큐리티 접속 설정을 작성한다.

package com.study.board;

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();
    }
}

 

@Configuration

: 이 파일이 스프링의 환경 설정 파일임을 의미하는 어노테이션. 여기서는 스프링 시큐리티를 설정하기 위해 사용함.

 

@EnableWebSecurity

: 모든 요청 URL이 스프링 시큐리티의 제어를 받도록 만드는 어노테이션.

이 어노테이션을 사용하면 스프링 시큐리티를 활성화하는 역할을 한다.

 

내부적으로 SecurityFilterChain 클래스가 동작하여 모든 요청 URL에 이 클래스가 필터로 적용되어

URL 별로 특별한 설정을 할 수 있게 된다.

스프링 시큐리티의 세부 설정은 @Bean 을 통해 SecurityFilerChain 빈을 생성하여 설정할 수 있다. 

 

* 빈이란?

: Bean은 스프링에 의해 생성 또는 관리되는 객체를 의미한다. 컨트롤러, 서비스, 리포지터리 등도 모두 빈에 해당한다. 또한 @Bean 어노테이션을 통해 자바 코드 내에서 별도로 빈을 정의하고 등록할 수도 있다.

 

 

위 파일을 작성하고 localhost:8080 접속 시

더이상 로그인 폼 화면이 보이지 않고 기존 프로젝트 화면대로 잘 보인다.

 

 

H2 콘솔 오류 수정하기

1) H2 콘솔 화면인 localhost:8080/h2-console 에 접속해서 확인한다. 아래와 같은 오류가 발생했다.

 

 

403 오류는 작동 중인 서버에 클라이언트의 요청이 들어왔으나, 

서버가 클라이언트의 접근을 거부했을 때 반환하는 HTTP 오류 코드다.

이 오류는 서버 또는 서버에 있는 파일 등에 접근 권한이 없을 경우 발생한다.

 

더 구체적으로 설명하자면, 스프링 시큐리티의 CSRF 방어 기능에 의해 H2 콘솔 접근이 거부되기 때문이다.

CSRF는 웹 보안 공격 중 하나로, 조작된 정보로 웹 사이트가 실행되도록 속이는 공격 기술이다.

 

스프링 시큐리티는 이러한 공격을 방지하기 위해, CSRF 토큰을 세션을 통해 발행하고,

웹 페이지에서는 폼 전송 시에 해당 토큰을 함께 전송하여 실제 웹 페이지에서 작성한 데이터가 전달되는지를 검증한다.

 

* 토큰이란 : 요청을 식별하고 검증하는 데 사용하는 특수한 문자열(값)

* 세션이란 : 사용자의 상태를 유지하고 관리하는 데 사용하는 기능

 

 

 

form 태그가 사용된 화면에서 [마우스 우클릭 -> 페이지 소스 보기]를 하면 csrf 코드를 확인해볼 수 있다.

답변을 작성하는 form 밑에 input type="hidden"으로 csrf가 자동으로 작성되었다.

* csrf 토큰은 서버에서 생성되는 임의의 값으로, 페이지 요청마다 항상 다른 값으로 생성됨.

 

스프링 시큐리티는 이런식으로 페이지에 csrf 토큰을 발행하여 이 값이 다시 서버로 정확하게 들어오는지 확인하는 과정을 거친다.

만약 csrf 토큰이 없거나, 해커가 임의로 csrf 토큰을 만들어 전송한다면 시큐리티에 의해 차단된다.

 

 

H2 콘솔은 스프링 프레임워크가 아니므로, CSRF 토큰을 발행하는 기능이 없다.

그리하여 시큐리티에 의해 차단되어 이와 같은 403 오류가 발생한 것이다.

(H2 콘솔은 스프링과 상관없는 일반 어플리케이션임.)

 

 

2) 스프링 시큐리티가 CSRF 처리시 H2 콘솔은 예외로 처리할 수 있도록 SecurityConfig.java 파일을 아래와 같이 수정한다.

(... 생략 ...)

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    @Bean
    SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            // 모든 화면에 인증 체크 없이 접근 가능하게 함
            .authorizeHttpRequests((authorizeHttpRequests) -> authorizeHttpRequests
            	.requestMatchers(new AntPathRequestMatcher("/**")).permitAll())
            //H2 콘솔 화면은 CSRF 토큰 체크 시 예외로 함
            .csrf((csrf) -> csrf
            	.ignoringRequestMatchers(new AntPathRequestMatcher("/h2-console/**")))
        ;
        return http.build();
    }
}

 

/h2-console/ 로 시작하는 모든 URL은 CSRF 검증을 하지 않는다는 설정을 추가했다.

 

 

 

3) 다시 localhost:8080/h2-console 에 접속해서 확인한다. 아래와 같은 오류가 발생했다.

이렇게 화면이 깨져서 보일 것이다.

 

이와 같이 오류가 발생하는 원인은 H2 콘솔의 화면이 프레임(frame) 구조로 작업되었기 때문이다.

즉, H2 콘솔 UI 레이아웃이 이 화면처럼 작업 영역이 나눠져 있음을 의미한다.

스프링 시큐리티는 웹 사이트의 콘텐츠가 다른 사이트에 포함되지 않도록 하기 위해

X-Frame-Options 헤더의 기본값을 DENY 로 사용하는데, 

프레임 구조의 웹 사이트는 이 헤더의 값이 DENY인 경우 이와 같은 오류가 발생한다.

 

* 스프링 부트에서 X-Frame-Options 헤더는 클릭재킹 공격을 막기 위해 사용한다. 클릭재킹은 사용자의 의도와 다른 작업이 수행되도록 속이는 보안 공격이다.

 

 

4) 프레임이 깨지는 오류를 해결하기 위해 SecurityConfig.java 파일을 아래와 같이 수정한다.

package com.study.board;

(... 생략 ...)
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())
            //H2 콘솔 화면은 CSRF 토큰 체크 시 예외로 함
            .csrf((csrf) -> csrf
            	.ignoringRequestMatchers(new AntPathRequestMatcher("/h2-console/**")))
            //H2 콘솔 화면 프레임 깨짐 방지 (X-Frame-Options 값을 SAMEORIGIN 으로)
            .headers((headers) -> headers
            	.addHeaderWriter(new XFrameOptionsHeaderWriter(
                	XFrameOptionsHeaderWriter.XFrameOptionsMode.SAMEORIGIN)))
        ;
        return http.build();
    }
}

 

위와 같이 X-Frame-Options 헤더의 값을 SAMEORIGIN 으로 설정하면

프레임에 포함된 웹 페이지가 동일한 사이트에서 제공할 때에만 사용이 허락된다.

 

즉, H2 콘솔의 모든 프레임들이, 동일한 사이트에서 제공하고 있다면, 프레임이 깨지지 않고 정상적으로 보일 것이다.

 

 

5) 다시 H2 콘솔 화면에 접근해서 확인해본다. 오류없이 정상적으로 동작한다.

 

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
글 보관함