[8/1 TIL] SPRING SECURITY(Architecture, FilterChainProxy, RequestCacheAwareFilter, ChannelProcessingFilter, AnonymousAuthenticationFilter, ExceptionTranslationFilter)

yumyeonghanยท2023๋…„ 8์›” 3์ผ
0
post-custom-banner

๐Ÿƒํ”„๋กœ๊ทธ๋ž˜๋จธ์Šค ๋ฐฑ์—”๋“œ ๋ฐ๋ธŒ์ฝ”์Šค 4๊ธฐ ๊ต์œก๊ณผ์ •์„ ๋“ฃ๊ณ  ์ •๋ฆฌํ•œ ๊ธ€์ž…๋‹ˆ๋‹ค.๐Ÿƒ

Architecture

๊ทธ๋ฆผ ์ถœ์ฒ˜

  • AuthenticationManager: ์‚ฌ์šฉ์ž ์ธ์ฆ ๊ด€๋ จ ์ฒ˜๋ฆฌ
  • AccessDecisionManager: ์‚ฌ์šฉ์ž๊ฐ€ ๋ณดํ˜ธ๋ฐ›๋Š” ๋ฆฌ์†Œ์Šค์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ์ ์ ˆํ•œ ๊ถŒํ•œ์ด ์žˆ๋Š”์ง€ ํ™•์ธ

    ์‚ฌ์šฉ์ž๋ฅผ ์ธ์ฆํ•˜๊ณ , ์ธ์ฆ๋œ ์‚ฌ์šฉ์ž๊ฐ€ ๋ฆฌ์†Œ์Šค์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ์ ์ ˆํ•œ ๊ถŒํ•œ์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๊ณ , ๋งŒ์•ฝ ์‚ฌ์šฉ์ž๊ฐ€ ์ ์ ˆํ•œ ์ธ๊ฐ€๊ฐ€ ์—†์œผ๋ฉด AccessDecisionManager์—์„œ 403 Forbidden ์—๋Ÿฌ๋ฅผ ๋‚ธ๋‹ค.

FilterChainProxy

๊ทธ๋ฆผ ์ถœ์ฒ˜

  • Spring Security์˜ ์‹ค์ œ์ ์ธ ๊ตฌํ˜„์€ ์„œ๋ธ”๋ฆฟ ํ•„ํ„ฐ(javax.servlet.Filter)๋ฅผ ํ†ตํ•ด ์ด๋ฃจ์–ด์ง
  • FilterChainProxy ์„ธ๋ถ€ ๋‚ด์šฉ์€ SecurityFilterChain ๋นˆ์„ ํ†ตํ•ด ์„ค์ •
    • ์›น ์š”์ฒญ์€ ์ด๋Ÿฌํ•œ FilterChain์„ ์ฐจ๋ก€๋กœ ํ†ต๊ณผํ•˜๋ฉด์„œ ์ ์ ˆํ•˜๊ฒŒ ๋™์ž‘ํ•จ
    • ๊ฐ ํ•„ํ„ฐ๋Š” ์›น ์š”์ฒญ์— ๋”ฐ๋ผ ๋™์ž‘ ์—ฌ๋ถ€๋ฅผ ๊ฒฐ์ •ํ•  ์ˆ˜ ์žˆ๊ณ , ๋™์ž‘์ด ํ•„์š” ์—†๋‹ค๋ฉด ๋‹ค์Œ ํ•„ํ„ฐ๋กœ ๋„˜๊น€
    • ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๊ณ  ์‘๋‹ต์„ ๋ฐ˜ํ™˜ํ•˜๋ฉด ํ•„ํ„ฐ ์ฒด์ธ ํ˜ธ์ถœ ์Šคํƒ์€ ๋ชจ๋“  ํ•„ํ„ฐ์— ๋Œ€ํ•ด ์—ญ์ˆœ์œผ๋กœ ์ง„ํ–‰

์›น ์š”์ฒญ์€ ์–ด๋–ป๊ฒŒ FilterChainProxy๋กœ ์ „๋‹ฌ๋ ๊นŒ?

DelegatingFilterProxy

  • ์›น ์š”์ฒญ์„ ์ˆ˜์‹ ํ•œ ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ๋Š” ํ•ด๋‹น ์š”์ฒญ์„ DelegatingFilterProxy๋กœ ์ „๋‹ฌํ•จ
    • DelegatingFilterProxy Bean์€ SecurityFilterAutoConfiguration ํด๋ž˜์Šค์—์„œ ์ž๋™์œผ๋กœ ๋“ฑ๋ก๋จ
    • DelegatingFilterProxy๋Š” ์‹ค์ œ์ ์œผ๋กœ ์›น ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•  Target Filter Bean์„ FilterChainProxy๋กœ ์ง€์ •ํ•จ

์ฆ‰, ์›น ์š”์ฒญ์€ FilterChain์˜ ํ•„ํ„ฐ๋“ค์„ ํ†ต๊ณผํ•˜๋‹ค๊ฐ€ DelegatingFilterProxy์— ๋„๋‹ฌํ•˜๋ฉด, FilterChainProxy๋กœ ์ „๋‹ฌ๋˜์–ด ์ฒ˜๋ฆฌ๋˜๋Š” ๊ฒƒ์ด๋‹ค.

FilterChainProxy๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” Filter ๋ชฉ๋ก

RequestCacheAwareFilter

  • ์ธ์ฆ ์š”์ฒญ์— ์˜ํ•ด ๊ฐ€๋กœ์ฑ„์–ด์ง„ ์›๋ž˜ ์š”์ฒญ์œผ๋กœ ์ด๋™ํ•˜๋Š” ํ•„ํ„ฐ

์ƒํ™ฉ

  1. ์ต๋ช… ์‚ฌ์šฉ์ž๊ฐ€ ๋ณดํ˜ธ(์ธ์ฆ, ์ธ๊ฐ€) ๋ฐ›๋Š” ๋ฆฌ์†Œ์Šค์— ์ ‘๊ทผ
  2. ์ ‘๊ทผ ๊ถŒํ•œ์ด ์—†๊ธฐ ๋•Œ๋ฌธ์— FilterSecurityInterceptor์—์„œ ์ ‘๊ทผ ๊ฑฐ๋ถ€ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒ
  3. ExceptionTranslationFilter๊ฐ€ ๋ฐœ์ƒํ•œ ์ ‘๊ทผ ๊ฑฐ๋ถ€ ์˜ˆ์™ธ๋ฅผ ์ฒ˜๋ฆฌ
    • ํ˜„์žฌ ์‚ฌ์šฉ์ž๊ฐ€ ์ต๋ช… ์‚ฌ์šฉ์ž๋ผ๋ฉด, ํ•ด๋‹น ์š”์ฒญ์„ ์บ์‹œ์ฒ˜๋ฆฌํ•˜๊ณ , ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ์ด๋™ ์‹œํ‚ด
  4. ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€์—์„œ ์ •์ƒ ๋กœ๊ทธ์ธ
  5. RequestCacheAwareFilter๊ฐ€ ์บ์‹œ๋œ ์š”์ฒญ์„ ์ฒ˜๋ฆฌ
    • ์บ์‹œ๋œ ์š”์ฒญ์ด ์žˆ๋‹ค๋ฉด ์บ์‹œ๋œ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๊ณ , ์บ์‹œ๋œ ์š”์ฒญ์ด ์—†๋‹ค๋ฉด ํ˜„์žฌ ์š”์ฒญ์„ ์ฒ˜๋ฆฌ
    • ex) ์ด์ „์— ์š”์ฒญํ–ˆ๋˜ ํŽ˜์ด์ง€๋กœ redirect ๋˜๋Š” API ํ˜ธ์ถœ

ChannelProcessingFilter

  • ์ „์†ก ๋ ˆ์ด์–ด ๋ณด์•ˆ์„ ์œ„ํ•ด SSL ์ธ์ฆ์„œ๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ์ด๋ฅผ Spring Boot ์›น ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์ ์šฉํ•˜๋Š” ํ•„ํ„ฐ

HTTPS

  • ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„๊ฐ€ ์ฃผ๊ณ  ๋ฐ›๋Š” ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ์•”ํ˜ธํ™”
  • ๋ฐ์ดํ„ฐ ์•”ํ˜ธํ™”๋ฅผ ์œ„ํ•ด SSL์„ ์‚ฌ์šฉ
  • SSL ์•”ํ˜ธํ™”๋ฅผ ์œ„ํ•ด SSL ์ธ์ฆ์„œ๊ฐ€ ํ•„์š”ํ•จ

HTTPS ๋™์ž‘

  1. ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์„œ๋ฒ„์— ์ ‘์† ์‹œ, ์„œ๋ฒ„๋Š” ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ๋Š” ์ธ์ฆ๊ธฐ๊ด€์œผ๋กœ๋ถ€ํ„ฐ ๋ฐœ๊ธ‰๋œ SSL/TLS ์ธ์ฆ์„œ๋ฅผ ์ œ๊ณตํ•˜๊ณ , ์ด ์ธ์ฆ์„œ์—๋Š” ์„œ๋ฒ„์˜ ๊ณต๊ฐœํ‚ค์™€ ์„œ๋ฒ„ ์ •๋ณด๊ฐ€ ํฌํ•จ๋จ
  2. ํด๋ผ์ด์–ธํŠธ๋Š” ์„œ๋ฒ„๊ฐ€ ์ œ๊ณตํ•œ ์ธ์ฆ์„œ๋ฅผ ํ™•์ธํ•˜๊ณ , ์ธ์ฆ์„œ์— ํฌํ•จ๋œ ๊ณต๊ฐœํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์„œ๋ฒ„๋ฅผ ๊ฒ€์ฆํ•˜๋ฉฐ, ์ด๋Ÿฌํ•œ ๊ณผ์ •์„ SSL/TLS ํ•ธ๋“œ์…ฐ์ดํฌ๋ผ๊ณ ํ•จ
  3. ํด๋ผ์ด์–ธํŠธ๋Š” ์„œ๋ฒ„์˜ ๊ณต๊ฐœํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋žœ๋คํ•œ ๋Œ€์นญ ์•”ํ˜ธํ™” ํ‚ค(์„ธ์…˜ ํ‚ค)๋ฅผ ์•”ํ˜ธํ™”ํ•˜์—ฌ ์„œ๋ฒ„๋กœ ์ „์†ก
  4. ์„œ๋ฒ„๋Š” ์ž์‹ ์˜ ๊ฐœ์ธํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํด๋ผ์ด์–ธํŠธ๋กœ๋ถ€ํ„ฐ ์ „์†ก๋œ ์•”ํ˜ธํ™”๋œ ๋Œ€์นญ ์•”ํ˜ธํ™” ํ‚ค(์„ธ์…˜ ํ‚ค)๋ฅผ ๋ณตํ˜ธํ™”
  5. ์ด๋ ‡๊ฒŒ ์„œ๋ฒ„์™€ ํด๋ผ์ด์–ธํŠธ๋Š” ์„œ๋กœ ์•ฝ์†ํ•œ ๋Œ€์นญ ์•”ํ˜ธํ™” ํ‚ค(์„ธ์…˜ ํ‚ค)๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ†ต์‹ ์„ ์•”ํ˜ธํ™”ํ•จ

SSL ์ธ์ฆ์„œ ์ƒ์„ฑ

  • SSL ์ธ์ฆ์„œ๋ฅผ ๋ฐœ๊ธ‰๋ฐ›๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋„๋ฉ”์ธ๊ณผ ๋ฐœ๊ธ‰ ๋น„์šฉ์ด ๋“ค๊ธฐ๋•Œ๋ฌธ์— ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ(๊ฐœ๋ฐœ ํ™˜๊ฒฝ)์—์„œ๋Š” java์˜ keytool ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ž„์˜๋กœ ์ƒ์„ฑ
    • ์‹ค์ œ ์„œ๋น„์Šค์—๋Š” ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Œ

3๊ฐ€์ง€ ์ž‘์—…์ด ํ•„์š”

  1. keystore ๋งŒ๋“ค๊ธฐ: keytool -genkey -alias prgrms_keystore -keyalg RSA -storetype PKCS12 -keystore prgrms_keystore.p12
  2. keystore์—์„œ ์ธ์ฆ์„œ ์ถ”์ถœํ•˜๊ธฐ: keytool -export -alias prgrms_keystore -keystore prgrms_keystore.p12 -rfc -file prgrms.cer
  3. trust-store ๋งŒ๋“ค๊ธฐ: keytool -import -alias prgrms_truststore -file prgrms.cer -keystore prgrms_truststore.p12

SSL ์ธ์ฆ์„œ ์ ์šฉ

server:
  port: 443
  ssl:
    enabled: true
    key-alias: prgrms_keystore
    key-store: classpath:prgrms_keystore.p12
    key-store-password: ์„ค์ •ํ•œ ๋น„๋ฐ€๋ฒˆํ˜ธ
    key-password: ์„ค์ •ํ•œ ๋น„๋ฐ€๋ฒˆํ˜ธ
    trust-store: classpath:prgrms_truststore.p12
    trust-store-password: ์„ค์ •ํ•œ ๋น„๋ฐ€๋ฒˆํ˜ธ
  • ์œ„์—์„œ ์ง์ ‘ ๋งŒ๋“  prgrms_keystore.p12, prgrms_truststore.p12, 2๊ฐœ ํŒŒ์ผ์„ resources ๋””๋ ‰ํ† ๋ฆฌ๋กœ ๋ณต์‚ฌ ํ›„ application.yml ์„ค์ •

Spring Security ์„ค์ •

	@Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        return http
                //์ƒ๋žต 
                .requiresChannel(auth -> auth
                		.anyRequest().requiresSecure()) //๋ชจ๋“  ์š”์ฒญ์ด HTTPS๋กœ ์š”์ฒญ ๋ผ์•ผํ•จ 
               	.build();
    }
  • ๊ธฐ์กด SecurityFilterChain ๋นˆ์— ChannelProcessingFilter ์„ค์ •
  • http.requiresChannel()๋Š” URL์ด ์š”์ฒญ๋œ ํ”„๋กœํ† ์ฝœ(HTTP ๋˜๋Š” HTTPS)๊ณผ ์ผ์น˜ํ•˜๋Š”์ง€ ๊ฒ€์‚ฌ

AnonymousAuthenticationFilter

  • ์ต๋ช… ์‚ฌ์šฉ์ž๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ์ธ์ฆ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ํ•„ํ„ฐ
  • ํ•ด๋‹น ํ•„ํ„ฐ์— ์š”์ฒญ์ด ๋„๋‹ฌํ• ๋•Œ๊นŒ์ง€ ์‚ฌ์šฉ์ž๊ฐ€ ์ธ์ฆ๋˜์ง€ ์•Š์•˜๋‹ค๋ฉด, ์‚ฌ์šฉ์ž๋ฅผ null ๋Œ€์‹  Anonymous ์ธ์ฆ ํƒ€์ž…์œผ๋กœ ํ‘œํ˜„
  • ์‚ฌ์šฉ์ž๊ฐ€ null์ธ์ง€ ํ™•์ธํ•˜๋Š”๊ฒƒ๋ณด๋‹ค ๊ตฌ์ฒด์ ์ธ ํƒ€์ž…์œผ๋กœ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋„๋กํ•จ
    • ์ธ์ฆ๋˜์ง€ ์•Š์€ ์‚ฌ์šฉ์ž๋ฉด, "principal"๊ณผ "authorities"๋กœ ์ธ์ฆ๋˜์ง€ ์•Š์€ ์‚ฌ์šฉ์ž๋ฅผ ๋Œ€ํ‘œํ•˜๋Š” ์ธ์ฆ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑ

Spring Security ์„ค์ •

	@Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        return http
                //์ƒ๋žต 
                .anonymous(auth -> auth
                		.principal("thisIsAnonymousUser") //์ต๋ช… ์‚ฌ์šฉ์ž์˜ ์‹๋ณ„์ž๋ฅผ ์„ค์ •
                        .authorities("ROLE_ANONYMOUS", "ROLE_UNKNOWN")) //์ต๋ช… ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ถ€์—ฌ๋˜๋Š” ๊ถŒํ•œ ์„ค์ •(์ ‘๋‘์‚ฌ "ROLE_" ๋ฅผ ์‚ฌ์šฉ)
               	.build();
    }

ExceptionTranslationFilter

  • SecurityFilterChain์—์„œ FilterSecurityInterceptor ๋ฐ”๋กœ ์œ„์— ์œ„์น˜ํ•˜๋ฉฐ, ์ธ์ฆ ๊ณผ์ •(FilterSecurityInterceptor ์‹คํ–‰)์—์„œ ๋ฐœ์ƒํ•˜๋Š” ์˜ˆ์™ธ๋ฅผ ์ฒ˜๋ฆฌ
    • AuthenticationException(์ธ์ฆ ๊ด€๋ จ ์˜ˆ์™ธ)์ด๋ฉฐ, ์ด ์˜ˆ์™ธ๋ฅผ ์žก์•„ ์‚ฌ์šฉ์ž๋ฅผ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ๋ณด๋ƒ„
    • AccessDeniedException(์ ‘๊ทผ ๊ฑฐ๋ถ€ ์˜ˆ์™ธ)์ด๋ฉฐ, ์ด ์˜ˆ์™ธ๋ฅผ ์žก์•„ ์ ‘๊ทผ ๊ฑฐ๋ถ€ ํŽ˜์ด์ง€๋ฅผ ๋ณด์—ฌ์ฃผ๊ฑฐ๋‚˜ ์‚ฌ์šฉ์ž๋ฅผ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ๋ณด๋ƒ„
  • ExceptionTranslationFilter๋Š” SecurityFilterChain์—์„œ ์ž๊ธฐ ์•„๋ž˜์— ์˜ค๋Š” ํ•„ํ„ฐ๋“ค์—์„œ ๋ฐœ์ƒํ•˜๋Š” ์˜ˆ์™ธ๋“ค์— ๋Œ€ํ•ด์„œ๋งŒ ์ฒ˜๋ฆฌ
  • ๋”ฐ๋ผ์„œ ์ปค์Šคํ…€ ํ•„ํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ ์ด๋ฅผ ๊ณ ๋ คํ•ด์•ผํ•จ

AccessDeniedException ํ•ธ๋“ค๋Ÿฌ ์„ค์ •

	@Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        return http
                //์ƒ๋žต 
               	.exceptionHandling(auth -> auth
                		.accessDeniedHandler(accessDeniedHandler())) //AccessDeniedHandler๋ฅผ ์„ค์ •
               	.build();
    }


	//Custom AccessDeniedHandler
	@Bean
    public AccessDeniedHandler accessDeniedHandler() {
        return (request, response, accessDeniedException) -> {
            Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
            Object principal = authentication != null ? authentication.getPrincipal() : null;
            log.warn("{} is denied", principal);
            response.setStatus(HttpServletResponse.SC_FORBIDDEN);
            response.setContentType("text/plain");
            response.getWriter().write("## ACCESS DENIED ##");
            response.getWriter().flush();
            response.getWriter().close();
        };
    }
  • ๊ธฐ๋ณธ์ ์œผ๋กœ AccessDeniedException ์˜ˆ์™ธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ๊ตฌํ˜„๋˜์–ด ์žˆ์Œ
    • org.springframework.security.web.access.AccessDeniedHandlerImpl ํด๋ž˜์Šค
  • ํ•˜์ง€๋งŒ ์œ„์˜ ์ฝ”๋“œ์™€ ๊ฐ™์ด ์‚ฌ์šฉ์ž ์ •์˜ AccessDeniedHandler ์„ค์ • ๊ฐ€๋Šฅํ•จ
  • ๊ธฐ์กด SecurityFilterChain ๋นˆ์— ExceptionTranslationFilter ์„ค์ •
  • http.exceptionHandling()๋Š” ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๋ฅผ ์„ค์ •
profile
์›น ๊ฐœ๋ฐœ์— ๊ด€์‹ฌ ์žˆ์Šต๋‹ˆ๋‹ค.
post-custom-banner

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