03E. μ€νλ§ μν리ν°
03E. μ€νλ§ μνλ¦¬ν° κ΄λ ¨
μ€νλ§λΆνΈλ νμκ°μ κ³Ό λ‘κ·ΈμΈμ λμμ£Όλ μ€νλ§ μν리ν°(Spring Security)λ₯Ό μ¬μ©ν μ μλ€. SBBλ μ€νλ§ μν리ν°λ₯Ό μ¬μ©νμ¬ νμκ°μ κ³Ό λ‘κ·ΈμΈ κΈ°λ₯μ λ§λ€ κ²μ΄λ€. κ·Έ μ μ μ€νλ§ μν리ν°μ λν΄μ κ°λ¨νκ² μμλ³΄κ³ νμν μ€μ λ μ§νν΄ λ³΄μ.
μ€νλ§ μν리ν°λ?
μ€νλ§ μν리ν°λ μ€νλ§ κΈ°λ° μ ν리μΌμ΄μ μ μΈμ¦κ³Ό κΆνμ λ΄λΉνλ μ€νλ§μ νμ νλ μμν¬μ΄λ€.
- μΈμ¦(Authenticate)μ λ‘κ·ΈμΈμ μλ―Ένλ€.
- κΆν(Authorize)μ μΈμ¦λ μ¬μ©μκ° μ΄λ€ κ²μ ν μ μλμ§λ₯Ό μλ―Ένλ€.
μ€νλ§ μνλ¦¬ν° μ€μΉ
μ€νλ§ μνλ¦¬ν° μ¬μ©μ μν΄ λ€μκ³Ό κ°μ΄ build.gradle
νμΌμ μμ νμ.
νμΌλͺ :
/sbb/
build.gradle
// (... μλ΅ ...)
dependencies {
// (... μλ΅ ...)
implementation "org.springframework.boot:spring-boot-starter-security"
implementation "org.thymeleaf.extras:thymeleaf-extras-springsecurity6:3.1.1.RELEASE"
}
// (... μλ΅ ...)
μ€νλ§ μν리ν°μ μ΄μ κ΄λ ¨λ νμ리ν λΌμ΄λΈλ¬λ¦¬λ₯Ό μ¬μ©νλλ‘ μ€μ νλ€. "[Refresh Gradle Project]
"λ₯Ό μννμ¬ νμν λΌμ΄λΈλ¬λ¦¬λ₯Ό μ€μΉν ν λ‘컬μλ²λ μ¬μμ νμ.
thymeleaf-extras-springsecurity6
thymeleaf-extras-springsecurity6
ν¨ν€μ§λ₯Ό μ¬μ©νκΈ° μν΄ λ€μ 3.1.1.RELEASE
κ³Ό κ°μ λ²μ μ 보λ₯Ό μΆκ°νλ€. thymeleaf-extras-springsecurity6
ν¨ν€μ§λ μ€νλ§λΆνΈκ° μ체μ μΌλ‘ κ΄λ¦¬νλ ν¨ν€μ§μ΄κΈ° λλ¬Έμ λ²μ μ λ³΄κ° νμμμ§λ§ νμ¬ μ¬μ©μ€μΈ μ€νλ§λΆνΈ λ²μ μΈ 3.0.0 λ²μ μμλ μμ κ°μ λ²μ μ 보λ₯Ό μ
λ ₯νμ§ μμΌλ©΄ μ€λ₯κ° λ°μνλ€. λ§μ½ λ²μ μ 보λ₯Ό μ κ±°νκ³ μ¬μ©νλλΌλ μ€λ₯κ° μλ€λ©΄ λ²μ μ 보 μμ΄ μ¬μ©νκΈ° λ°λλ€.
μ€νλ§ μνλ¦¬ν° μ€μ
μ€νλ§ μν리ν°λ₯Ό μ€μΉνκ³ λ‘컬μλ²λ₯Ό μ¬μμν νμ SBBμ μ§λ¬Έ λͺ©λ‘ νλ©΄μ μ μν΄ λ³΄μ. μλ§λ λ€μκ³Ό κ°μ λ‘κ·ΈμΈ νλ©΄μ΄ λνλμ κΉμ§ λλ κ²μ΄λ€.
μ€νλ§ μν리ν°λ κΈ°λ³Έμ μΌλ‘ μΈμ¦λμ§ μμ μ¬μ©μλ μλΉμ€λ₯Ό μ¬μ©ν μ μκ²λ λμ΄ μλ€. λ°λΌμ μΈμ¦μ μν λ‘κ·ΈμΈ νλ©΄μ΄ λνλλ κ²μ΄λ€. νμ§λ§ μ΄λ¬ν κΈ°λ³Έ κΈ°λ₯μ SBBμ κ·Έλλ‘ μ μ©νκΈ°μλ κ³€λνλ―λ‘ μν리ν°μ μ€μ μ ν΅ν΄ λ°λ‘ μ‘μμΌ νλ€.
SBBλ λ‘κ·ΈμΈ μμ΄λ κ²μλ¬Όμ μ‘°νν μ μμ΄μΌ νλ€.
λ€μκ³Ό κ°μ΄ SecurityConfig.java νμΌμ μμ±νμ.
νμΌλͺ :
/sbb/src/main/java/com/mysite/sbb/
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();
}
}
@Configuration
μ μ€νλ§μ νκ²½μ€μ νμΌμμ μλ―Ένλ μ λν
μ΄μ
μ΄λ€. μ¬κΈ°μλ μ€νλ§ μν리ν°μ μ€μ μ μν΄ μ¬μ©λμλ€. @EnableWebSecurity
λ λͺ¨λ μμ² URLμ΄ μ€νλ§ μν리ν°μ μ μ΄λ₯Ό λ°λλ‘ λ§λλ μ λν
μ΄μ
μ΄λ€.
@EnableWebSecurity
μ λν μ΄μ μ μ¬μ©νλ©΄ λ΄λΆμ μΌλ‘SpringSecurityFilterChain
μ΄ λμνμ¬ URL νν°κ° μ μ©λλ€.
μ€νλ§ μν리ν°μ μΈλΆ μ€μ μ SecurityFilterChain
λΉμ μμ±νμ¬ μ€μ ν μ μλ€. λ€μ λ¬Έμ₯μ λͺ¨λ μΈμ¦λμ§ μμ μμ²μ νλ½νλ€λ μλ―Έμ΄λ€. λ°λΌμ λ‘κ·ΈμΈμ νμ§ μλλΌλ λͺ¨λ νμ΄μ§μ μ κ·Όν μ μλ€.
http
.authorizeHttpRequests((authorizeHttpRequests) -> authorizeHttpRequests
.requestMatchers(new AntPathRequestMatcher("/**")).permitAll())
;
μ΄λ κ² μ€νλ§ μνλ¦¬ν° μ€μ νμΌμ ꡬμ±νλ©΄ μ΄μ μ§λ¬Έ λͺ©λ‘, μ§λ¬Έ λ΅λ³ λ±μ κΈ°λ₯μ μ΄μ κ³Ό λμΌνκ² μ¬μ©ν μ μλ€.
H2 μ½μ
νμ§λ§ μ€νλ§ μν리ν°λ₯Ό μ μ©νλ©΄ H2 μ½μ λ‘κ·ΈμΈμ λ€μκ³Ό κ°μ 403 Forbidden μ€λ₯κ° λ°μνλ€.
403 Forbidden μ€λ₯κ° λ°μνλ μ΄μ λ μ€νλ§ μν리ν°λ₯Ό μ μ©νλ©΄ CSRF κΈ°λ₯μ΄ λμνκΈ° λλ¬Έμ΄λ€.
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 μ½μμ μμΈλ‘ μ²λ¦¬ν μ μλλ‘ λ€μκ³Ό κ°μ΄ μ€μ νμΌμ μμ νμ.
// (... μλ΅ ...)
@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();
}
}
/h2-console/
λ‘ μμνλ URLμ CSRF κ²μ¦μ νμ§ μλλ€λ μ€μ μ μΆκ°νλ€. μ΄λ κ² μμ νκ³ λ€μ H2 μ½μμ μ μν΄ λ³΄μ. μ΄μ CSRF κ²μ¦μ΄ μμΈ μ²λ¦¬λμ΄ λ‘κ·ΈμΈμ μνλμ§λ§ λ€μμ²λΌ νλ©΄μ΄ κΉ¨μ Έλ³΄μΈλ€.
μ΄ μ€λ₯κ° λ°μνλ μμΈμ H2 μ½μμ νλ©΄μ΄ frame κ΅¬μ‘°λ‘ μμ±λμκΈ° λλ¬Έμ΄λ€. μ€νλ§ μν리ν°λ μ¬μ΄νΈμ μ½ν
μΈ κ° λ€λ₯Έ μ¬μ΄νΈμ ν¬ν¨λμ§ μλλ‘ νκΈ° μν΄ X-Frame-Options
ν€λκ°μ μ¬μ©νμ¬ μ΄λ₯Ό λ°©μ§νλ€. (clickjacking 곡격μ λ§κΈ°μν΄ μ¬μ©ν¨)
μ΄ λ¬Έμ λ₯Ό ν΄κ²°νκΈ° μν΄ λ€μκ³Ό κ°μ΄ μ€μ νμΌμ μμ νμ.
package com.mysite.sbb;
// (... μλ΅ ...)
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();
}
}
μ μ²λΌ URL μμ²μ X-Frame-Options
ν€λκ°μ sameorigin
μΌλ‘ μ€μ νμ¬ μ€λ₯κ° λ°μνμ§ μλλ‘ νλ€. X-Frame-Options
ν€λμ κ°μΌλ‘ sameoriginμ μ€μ νλ©΄ frameμ ν¬ν¨λ νμ΄μ§κ° νμ΄μ§λ₯Ό μ 곡νλ μ¬μ΄νΈμ λμΌν κ²½μ°μλ κ³μ μ¬μ©ν μ μλ€.
μ΄μ λ€μ H2 μ½μλ‘ λ‘κ·ΈμΈνλ©΄ μ μ λμνλ κ²μ νμΈν μ μμ κ²μ΄λ€.