๐Ÿงฑ Spring Security 6 ๊ฐœ์š” & ๊ธฐ๋ณธ ์„ค์ • ์™„์ „ ์ •๋ฆฌ

okorionยท2025๋…„ 10์›” 6์ผ

๐Ÿ” Spring Security 6

๋ชฉ๋ก ๋ณด๊ธฐ
1/10
post-thumbnail

๐Ÿ“– ๋“ค์–ด๊ฐ€๋ฉฐ

์‹ค์ œ ์šด์˜ ํ™˜๊ฒฝ์—์„œ REST API๋Š” ์•„๋ฌด๋‚˜ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ ์™„์ „ํ•œ ์˜คํ”ˆ API ์ƒํƒœ๋กœ ์„œ๋น„์Šค๋ฅผ ๋ฐฐํฌํ•  ์ˆ˜๋Š” ์—†์Šต๋‹ˆ๋‹ค.

์ด๋ฒˆ ๊ธ€์—์„œ๋Š” Spring Security๊ฐ€ ์–ด๋–ป๊ฒŒ ๊ธฐ๋ณธ ๋ณด์•ˆ์„ ์ œ๊ณตํ•˜๋Š”์ง€, ๊ทธ๋ฆฌ๊ณ  Security ๊ตฌ์กฐ์˜ ๋‚ด๋ถ€ ๋™์ž‘์„ ๋‹จ๊ณ„๋ณ„๋กœ ๋ถ„์„ํ•ฉ๋‹ˆ๋‹ค.


#1. Spring Security ์˜์กด์„ฑ ์ถ”๊ฐ€๋กœ ์–ป๋Š” ๋ณ€ํ™”

Spring Boot ์•ฑ์— ๋‹ค์Œ ์˜์กด์„ฑ๋งŒ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-security</artifactId>
</dependency>

๋นŒ๋“œ ํ›„ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์žฌ์‹คํ–‰ํ•˜๋ฉด ์ฝ˜์†”์— ์ž๋™์œผ๋กœ ์ƒ์„ฑ๋œ ๋น„๋ฐ€๋ฒˆํ˜ธ(UUID)๊ฐ€ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

Using generated security password: a12b3c4d-...

์ด์ œ /welcome ๋“ฑ ์–ด๋–ค API๋ฅผ ํ˜ธ์ถœํ•˜๋”๋ผ๋„ Spring Security๊ฐ€ ์ž๋™์œผ๋กœ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ’ก ์ง์ ‘ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋ฅผ ๋งŒ๋“  ์ ์ด ์—†์–ด๋„ ์ž๋™์œผ๋กœ ๋‚˜ํƒ€๋‚˜๋Š” ์ด์œ ๋Š”,

DefaultLoginPageGeneratingFilter๊ฐ€ HTML ๋กœ๊ทธ์ธ ํ™”๋ฉด์„ ์ž๋™ ๋ Œ๋”๋งํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.


#2. ๊ธฐ๋ณธ ๋™์ž‘ ์š”์•ฝ

ํ•ญ๋ชฉ์„ค๋ช…
๊ธฐ๋ณธ ์‚ฌ์šฉ์ž ์ด๋ฆ„user
๊ธฐ๋ณธ ๋น„๋ฐ€๋ฒˆํ˜ธ์ฝ˜์†”์— ํ‘œ์‹œ๋œ UUID
๋กœ๊ทธ์ธ ํŽ˜์ด์ง€Spring Security ์ž๋™ ์ƒ์„ฑ
๋ณดํ˜ธ ๋ฒ”์œ„๋ชจ๋“  API (/**)

โœ… ๋กœ๊ทธ์ธ ์„ฑ๊ณต โ†’ API ์ •์ƒ ์‘๋‹ต

โœ… ์‹คํŒจ โ†’ 401 Unauthorized ๋˜๋Š” 403 Forbidden


#3. ๊ธฐ๋ณธ ๊ณ„์ • ๋ณ€๊ฒฝ (application.properties)

๋งค๋ฒˆ ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ๋ฐ”๋€Œ๋Š” ๊ฑด ๋ถˆํŽธํ•˜๋ฏ€๋กœ, ๋‹ค์Œ์ฒ˜๋Ÿผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.

spring.security.user.name=${SECURITY_USERNAME:eazybytes}
spring.security.user.password=${SECURITY_PASSWORD:12345}
  • :${} ๊ตฌ๋ฌธ โ†’ ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์—†์„ ๊ฒฝ์šฐ ๊ธฐ๋ณธ๊ฐ’ ์‚ฌ์šฉ
  • DevOps ํ™˜๊ฒฝ์—์„œ๋„ ์†์‰ฝ๊ฒŒ ์žฌ์ •์˜ ๊ฐ€๋Šฅ

์žฌ์‹œ์ž‘ ํ›„์—” ์ฝ˜์†”์— ๋” ์ด์ƒ ์ž„์‹œ ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ํ‘œ์‹œ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.


#4. ์„ธ์…˜ ๊ธฐ๋ฐ˜ ์ธ์ฆ ํ๋ฆ„

Spring Security๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์„ธ์…˜ ๊ธฐ๋ฐ˜ ์ธ์ฆ(Session-based Authentication)์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

์ฆ‰, ๋กœ๊ทธ์ธ ์„ฑ๊ณต ์‹œ JSESSIONID ์ฟ ํ‚ค๋ฅผ ๋ฐœ๊ธ‰ํ•˜๊ณ  ์ดํ›„ ์š”์ฒญ ์‹œ ์žฌ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ” ๋ธŒ๋ผ์šฐ์ €์—์„œ ํ™•์ธ

F12 โ†’ Application โ†’ Cookies โ†’ localhost:8080

์ฟ ํ‚ค๋ช…์—ญํ• 
JSESSIONID์ธ์ฆ ์„ธ์…˜ ์‹๋ณ„ ํ‚ค
๊ฐ’์„œ๋ฒ„์˜ SecurityContext์™€ ๋งคํ•‘๋จ

๐Ÿ’ก ์ฟ ํ‚ค๋ฅผ ์‚ญ์ œํ•˜๊ฑฐ๋‚˜ ์กฐ์ž‘ํ•˜๋ฉด ๋กœ๊ทธ์ธ ์ •๋ณด๊ฐ€ ์‚ฌ๋ผ์ง€๊ณ  ๋‹ค์‹œ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๊ฐ€ ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค.


#5. ์™œ ๋ณด์•ˆ์ด ์ค‘์š”ํ•œ๊ฐ€?

"์™œ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋ณดํ˜ธํ•ด์•ผ ํ•˜๋‚˜์š”?"

๋ฉด์ ‘ ๋‹จ๊ณจ ์งˆ๋ฌธ์ž…๋‹ˆ๋‹ค.

๐Ÿ” ๋น„์œ : ์€ํ–‰ ์‹œ์Šคํ…œ๊ณผ ๋ณด์•ˆ

  • ์€ํ–‰์€ ๊ธˆ๊ณ ยทCCTVยท๊ฒฝ๋น„ โ†’ ๊ฐ€์น˜ ์žˆ๋Š” ์ž์‚ฐ ๋ณดํ˜ธ
  • ์›น ์•ฑ๋„ ์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐยท๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์งยท์žฌ๋ฌด์ •๋ณด ๋“ฑ ๊ฐ€์น˜ ์žˆ๋Š” ์ž์‚ฐ์„ ๋ณด์œ 

์ฃผ์š” ๋ณดํ˜ธ ๋Œ€์ƒ

  1. ๊ฐœ์ธ/๋ฏผ๊ฐ ๋ฐ์ดํ„ฐ (PII)
  2. ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง
  3. ๊ธฐ์—… ์ง€์‹ ์ž์‚ฐ

๋ณด์•ˆ์„ ๋Šฆ๊ฒŒ ๋„ฃ์œผ๋ฉด ์•ˆ ๋˜๋Š” ์ด์œ 

๋ณด์•ˆ์€ โ€œ๋น„๊ธฐ๋Šฅ ์š”๊ตฌ์‚ฌํ•ญ(NFR)โ€์ด์ง€๋งŒ,

๊ฐœ๋ฐœ ์ดˆ๊ธฐ๋ถ€ํ„ฐ ๋ฐ˜์˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ‘‰ SDLC์˜ โ€œ์™ผ์ชฝ์œผ๋กœ ๋ณด์•ˆ ์ด๋™(Shift Left Security)โ€

โ†’ DevSecOps (Dev + Sec + Ops ํ˜‘์—…) ๊ฐœ๋… ๋“ฑ์žฅ


#6. ๋ณด์•ˆ์˜ ๊ณ„์ธต ๊ตฌ์กฐ

Spring Security๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ ˆ๋ฒจ ๋ณด์•ˆ์„ ๋‹ด๋‹นํ•ฉ๋‹ˆ๋‹ค.

์ „์ฒด ์ธํ”„๋ผ์˜ ๋ณด์•ˆ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ณ„์ธต ๊ตฌ์กฐ๋กœ ์ด๋ฃจ์–ด์ง‘๋‹ˆ๋‹ค.

[ํด๋ผ์šฐ๋“œ] โ†’ [VM/OS] โ†’ [์ปจํ…Œ์ด๋„ˆ] โ†’ [์•ฑ ์„œ๋ฒ„] โ†’ [Spring Security]
๊ณ„์ธต๋‹ด๋‹น์˜ˆ์‹œ
ํด๋ผ์šฐ๋“œ, VM, OS์šด์˜ํŒ€IAM, ๋ฐฉํ™”๋ฒฝ, SSL
์ปจํ…Œ์ด๋„ˆ, ์„œ๋ฒ„DevOpsHTTPS, ๋„คํŠธ์›Œํฌ ์ œ์–ด
์• ํ”Œ๋ฆฌ์ผ€์ด์…˜๊ฐœ๋ฐœ์ž์ธ์ฆ, ์ธ๊ฐ€, CSRF, CORS

#7. Spring Security ๋‚ด๋ถ€ ๊ตฌ์กฐ

Spring Security๋Š” Filter ๊ธฐ๋ฐ˜ ์•„ํ‚คํ…์ฒ˜๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ”น ๊ธฐ๋ณธ ์š”์ฒญ ํ๋ฆ„

Client โ†’ Security Filters โ†’ DispatcherServlet โ†’ Controller

๋ชจ๋“  ์š”์ฒญ์€ ์„œ๋ธ”๋ฆฟ ๋„๋‹ฌ ์ „ ๋‹ค์ˆ˜์˜ Security Filter (์•ฝ 20์—ฌ ๊ฐœ)๋ฅผ ๊ฑฐ์นฉ๋‹ˆ๋‹ค.

ํ•„ํ„ฐ์—ญํ• 
AuthorizationFilter์ธ์ฆ๋˜์ง€ ์•Š์€ ์š”์ฒญ ๊ฐ์‹œ
DefaultLoginPageGeneratingFilter๋กœ๊ทธ์ธ ํŽ˜์ด์ง€ ์ƒ์„ฑ
UsernamePasswordAuthenticationFilter๋กœ๊ทธ์ธ ์ž๊ฒฉ ์ฆ๋ช… ์ถ”์ถœ
BasicAuthenticationFilterHTTP Basic ์ฒ˜๋ฆฌ
CsrfFilterCSRF ๊ณต๊ฒฉ ๋ฐฉ์–ด
SecurityContextPersistenceFilter์„ธ์…˜ ์œ ์ง€

#8. ์ธ์ฆ(Authentication) ๊ณผ์ • ํ๋ฆ„

  • ์ฒซ ์š”์ฒญ: AuthenticationManager โ†’ AuthenticationProvider๊ฐ€ ์ธ์ฆ ์ˆ˜ํ–‰
  • ์„ฑ๊ณต ์‹œ: SecurityContext์— ์ €์žฅ, ์„ธ์…˜ ์œ ์ง€
  • ์ดํ›„ ์š”์ฒญ: ์„ธ์…˜ ์ธ์ฆ ์žฌ์‚ฌ์šฉ (JSESSIONID ๊ธฐ๋ฐ˜)

#9. ๊ธฐ๋ณธ Security ์„ค์ • ๋ถ„์„

Spring Boot๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ SpringBootWebSecurityConfiguration์„ ํ†ตํ•ด ์•„๋ž˜ ๋””ํดํŠธ ๊ตฌ์„ฑ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

@Bean
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
    http.authorizeHttpRequests(req -> req.anyRequest().authenticated());
    http.formLogin(Customizer.withDefaults());
    http.httpBasic(Customizer.withDefaults());
    return http.build();
}

๐Ÿ“Œ ์˜๋ฏธ

  • ๋ชจ๋“  ์š”์ฒญ(anyRequest()) ์ธ์ฆ ํ•„์š”
  • formLogin() โ†’ ๋ธŒ๋ผ์šฐ์ € ๋กœ๊ทธ์ธ UI ์ œ๊ณต
  • httpBasic() โ†’ REST ํด๋ผ์ด์–ธํŠธ์—์„œ ํ—ค๋” ์ธ์ฆ

#10. ์‚ฌ์šฉ์ž ์ •์˜ SecurityFilterChain

@Configuration
public class ProjectSecurityConfig {

    @Bean
    SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests(req -> req
            .requestMatchers("/myAccount", "/myBalance", "/myLoans", "/myCards").authenticated()
            .requestMatchers("/notices", "/contact", "/error").permitAll()
        );

        http.formLogin(Customizer.withDefaults());
        http.httpBasic(Customizer.withDefaults());
        return http.build();
    }
}

โœ… requestMatchers() ๋กœ ๊ฒฝ๋กœ๋ณ„ ์ ‘๊ทผ ์ œ์–ด

โœ… permitAll() โ†’ ๋ˆ„๊ตฌ๋‚˜ ์ ‘๊ทผ ๊ฐ€๋Šฅ

โœ… authenticated() โ†’ ๋กœ๊ทธ์ธ ํ•„์š”


#11. formLogin vs httpBasic

๊ตฌ๋ถ„ํŠน์ง•์‚ฌ์šฉ ์ƒํ™ฉ
formLogin()HTML ๋กœ๊ทธ์ธ UI ์ž๋™ ์ƒ์„ฑ๋ธŒ๋ผ์šฐ์ € ํ™˜๊ฒฝ
httpBasic()ํ—ค๋”์— Base64 ์ธ์ฝ”๋”ฉ ์ธ์ฆ ์ •๋ณด ํฌํ•จREST ํด๋ผ์ด์–ธํŠธ, Postman
http.formLogin(flc -> flc.disable());
http.httpBasic(hbc -> hbc.disable());

โ†’ ๋‘˜ ๋‹ค ๋น„ํ™œ์„ฑํ™” ์‹œ ์ธ์ฆ ๋ถˆ๊ฐ€ (403 Forbidden)


#12. Postman์œผ๋กœ ์ธ์ฆ ํ…Œ์ŠคํŠธ

  1. Postman ์‹คํ–‰ โ†’ ์ƒˆ ์š”์ฒญ ์ƒ์„ฑ

  2. URL ์ž…๋ ฅ

    GET http://localhost:8080/myAccount
    
  3. Authorization ํƒญ โ†’ Basic Auth ์„ ํƒ

    • Username: eazybytes
    • Password: 12345

์ž๋™ ํ—ค๋” ์ถ”๊ฐ€:

Authorization: Basic ZWF6eWJ5dGVzOjEyMzQ1

์ด๋Š” username:password๋ฅผ Base64 ์ธ์ฝ”๋”ฉํ•œ ๊ฐ’์ž…๋‹ˆ๋‹ค.


#13. ๋ฉด์ ‘ & ์‹ค๋ฌด ํฌ์ธํŠธ ์š”์•ฝ

์งˆ๋ฌธํ•ต์‹ฌ ์š”์•ฝ
Security ๊ธฐ๋ณธ ์ธ์ฆ ํ๋ฆ„?Filter โ†’ AuthManager โ†’ Provider โ†’ UserDetailsService โ†’ PasswordEncoder โ†’ SecurityContext
formLogin vs httpBasicUI ์œ ๋ฌด / ์š”์ฒญ๋ฐฉ์‹ ์ฐจ์ด
permitAll / authenticated / denyAll์ ‘๊ทผ์ œ์–ด ๊ตฌ๋ฌธ ๋น„๊ต
JSESSIONID ์—ญํ• ์„ธ์…˜ ์ธ์ฆ ์‹๋ณ„์šฉ ์ฟ ํ‚ค
์™œ JWT ์‚ฌ์šฉ?์„ธ์…˜์˜ ํ™•์žฅ์„ฑ ๋ฌธ์ œ ํ•ด๊ฒฐ (Stateless ์ธ์ฆ)
profile
Tech Blog

0๊ฐœ์˜ ๋Œ“๊ธ€