[Spring][Security][๊ฐœ๋…]๐Ÿ”ฅ Spring Security ์™„๋ฒฝ ํ•ด๋ถ€: ํ•„ํ„ฐ ์ฒด์ธ๊ณผ ๋ณด์•ˆ ํ๋ฆ„ ํ•œ๋ˆˆ์— ํŒŒ์•…ํ•˜๊ธฐ! ๐Ÿ”

๊น€์ƒ์šฑยท2024๋…„ 11์›” 7์ผ
post-thumbnail

๐Ÿ”’ Spring Security ์š”์ฒญ ์ฒ˜๋ฆฌ ํ๋ฆ„ ์™„๋ฒฝ ์ดํ•ดํ•˜๊ธฐ ๐Ÿš€

์„œ๋ธ”๋ฆฟ ๊ธฐ๋ฐ˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ Spring Security๊ฐ€ ์š”์ฒญ์„ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ•˜๋Š”์ง€ ์ดํ•ดํ•˜๋ ค๋ฉด ํ•„ํ„ฐ(Filter)์˜ ๊ตฌ์กฐ์™€ ์—ญํ• ์„ ํŒŒ์•…ํ•˜๋Š” ๊ฒƒ์ด ํ•„์ˆ˜์ ์ž…๋‹ˆ๋‹ค. Spring Security๋Š” ํ•„ํ„ฐ ์ฒด์ธ์„ ํ†ตํ•ด ์ž‘๋™ํ•˜๋ฉฐ, ์š”์ฒญ์ด ์—ฌ๋Ÿฌ ํ•„ํ„ฐ๋ฅผ ์ฐจ๋ก€๋กœ ๊ฑฐ์ณ ๋ณด์•ˆ์„ ์ ์šฉํ•˜๋Š” ๊ตฌ์กฐ๋ฅผ ์ด๋ฃน๋‹ˆ๋‹ค.


๐Ÿ“ฌ ์š”์ฒญ ์ฒ˜๋ฆฌ ํ๋ฆ„ ํ•œ๋ˆˆ์— ๋ณด๊ธฐ ๐Ÿ“ฌ

1๏ธโƒฃ ํด๋ผ์ด์–ธํŠธ ์š”์ฒญ

  • ํด๋ผ์ด์–ธํŠธ๊ฐ€ HTTP ์š”์ฒญ์„ ์„œ๋ฒ„๋กœ ์ „์†กํ•ฉ๋‹ˆ๋‹ค.

2๏ธโƒฃ FilterChain ์ƒ์„ฑ

  • ์ปจํ…Œ์ด๋„ˆ๋Š” ์š”์ฒญ ๊ฒฝ๋กœ์— ๋งž๋Š” ํ•„ํ„ฐ๋“ค๊ณผ ์„œ๋ธ”๋ฆฟ์„ ๋ชจ์•„ FilterChain์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
  • FilterChain์€ ์š”์ฒญ์„ ๊ด€๋ฆฌํ•˜๋ฉฐ, ์ ์ ˆํ•œ ํ•„ํ„ฐ์™€ ์„œ๋ธ”๋ฆฟ์„ ์ฐจ๋ก€๋กœ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

3๏ธโƒฃ DispatcherServlet ํ˜ธ์ถœ

  • Spring MVC์—์„œ๋Š” FilterChain ๋งˆ์ง€๋ง‰ ์„œ๋ธ”๋ฆฟ์ด DispatcherServlet์ž…๋‹ˆ๋‹ค.
  • DispatcherServlet์€ ๋ชจ๋“  HTTP ์š”์ฒญ์„ ์ค‘์•™์—์„œ ์ฒ˜๋ฆฌํ•˜๋ฉฐ, ์š”์ฒญ์„ ํ•ด๋‹น ์ปจํŠธ๋กค๋Ÿฌ๋กœ ๋ผ์šฐํŒ…ํ•ฉ๋‹ˆ๋‹ค.

๐ŸŽฏ ํ•„ํ„ฐ์˜ ์ฃผ์š” ์—ญํ•  ๐ŸŽฏ

ํ•„ํ„ฐ๋Š” FilterChain์„ ํ†ตํ•ด ์š”์ฒญ๊ณผ ์‘๋‹ต์„ ์กฐ์ž‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

  • ํ•˜์œ„ ํ•„ํ„ฐ ๋ฐ ์„œ๋ธ”๋ฆฟ ํ˜ธ์ถœ ๋ฐฉ์ง€:
    • ์˜ˆ๋ฅผ ๋“ค์–ด ์ธ์ฆ ์‹คํŒจ ์‹œ ํ•„ํ„ฐ๊ฐ€ ์ง์ ‘ HttpServletResponse์— ์‘๋‹ต์„ ์ž‘์„ฑํ•˜์—ฌ ์š”์ฒญ ์ฒ˜๋ฆฌ๋ฅผ ์ข…๋ฃŒํ•ฉ๋‹ˆ๋‹ค.
  • HttpServletRequest์™€ HttpServletResponse ์ˆ˜์ •:
    • ํ•˜์œ„ ํ•„ํ„ฐ๋‚˜ ์„œ๋ธ”๋ฆฟ์— ์ „๋‹ฌ๋  ์š”์ฒญ, ์‘๋‹ต ๊ฐ์ฒด์˜ ํ—ค๋”๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐ์ž‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿงฉ FilterChain์˜ ํ•ต์‹ฌ ์—ญํ•  ๐Ÿงฉ

FilterChain์€ ๊ฐ ํ•„ํ„ฐ๊ฐ€ ์š”์ฒญ์„ ์ˆœ์ฐจ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ์—ฐ๊ฒฐํ•˜๋Š” ๊ตฌ์กฐ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๊ฐ ํ•„ํ„ฐ๋Š” doFilter ๋ฉ”์„œ๋“œ๋กœ ๋‹ค์Œ ํ•„ํ„ฐ์— ์š”์ฒญ์„ ๋„˜๊ธฐ๊ฑฐ๋‚˜, ํ•„์š” ์‹œ ์ง์ ‘ ์‘๋‹ต์„ ์ž‘์„ฑํ•ด ์ข…๋ฃŒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ๊ฐ•๋ ฅํ•œ ๋ฉ”์ปค๋‹ˆ์ฆ˜ ๋•๋ถ„์— Spring Security์—์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ณด์•ˆ ํ•„ํ„ฐ๋ฅผ ์„ค์ •ํ•˜์—ฌ ์š”์ฒญ ๋ณดํ˜ธ๋ฅผ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค:

  • ์ธ์ฆ ํ•„ํ„ฐ: ์š”์ฒญ์ด ์ ์ ˆํ•œ ์ธ์ฆ์„ ๊ฑฐ์ณค๋Š”์ง€ ํ™•์ธ
  • ๊ถŒํ•œ ํ•„ํ„ฐ: ์ž์› ์ ‘๊ทผ ๊ถŒํ•œ์ด ์žˆ๋Š”์ง€ ํ™•์ธ
  • CSRF ๋ณดํ˜ธ ํ•„ํ„ฐ: CSRF ๊ณต๊ฒฉ ๋ฐฉ์ง€

ํ•„ํ„ฐ ์ฒด์ธ์€ ๋ณด์•ˆ ๊ธฐ๋Šฅ์„ ์š”์ฒญ๊ณผ ์‘๋‹ต ํ๋ฆ„์— ๋™์ ์œผ๋กœ ์ถ”๊ฐ€ํ•˜๋ฉฐ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ•๋ ฅํ•œ ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค. ๊ฐ ํ•„ํ„ฐ๊ฐ€ ์ˆœ์„œ์— ๋”ฐ๋ผ ์ž‘๋™ํ•ด ๋ณด์•ˆ์„ ์ ์ง„์ ์œผ๋กœ ๊ฐ•ํ™”ํ•ฉ๋‹ˆ๋‹ค. ๐Ÿ’ชโœจ


FilterChain ์‚ฌ์šฉ ์˜ˆ์‹œ

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
	// do something before the rest of the application
    chain.doFilter(request, response); // invoke the rest of the application
    // do something after the rest of the application
}

์ด๋ ‡๊ฒŒ ๊ตฌ์„ฑ๋œ ํ•„ํ„ฐ ์ฒด์ธ ๋•๋ถ„์—, Spring Security์—์„œ๋Š” ๋ณด๋‹ค ์œ ์—ฐํ•˜๊ณ  ๊ฐ•๋ ฅํ•œ ๋ณด์•ˆ ์ฒ˜๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ๐Ÿ˜Ž๐Ÿ”ฅ


๐Ÿšจ CSRF ๊ณต๊ฒฉ ๋ฐฉ์ง€์˜ ํ•„์ˆ˜ ์š”์†Œ! ๐Ÿ’ฅ

CSRF(Cross-Site Request Forgery)๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์˜๋„์น˜ ์•Š๊ฒŒ ๊ณต๊ฒฉ์ž์— ์˜ํ•ด ์กฐ์ž‘๋œ ์š”์ฒญ์„ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์œผ๋กœ ๋ณด๋‚ด๋„๋ก ์œ ๋„ํ•˜๋Š” ์น˜๋ช…์ ์ธ ๊ณต๊ฒฉ ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. ์ด ๊ณต๊ฒฉ์€ ์‚ฌ์šฉ์ž๊ฐ€ ์ด๋ฏธ ๋กœ๊ทธ์ธ๋œ ์„ธ์…˜์„ ์•…์šฉํ•ด ์ด๋ฃจ์–ด์ง€๋ฉฐ, ๋ฏผ๊ฐํ•œ ์ž‘์—…์ด ๋ฌด๋‹จ์œผ๋กœ ์‹คํ–‰๋  ์ˆ˜ ์žˆ์–ด ๋งค์šฐ ์‹ฌ๊ฐํ•œ ๋ณด์•ˆ ์œ„ํ˜‘์ด ๋ฉ๋‹ˆ๋‹ค.


๐Ÿ” CSRF ๊ณต๊ฒฉ ํ๋ฆ„ ๊ฐ„๋‹จ ์ •๋ฆฌ ๐Ÿ”

1๏ธโƒฃ ์‚ฌ์šฉ์ž ๋กœ๊ทธ์ธ

  • ์‚ฌ์šฉ์ž๊ฐ€ ์‚ฌ์ดํŠธ A์— ๋กœ๊ทธ์ธํ•˜์—ฌ ์„ธ์…˜์ด ์œ ์ง€๋ฉ๋‹ˆ๋‹ค.

2๏ธโƒฃ ์•…์˜์ ์ธ ์‚ฌ์ดํŠธ ๋ฐฉ๋ฌธ

  • ์‚ฌ์šฉ์ž๊ฐ€ ์˜๋„์น˜ ์•Š๊ฒŒ ๊ณต๊ฒฉ์ž์˜ ํŽ˜์ด์ง€๋กœ ์ ‘์†ํ•ด, ์ˆจ๊ฒจ์ง„ CSRF ๊ณต๊ฒฉ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

3๏ธโƒฃ ์‚ฌ์ดํŠธ A๋กœ ์š”์ฒญ ์ „์†ก

  • ๋ธŒ๋ผ์šฐ์ €๋Š” ์„ธ์…˜ ์ฟ ํ‚ค๋ฅผ ํฌํ•จํ•˜์—ฌ ์‚ฌ์ดํŠธ A๋กœ ์š”์ฒญ์„ ๋ณด๋‚ด, ์‚ฌ์ดํŠธ๋Š” ์ด๋ฅผ ์ •์ƒ์ ์ธ ์š”์ฒญ์œผ๋กœ ์ธ์‹ํ•ฉ๋‹ˆ๋‹ค.

4๏ธโƒฃ ์˜๋„์น˜ ์•Š์€ ์ž‘์—… ์‹คํ–‰

  • ์‚ฌ์ดํŠธ A๋Š” ์‚ฌ์šฉ์ž ๊ถŒํ•œ์œผ๋กœ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•ด, ๊ณต๊ฒฉ์ž๊ฐ€ ์›ํ•˜๋Š” ์ž‘์—…์ด ์ˆ˜ํ–‰๋ฉ๋‹ˆ๋‹ค (์˜ˆ: ๊ณ„์ขŒ ์ด์ฒด).

๐Ÿ›ก๏ธ CSRF ๋ฐฉ์ง€ ๋ฐฉ๋ฒ• ๐Ÿ›ก๏ธ

  1. CSRF ํ† ํฐ ์‚ฌ์šฉ ๐Ÿ”‘

    • ์„œ๋ฒ„๋Š” ์š”์ฒญ๋งˆ๋‹ค ๊ณ ์œ ํ•œ CSRF ํ† ํฐ์„ ์ƒ์„ฑํ•˜์—ฌ, ์š”์ฒญ ์‹œ ํ† ํฐ์„ ํ•จ๊ป˜ ์ „์†กํ•ฉ๋‹ˆ๋‹ค. ์„œ๋ฒ„๋Š” ์ด ํ† ํฐ์˜ ์œ ํšจ์„ฑ์„ ๊ฒ€์ฆํ•ด CSRF ๊ณต๊ฒฉ์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค.
  2. SameSite ์ฟ ํ‚ค ์„ค์ • ๐Ÿช

    • SameSite ์†์„ฑ์„ ์„ค์ •ํ•ด ์ฟ ํ‚ค๊ฐ€ ๋™์ผ ์‚ฌ์ดํŠธ ๋‚ด์—์„œ๋งŒ ์ „์†ก๋˜๋„๋ก ์ œํ•œํ•ฉ๋‹ˆ๋‹ค.
      • Strict: ๋™์ผ ์‚ฌ์ดํŠธ ๋‚ด ์š”์ฒญ๋งŒ ์ฟ ํ‚ค ์ „์†ก
      • Lax: ์•ˆ์ „ํ•œ ๋ฐฉ์‹์˜ ์š”์ฒญ(GET)๋งŒ ์ฟ ํ‚ค ์ „์†ก
  3. ์‚ฌ์šฉ์ž ์ž…๋ ฅ ๊ฒ€์ฆ ๐Ÿ“

    • HTTP ํ—ค๋” ๋ฐ ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ์—์„œ ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ๊ฐ’์ด ๋“ค์–ด์˜ค์ง€ ์•Š๋„๋ก ๊ฒ€์ฆํ•ด CSRF ๊ณต๊ฒฉ์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค.
  4. Referer ๋ฐ Origin ํ—ค๋” ํ™•์ธ ๐ŸŒ

    • ์š”์ฒญ ์ถœ์ฒ˜๋ฅผ ํ™•์ธํ•˜์—ฌ ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ๋Š” ๋„๋ฉ”์ธ์—์„œ ์˜จ ์š”์ฒญ๋งŒ ์ฒ˜๋ฆฌํ•˜๋„๋ก ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ” CSRF ๋ฐฉ์ง€๊ฐ€ ์ค‘์š”ํ•œ ์ด์œ  ๐Ÿ”

CSRF ๊ณต๊ฒฉ์€ ์‚ฌ์šฉ์ž๊ฐ€ ์‹ ๋ขฐํ•˜๋Š” ์ƒํƒœ(๋กœ๊ทธ์ธ ์„ธ์…˜)๋ฅผ ์•…์šฉํ•ด ๋ฏผ๊ฐํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋„๋ก ์œ ๋„ํ•ฉ๋‹ˆ๋‹ค. ํŠนํžˆ ๊ธˆ์œต ์‚ฌ์ดํŠธ๋‚˜ ์ค‘์š”ํ•œ ์ •๋ณด๊ฐ€ ์˜ค๊ฐ€๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ๋Š” ์ด๋Ÿฌํ•œ ๋ณด์•ˆ ์œ„ํ˜‘์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด CSRF ํ† ํฐ์„ ํ†ตํ•œ ๋ฐฉ์–ด๊ฐ€ ํ•„์ˆ˜์ ์ž…๋‹ˆ๋‹ค. CSRF ๋ฐฉ์–ด๋Š” ์•…์˜์ ์ธ ์‚ฌ์ดํŠธ๊ฐ€ ์˜ฌ๋ฐ”๋ฅธ ํ† ํฐ์„ ํฌํ•จํ•  ์ˆ˜ ์—†๋„๋ก ํ•˜์—ฌ, ์‚ฌ์šฉ์ž์™€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ชจ๋‘์˜ ์•ˆ์ „์„ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค! ๐Ÿ›ก๏ธโœจ


๐ŸŒ‰ Spring DelegatingFilterProxy: ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์™€ Spring Bean์„ ์—ฐ๊ฒฐํ•˜๋Š” ๋‹ค๋ฆฌ ๐Ÿš€

Spring์˜ DelegatingFilterProxy๋Š” ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์˜ ํ•„ํ„ฐ์™€ Spring ApplicationContext์˜ Bean์„ ์—ฐ๊ฒฐํ•ด์ฃผ๋Š” ์ค‘์š”ํ•œ ๋ฉ”์ปค๋‹ˆ์ฆ˜์œผ๋กœ, ํ•„ํ„ฐ ํ˜•ํƒœ๋กœ ์ธ์ฆ, ๊ถŒํ•œ ๋ถ€์—ฌ, ํŠธ๋žœ์žญ์…˜ ๊ด€๋ฆฌ ๋“ฑ์„ ์†์‰ฝ๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค. Spring์—์„œ ๊ด€๋ฆฌํ•˜๋Š” Bean์„ ํ•„ํ„ฐ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๋•๋Š” DelegatingFilterProxy์˜ ์ž‘๋™ ์›๋ฆฌ์™€ ์„ค์ • ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.


๐Ÿ”— DelegatingFilterProxy๊ฐ€ ํ•„์š”ํ•œ ์ด์œ  ๐Ÿ”—

์ผ๋ฐ˜์ ์œผ๋กœ ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ๋Š” ์ž์ฒด ํ‘œ์ค€์— ๋”ฐ๋ผ ํ•„ํ„ฐ ์ธ์Šคํ„ด์Šค๋ฅผ ๊ด€๋ฆฌํ•˜์—ฌ Spring์ด ๊ด€๋ฆฌํ•˜๋Š” Bean์„ ์ธ์‹ํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค. DelegatingFilterProxy๋Š” ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜์—ฌ, ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ๊ฐ€ Spring Bean์„ ํ•„ํ„ฐ๋กœ ์ธ์‹ํ•˜๊ณ  ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค.


โš™๏ธ DelegatingFilterProxy ์ž‘๋™ ์›๋ฆฌ โš™๏ธ

1๏ธโƒฃ ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์— ๋“ฑ๋ก

  • web.xml์ด๋‚˜ Spring Boot ์ž๋™ ์„ค์ •์„ ํ†ตํ•ด ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์— DelegatingFilterProxy๋ฅผ ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค.

2๏ธโƒฃ Spring Bean์œผ๋กœ ์œ„์ž„

  • DelegatingFilterProxy์˜ doFilter ๋ฉ”์„œ๋“œ๋Š” ์š”์ฒญ์„ Spring ApplicationContext์˜ ํŠน์ • Bean์— ์ „๋‹ฌํ•ด ์‹ค์ œ ํ•„ํ„ฐ ์ž‘์—…์„ ์œ„์ž„ํ•ฉ๋‹ˆ๋‹ค.

3๏ธโƒฃ FilterChain ๋‚ด ์œ„์น˜

  • DelegatingFilterProxy๋Š” FilterChain์˜ ์ผ๋ถ€๋กœ ๋“ฑ๋ก๋˜์–ด ์„ค์ •๋œ ์ˆœ์„œ์— ๋”ฐ๋ผ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค. Spring Bean์€ ํ•„ํ„ฐ๋กœ์„œ์˜ ์—ญํ• ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“˜ DelegatingFilterProxy ์„ค์ • ์˜ˆ์‹œ ๐Ÿ“˜

1. web.xml์—์„œ DelegatingFilterProxy ๋“ฑ๋กํ•˜๊ธฐ (Spring MVC ์‚ฌ์šฉ ์‹œ)

<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

์œ„ ์„ค์ •์œผ๋กœ springSecurityFilterChain์ด๋ผ๋Š” ์ด๋ฆ„์˜ DelegatingFilterProxy๊ฐ€ ๋“ฑ๋ก๋˜์–ด ๋ชจ๋“  ๊ฒฝ๋กœ(/)์— ๋Œ€ํ•ด ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. Spring Security์™€ ๊ฐ™์€ ์ธ์ฆ ๋ฐ ๊ถŒํ•œ ๊ด€๋ฆฌ์— ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. ๐Ÿ”

2. Spring Boot์—์„œ DelegatingFilterProxy ์„ค์ •

Spring Boot์—์„œ๋Š” @Component๋กœ ํ•„ํ„ฐ Bean์„ ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

@Component("customFilter")
public class CustomFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
            throws IOException, ServletException {
        // ํ•„ํ„ฐ ๋™์ž‘ ๊ตฌํ˜„
        chain.doFilter(request, response);
    }
}

์ด ์„ค์ •์œผ๋กœ customFilter๋ผ๋Š” ์ด๋ฆ„์˜ ํ•„ํ„ฐ๊ฐ€ Spring ApplicationContext์— ์˜ํ•ด ๊ด€๋ฆฌ๋˜๋ฉฐ, DelegatingFilterProxy๊ฐ€ ์ด๋ฅผ ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.


๐Ÿ’ก DelegatingFilterProxy์˜ ์žฅ์  ๐Ÿ’ก

  • Spring์˜ ์˜์กด์„ฑ ์ฃผ์ž… ์‚ฌ์šฉ ๊ฐ€๋Šฅ: Spring Security์™€ ๊ฐ™์€ ๋ณต์žกํ•œ ํ•„ํ„ฐ ์„ค์ •์„ ์‰ฝ๊ฒŒ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ํŠธ๋žœ์žญ์…˜ ๊ด€๋ฆฌ ๊ฐ€๋Šฅ: ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ์ƒํ˜ธ์ž‘์šฉํ•˜๋Š” ํ•„ํ„ฐ์—์„œ ์ผ๊ด€๋œ ํŠธ๋žœ์žญ์…˜ ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
  • ์œ ์—ฐํ•œ ์„ค์ •: Java Config๋‚˜ XML ๋“ฑ ๋‹ค์–‘ํ•œ ๋ฐฉ์‹์œผ๋กœ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์–ด ์œ ์—ฐํ•ฉ๋‹ˆ๋‹ค.

DelegatingFilterProxy๋Š” ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์™€ Spring์„ ์—ฐ๊ฒฐํ•ด ์ฃผ๋ฉฐ, Spring Security์™€ ํŠธ๋žœ์žญ์…˜ ๊ด€๋ฆฌ ๋“ฑ ๋‹ค์–‘ํ•œ Spring ๊ธฐ๋Šฅ์„ ํ•„ํ„ฐ๋กœ ์‰ฝ๊ฒŒ ํ†ตํ•ฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ•๋ ฅํ•œ ๋„๊ตฌ์ž…๋‹ˆ๋‹ค. ๐Ÿ›ก๏ธโœจ


๐ŸŒ‰ DelegatingFilterProxy: ๋“ฑ๋ก๊ณผ ์‹ค์ œ ์‚ฌ์šฉ์˜ ํ•ต์‹ฌ ํฌ์ธํŠธ ๐Ÿ’ก

DelegatingFilterProxy๋Š” ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์™€ Spring์˜ ๋นˆ ๊ด€๋ฆฌ ์‹œ์Šคํ…œ์„ ์—ฐ๊ฒฐํ•ด์ฃผ๋Š” ์—ญํ• ๋กœ, ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ๊ฐ€ Spring ๋นˆ์œผ๋กœ ๋“ฑ๋ก๋œ ํ•„ํ„ฐ๋ฅผ ์ธ์‹ํ•˜๊ฒŒ ํ•ด์ฃผ๋Š” '๋‹ค๋ฆฌ' ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด ์—ญํ• ์ด ์‹ค์ œ ํ•„ํ„ฐ ์‹คํ–‰๊ณผ๋Š” ์ฐจ์ด๊ฐ€ ์žˆ๋‹ค๋Š” ์ ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.


๐Ÿ“ ๋“ฑ๋ก๊ณผ ์‹ค์ œ ์‚ฌ์šฉ์˜ ์ฐจ์ด์  ๐Ÿ“

  • ๋“ฑ๋ก๋งŒ ํ•œ๋‹ค: DelegatingFilterProxy๋Š” Spring ๋นˆ์„ ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์˜ ํ•„ํ„ฐ๋กœ ๋“ฑ๋กํ•ด์ฃผ๋Š” ์—ญํ• ๋งŒ ํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, ๋“ฑ๋ก ์ž์ฒด๋กœ๋Š” ํ•„ํ„ฐ๊ฐ€ ์‹คํ–‰๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • ์‹ค์ œ ์‚ฌ์šฉ: FilterChain์—์„œ ์š”์ฒญ์ด ๋“ค์–ด์˜ค๊ณ , Chain ์ˆœ์„œ์— ๋”ฐ๋ผ DelegatingFilterProxy๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ์—์•ผ ๋น„๋กœ์†Œ ํ•„ํ„ฐ ๋นˆ์ด ์ž‘๋™์„ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ํ•„ํ„ฐ๋Š” ์š”์ฒญ์ด FilterChain์„ ํ†ตํ•ด ์‹คํ–‰๋  ๋•Œ ์‹ค์ œ๋กœ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ”„ DelegatingFilterProxy ์ž‘๋™ ๊ณผ์ • ์š”์•ฝ ๐Ÿ”„

1๏ธโƒฃ ํ•„ํ„ฐ ๋นˆ ์ •์˜

  • Spring ApplicationContext์— ํ•„ํ„ฐ๋ฅผ ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค.

2๏ธโƒฃ DelegatingFilterProxy ๋“ฑ๋ก

  • ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์— DelegatingFilterProxy๋ฅผ ํ•„ํ„ฐ๋กœ ๋“ฑ๋กํ•˜์—ฌ Spring ํ•„ํ„ฐ ๋นˆ์„ ์‚ฌ์šฉํ•  ์ค€๋น„๋ฅผ ๋งˆ์นฉ๋‹ˆ๋‹ค.

3๏ธโƒฃ FilterChain์—์„œ ํ˜ธ์ถœ

  • ํด๋ผ์ด์–ธํŠธ ์š”์ฒญ์ด ๋“ค์–ด์˜ค๋ฉด FilterChain์— ๋“ฑ๋ก๋œ ์ˆœ์„œ์— ๋”ฐ๋ผ DelegatingFilterProxy๊ฐ€ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.

4๏ธโƒฃ DelegatingFilterProxy๊ฐ€ ํ•„ํ„ฐ ๋นˆ์— ์œ„์ž„

  • DelegatingFilterProxy๋Š” ์„ค์ •๋œ ํ•„ํ„ฐ ๋นˆ์œผ๋กœ ์š”์ฒญ์„ ์œ„์ž„ํ•˜๊ณ , ์‹ค์ œ ํ•„ํ„ฐ ๋กœ์ง์ด ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ DelegatingFilterProxy๋Š” Spring๊ณผ ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ ๊ฐ„์˜ ์—ฐ๊ฒฐ์„ ๋„์™€์ฃผ๋Š” ์—ญํ• ์ผ ๋ฟ, ์š”์ฒญ์ด ๋“ค์–ด์˜ค๊ณ  FilterChain์ด ์‹คํ–‰๋  ๋•Œ์—์•ผ ์‹ค์ œ ํ•„ํ„ฐ๊ฐ€ ์ž‘๋™ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ด ์ฐจ์ด์ ์„ ์ดํ•ดํ•˜๋Š” ๊ฒƒ์ด Spring Security์™€ ๊ฐ™์€ ๋ณด์•ˆ ํ•„ํ„ฐ ์„ค์ •์—์„œ ๋งค์šฐ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค! ๐Ÿ›ก๏ธ๐Ÿ’ฅ


DelegatingFilterProxy์˜ ์˜์‚ฌ ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด Spring Bean์œผ๋กœ ๋“ฑ๋ก๋œ ํ•„ํ„ฐ๊ฐ€ ์–ด๋–ป๊ฒŒ ์ง€์—ฐ ์ดˆ๊ธฐํ™”(lazy initialization) ๋ฐฉ์‹์œผ๋กœ ๋ถˆ๋Ÿฌ์™€์ง€๋Š”์ง€ ์ž˜ ์„ค๋ช…ํ•ด์ฃผ์…จ์Šต๋‹ˆ๋‹ค. ์ด ์ฝ”๋“œ๋Š” DelegatingFilterProxy๊ฐ€ ์š”์ฒญ์„ ๋ฐ›์„ ๋•Œ๋งˆ๋‹ค ApplicationContext์—์„œ ํ•ด๋‹น ์ด๋ฆ„์œผ๋กœ ๋“ฑ๋ก๋œ Bean์„ ์ฐพ์•„ ๊ทธ ์ธ์Šคํ„ด์Šค๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋ฐฉ์‹์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.


๐Ÿ” DelegatingFilterProxy ์˜์‚ฌ ์ฝ”๋“œ ์„ค๋ช… ๐Ÿ”

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
    Filter delegate = getFilterBean(someBeanName); 
    delegate.doFilter(request, response, chain); 
}
  • getFilterBean(someBeanName): someBeanName์ด๋ผ๋Š” ์ด๋ฆ„์œผ๋กœ ApplicationContext์—์„œ ๋“ฑ๋ก๋œ ํ•„ํ„ฐ ๋นˆ์„ ์ฐพ์•„, ์ง€์—ฐ ์ดˆ๊ธฐํ™” ๋ฐฉ์‹์œผ๋กœ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
    • ์ด ๋ฐฉ์‹์œผ๋กœ ๋ถˆ๋Ÿฌ์˜จ ํ•„ํ„ฐ ๋นˆ์€ ApplicationContext์—์„œ ๊ด€๋ฆฌํ•˜๋Š” ํ•„ํ„ฐ ์ธ์Šคํ„ด์Šค์ด๋ฏ€๋กœ, Spring์˜ ์˜์กด์„ฑ ์ฃผ์ž…, ํŠธ๋žœ์žญ์…˜ ๊ด€๋ฆฌ ๋“ฑ ๋‹ค์–‘ํ•œ ๊ธฐ๋Šฅ์„ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • delegate.doFilter(request, response, chain): ๊ฐ€์ ธ์˜จ ํ•„ํ„ฐ ๋นˆ ์ธ์Šคํ„ด์Šค๊ฐ€ doFilter ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ์‹ค์ œ ํ•„ํ„ฐ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ delegate๋Š” Bean Filter0์˜ ์ธ์Šคํ„ด์Šค์ด๋ฉฐ, DelegatingFilterProxy๋Š” ์š”์ฒญ์„ ์ด ํ•„ํ„ฐ ๋นˆ์œผ๋กœ ์ „๋‹ฌํ•ด ์ž‘์—…์„ ์œ„์ž„ํ•ฉ๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ๋ฐฉ์‹์œผ๋กœ DelegatingFilterProxy๋Š” ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์˜ ์š”์ฒญ์„ ApplicationContext์˜ ํ•„ํ„ฐ ๋นˆ์œผ๋กœ ์—ฐ๊ฒฐํ•˜์—ฌ, Spring์—์„œ ๊ด€๋ฆฌํ•˜๋Š” ํ•„ํ„ฐ๊ฐ€ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค.


๐Ÿš€ DelegatingFilterProxy์˜ ๋™์ž‘๊ณผ ์ง€์—ฐ ์ดˆ๊ธฐํ™”(lazy initialization) ์™„๋ฒฝ ์ดํ•ดํ•˜๊ธฐ! ๐ŸŒ

DelegatingFilterProxy๋Š” ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์—์„œ ํ•„ํ„ฐ๋กœ ์ž‘๋™ํ•˜๋ฉด์„œ Spring ApplicationContext์˜ ํ•„ํ„ฐ ๋นˆ์„ ํ˜ธ์ถœํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฉ”์ปค๋‹ˆ์ฆ˜์˜ ํ•ต์‹ฌ์€ ์ง€์—ฐ ์ดˆ๊ธฐํ™”(lazy initialization) ๋ฅผ ํ†ตํ•ด ์„ฑ๋Šฅ ์ตœ์ ํ™”์™€ ์ข…์†์„ฑ ๋ฌธ์ œ ํ•ด๊ฒฐ์„ ๋•๋Š”๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.


๐Ÿงฉ DelegatingFilterProxy ๋™์ž‘ ๊ณผ์ • ๐Ÿงฉ

1๏ธโƒฃ ํ•„ํ„ฐ ํ˜ธ์ถœ

  • DelegatingFilterProxy๋Š” ์š”์ฒญ์ด ๋“ค์–ด์˜ฌ ๋•Œ doFilter ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ, Spring ํ•„ํ„ฐ ๋นˆ์„ ์ฐพ๊ณ  ์‹คํ–‰ํ•˜๋Š” ๊ณผ์ •์„ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.

2๏ธโƒฃ ํ•„ํ„ฐ ๋นˆ ์ฐพ๊ธฐ (getFilterBean ํ˜ธ์ถœ)

  • getFilterBean ๋ฉ”์„œ๋“œ๋Š” ApplicationContext์—์„œ ์ง€์ •๋œ ์ด๋ฆ„(someBeanName)์˜ ํ•„ํ„ฐ Bean์„ ์ฐพ์•„ delegate์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

3๏ธโƒฃ ์‹ค์ œ ํ•„ํ„ฐ๋กœ ์š”์ฒญ ์ „๋‹ฌ

  • delegate.doFilter(request, response)๋ฅผ ํ˜ธ์ถœํ•ด ์‹ค์ œ ์š”์ฒญ ์ฒ˜๋ฆฌ๋Š” delegate ํ•„ํ„ฐ ๋นˆ์ด ์ˆ˜ํ–‰ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. DelegatingFilterProxy๋Š” ์ค‘๊ณ„ ์—ญํ• ๋งŒ ํ•˜๋ฉฐ, ์‹ค์ œ ์ž‘์—…์€ Spring ํ•„ํ„ฐ Bean์ด ๋‹ด๋‹นํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ•ฐ๏ธ ์ง€์—ฐ ์ดˆ๊ธฐํ™”(lazy initialization)๋ž€? ๐Ÿ•ฐ๏ธ

์ง€์—ฐ ์ดˆ๊ธฐํ™”๋Š” ๊ฐ์ฒด๋‚˜ ๋ฆฌ์†Œ์Šค๋ฅผ ์ฒ˜์Œ ์‚ฌ์šฉํ•  ๋•Œ์—์•ผ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. ์ฆ‰, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹œ์ž‘ ์‹œ ๋ชจ๋“  ๊ฐ์ฒด๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜์ง€ ์•Š๊ณ , ํ•„์š”ํ•  ๋•Œ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

  • DelegatingFilterProxy์—์„œ์˜ ์ง€์—ฐ ์ดˆ๊ธฐํ™”
    • doFilter ๋ฉ”์„œ๋“œ๊ฐ€ ์ฒ˜์Œ ํ˜ธ์ถœ๋  ๋•Œ getFilterBean์„ ํ†ตํ•ด ApplicationContext์—์„œ ํ•„ํ„ฐ Bean์„ ์ฐพ์•„ delegate์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. ์ดํ›„๋กœ๋Š” delegate์— ์ €์žฅ๋œ ํ•„ํ„ฐ Bean์„ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ, ๋ฐ˜๋ณต ๊ฒ€์ƒ‰ ์—†์ด ํšจ์œจ์ ์œผ๋กœ ํ•„ํ„ฐ๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

โšก ์ง€์—ฐ ์ดˆ๊ธฐํ™”์˜ ์žฅ์  โšก

  1. ์„ฑ๋Šฅ ์ตœ์ ํ™”

    • ๋ชจ๋“  ํ•„ํ„ฐ๋ฅผ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹œ์ž‘ ์‹œ ์ƒ์„ฑํ•˜๋Š” ๋Œ€์‹ , ํ•„์š”ํ•  ๋•Œ๋งŒ ์ƒ์„ฑํ•˜์—ฌ ๋ฉ”๋ชจ๋ฆฌ์™€ ์ดˆ๊ธฐํ™” ์‹œ๊ฐ„์„ ์ ˆ์•ฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  2. ์ข…์†์„ฑ ๋ฌธ์ œ ํ•ด๊ฒฐ

    • ํŠน์ • ํ•„ํ„ฐ๋‚˜ Bean์ด ๋‹ค๋ฅธ ์„œ๋น„์Šค๊ฐ€ ์ค€๋น„๋œ ํ›„์—์•ผ ์ž‘๋™ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ, ์ง€์—ฐ ์ดˆ๊ธฐํ™”๋กœ ํ•„์š”ํ•œ ์‹œ์ ์—๋งŒ ์ดˆ๊ธฐํ™”ํ•˜์—ฌ ์ข…์†์„ฑ ๋ฌธ์ œ๋ฅผ ํ”ผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ“ ์š”์•ฝ ๐Ÿ“

DelegatingFilterProxy๋Š” ํ•„์š”ํ•  ๋•Œ ํ•„ํ„ฐ ๋นˆ์„ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ง€์—ฐ ์ดˆ๊ธฐํ™” ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜์—ฌ ์„ฑ๋Šฅ์„ ์ตœ์ ํ™”ํ•˜๊ณ  ๋ถˆํ•„์š”ํ•œ ์ž์› ๋‚ญ๋น„๋ฅผ ์ค„์ด๋ฉฐ, ์ข…์†์„ฑ ๋ฌธ์ œ๋ฅผ ์˜ˆ๋ฐฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด Spring์˜ ํ•„ํ„ฐ ๋นˆ์ด ์š”์ฒญ ์ฒ˜๋ฆฌ ์ค‘์—๋งŒ ํ™œ์„ฑํ™”๋˜์–ด ํšจ์œจ์ ์ด๊ณ  ์œ ์—ฐํ•œ ๋ณด์•ˆ ์„ค์ •์ด ๊ฐ€๋Šฅํ•ด์ง‘๋‹ˆ๋‹ค! ๐Ÿ’ช๐ŸŒˆ


DelegatingFilterProxy๊ฐ€ ์ง€์—ฐ ์ดˆ๊ธฐํ™”๋ฅผ ํ†ตํ•ด Spring ApplicationContext์— ๋ฏธ๋ฆฌ ๋“ฑ๋ก๋œ ํ•„ํ„ฐ Bean์„ ์‹ค์ œ ์š”์ฒญ ์‹œ์ ์—์„œ๋งŒ ๊ฐ€์ ธ์™€ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹์ด ํ•ต์‹ฌ์ž…๋‹ˆ๋‹ค. ์ด ์ ‘๊ทผ ๋ฐฉ์‹์ด ์„ฑ๋Šฅ ์ตœ์ ํ™”์™€ ์œ ์—ฐ์„ฑ์„ ๋ชจ๋‘ ํ™•๋ณดํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค.


๐Ÿงต DelegatingFilterProxy์˜ ๋™์ž‘ ๋ฐฉ์‹ ๋‹ค์‹œ ์ •๋ฆฌ ๐Ÿงต

  • ๋ฏธ๋ฆฌ ๋“ฑ๋ก๋œ Bean: Spring ApplicationContext๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹œ์ž‘ ์‹œ์ ์— ํ•„ํ„ฐ Bean์„ ๋ฏธ๋ฆฌ ์ƒ์„ฑํ•˜๊ณ  ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ํ•„ํ„ฐ Bean ์ž์ฒด๋Š” ์ด๋ฏธ ApplicationContext์—์„œ ๊ด€๋ฆฌ๋˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์ง€์—ฐ ์ดˆ๊ธฐํ™”์˜ ์˜๋ฏธ:

    • DelegatingFilterProxy๋Š” doFilter ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜๊ธฐ ์ „๊นŒ์ง€๋Š” ํ•ด๋‹น ํ•„ํ„ฐ Bean์„ ๊ฐ€์ ธ์˜ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
    • ์š”์ฒญ์ด ๋“ค์–ด์™€ doFilter๊ฐ€ ํ˜ธ์ถœ๋˜๋Š” ์‹œ์ ์—์„œ์•ผ ApplicationContext๋กœ๋ถ€ํ„ฐ ํ•„ํ„ฐ Bean์„ ๊ฐ€์ ธ์™€ ํ•„ํ„ฐ ์ž‘์—…์„ ์‹คํ–‰ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์ด ๊ณผ์ •์„ ํ†ตํ•ด ํ•„ํ„ฐ ์ธ์Šคํ„ด์Šค์˜ ํ˜ธ์ถœ ์‹œ์ ์„ ๋Šฆ์ถค์œผ๋กœ์จ ๋ถˆํ•„์š”ํ•œ ์ดˆ๊ธฐํ™”๋ฅผ ๋ฐฉ์ง€ํ•˜๊ณ , ์‹ค์ œ ์š”์ฒญ์ด ๋“ค์–ด์˜ฌ ๋•Œ์—๋งŒ ํ•„ํ„ฐ๊ฐ€ ์ž‘๋™ํ•˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.


โœ๏ธ ์š”์•ฝ ์ •๋ฆฌ โœ๏ธ

  1. ํ•„ํ„ฐ Bean์€ ApplicationContext์— ๋ฏธ๋ฆฌ ๋“ฑ๋ก๋ฉ๋‹ˆ๋‹ค.
  2. DelegatingFilterProxy๋Š” ์š”์ฒญ์ด ๋“ค์–ด์™€ doFilter๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ๊นŒ์ง€ ํ•ด๋‹น Bean์„ ํ˜ธ์ถœํ•˜์ง€ ์•Š์Œ์œผ๋กœ์จ, ํ•„์š”ํ•œ ์‹œ์ ๊นŒ์ง€ ์ดˆ๊ธฐํ™”๋ฅผ ๋ฏธ๋ฃน๋‹ˆ๋‹ค.
  3. ์ด ๋ฐฉ์‹์„ ํ†ตํ•ด ํ•„ํ„ฐ์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ˆœ๊ฐ„๊นŒ์ง€ ํ˜ธ์ถœ์„ ๋ฏธ๋ฃจ๋Š” ๋ฐฉ์‹์œผ๋กœ ๋™์ž‘ํ•˜๋ฉฐ, ์ด๊ฒƒ์ด ์ง€์—ฐ ์ดˆ๊ธฐํ™”(lazy initialization)์ž…๋‹ˆ๋‹ค.

์ด์™€ ๊ฐ™์€ ์„ค๊ณ„ ๋•๋ถ„์— DelegatingFilterProxy๋Š” ์„ฑ๋Šฅ๊ณผ ์ž์› ํšจ์œจ์„ฑ์„ ๋†’์ด๋Š” ๋™์‹œ์— Spring์˜ ์œ ์—ฐํ•œ ์˜์กด์„ฑ ์ฃผ์ž… ๋ฐ ๊ด€๋ฆฌ ๊ธฐ๋Šฅ์„ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค! ๐Ÿ› ๏ธ๐Ÿ’ก


๐Ÿงฉ DelegatingFilterProxy ๋™์ž‘ ๊ณผ์ •: ์ดˆ๊ธฐํ™” ์‹œ์  ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ํ•ต์‹ฌ ๋ฉ”์ปค๋‹ˆ์ฆ˜ ๐Ÿš€

DelegatingFilterProxy๋Š” ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์™€ Spring ApplicationContext์˜ ์ดˆ๊ธฐํ™” ์‹œ์  ์ฐจ์ด๋ฅผ ๊ทน๋ณตํ•˜๊ธฐ ์œ„ํ•œ ์žฅ์น˜๋กœ, ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์ง€์—ฐ ์กฐํšŒ(lazy lookup) ๋ฐฉ์‹์œผ๋กœ ํ•„ํ„ฐ Bean์„ ๋‹ค๋ฃน๋‹ˆ๋‹ค. ๋‹จ๊ณ„๋ณ„๋กœ ๊ทธ ๋™์ž‘ ์›๋ฆฌ์™€ ์œ ์šฉ์„ฑ์— ๋Œ€ํ•ด ์ •๋ฆฌํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.


๐Ÿ•ฐ๏ธ ๋ฌธ์ œ์˜ ๋ฐฐ๊ฒฝ: ์ปจํ…Œ์ด๋„ˆ์™€ Spring ApplicationContext์˜ ์ดˆ๊ธฐํ™” ์‹œ์  ์ฐจ์ด ๐Ÿ•ฐ๏ธ

1๏ธโƒฃ ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์˜ ํ•„ํ„ฐ ๋“ฑ๋ก ๊ณผ์ •

  • ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์‹œ์ž‘๋  ๋•Œ ํ•„์š”ํ•œ ํ•„ํ„ฐ๋“ค์„ ๋ฏธ๋ฆฌ ์ƒ์„ฑํ•˜๊ณ  ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ณผ์ •์€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹คํ–‰ ์ „์— ์ด๋ฃจ์–ด์ง€๋ฉฐ, ์ปจํ…Œ์ด๋„ˆ๋Š” ํ•„ํ„ฐ๋ฅผ ๋จผ์ € ์ค€๋น„ํ•œ ํ›„ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹คํ–‰์„ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.

2๏ธโƒฃ Spring์˜ Bean ์ดˆ๊ธฐํ™”

  • ๋ฐ˜๋ฉด Spring์€ ContextLoaderListener์™€ ๊ฐ™์€ ๋ฆฌ์Šค๋„ˆ๋ฅผ ํ†ตํ•ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ปจํ…์ŠคํŠธ(ApplicationContext)๋ฅผ ๋‚˜์ค‘์— ๋กœ๋“œํ•˜์—ฌ Bean๋“ค์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
  • ์ด ์‹œ์ ์€ ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์˜ ํ•„ํ„ฐ ์ดˆ๊ธฐํ™”๊ฐ€ ์™„๋ฃŒ๋œ ํ›„์ด๋ฏ€๋กœ, ํ•„ํ„ฐ ๋“ฑ๋ก ํ›„์—์•ผ Spring Bean๋“ค์ด ๋กœ๋“œ๋ฉ๋‹ˆ๋‹ค.

3๏ธโƒฃ ํƒ€์ด๋ฐ ๋ฌธ์ œ

  • ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ๋Š” ํ•„ํ„ฐ๋ฅผ ๋จผ์ € ์ดˆ๊ธฐํ™”ํ•ด์•ผ ํ•˜๋Š” ๋ฐ˜๋ฉด, Spring Bean๋“ค์€ ๊ทธ๋ณด๋‹ค ๋Šฆ๊ฒŒ ์ดˆ๊ธฐํ™”๋˜๋ฏ€๋กœ Spring์˜ Bean์„ ํ•„ํ„ฐ๋กœ ์ง์ ‘ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋Š” ์ƒํ™ฉ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ› ๏ธ DelegatingFilterProxy์˜ ํ•ด๊ฒฐ์ฑ…: ์ง€์—ฐ ์กฐํšŒ(lazy lookup) ๋ฐฉ์‹์œผ๋กœ ํ•„ํ„ฐ Bean ์‚ฌ์šฉ ๐Ÿ› ๏ธ

DelegatingFilterProxy๋Š” ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์™€ Spring ์‚ฌ์ด์˜ ํƒ€์ด๋ฐ ์ฐจ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ํ•„ํ„ฐ Bean์„ ์ง€์—ฐ ์กฐํšŒํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค. ์•„๋ž˜์™€ ๊ฐ™์ด ๊ฐ ๋‹จ๊ณ„๋ณ„๋กœ ์ง„ํ–‰๋ฉ๋‹ˆ๋‹ค:

1๏ธโƒฃ DelegatingFilterProxy ๋“ฑ๋ก

  • ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์— DelegatingFilterProxy๋ฅผ ํ•„ํ„ฐ๋กœ ๋“ฑ๋กํ•˜์ง€๋งŒ, ์ด ๋‹จ๊ณ„์—์„œ๋Š” Spring ํ•„ํ„ฐ Bean์„ ์ดˆ๊ธฐํ™”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • DelegatingFilterProxy๋Š” ๋‹จ์ง€ ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์— ๋“ฑ๋ก๋  ๋ฟ, ํ•„ํ„ฐ ์—ญํ• ์„ ์ˆ˜ํ–‰ํ•  Spring Bean์€ ์‹ค์ œ๋กœ ํ˜ธ์ถœ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

2๏ธโƒฃ ์š”์ฒญ ์‹œ์ ์—์„œ ํ•„ํ„ฐ Bean ์กฐํšŒ

  • DelegatingFilterProxy์˜ doFilter ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ, ApplicationContext์—์„œ ํ•„ํ„ฐ ์—ญํ• ์„ ํ•˜๋Š” Spring Bean์„ ์ฐพ์•„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
  • ์ด ์‹œ์ ์— DelegatingFilterProxy๋Š” ํ•„ํ„ฐ Bean์˜ doFilter ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ, ์‹ค์ œ ํ•„ํ„ฐ ๋กœ์ง์„ ์ˆ˜ํ–‰ํ•˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

๐ŸŽฏ ์š”์•ฝ ์ •๋ฆฌ ๐ŸŽฏ

  • ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ๋Š” DelegatingFilterProxy๋ฅผ ๋จผ์ € ๋“ฑ๋กํ•œ ํ›„ ํ•„ํ„ฐ ์—ญํ• ์„ ์ˆ˜ํ–‰ํ•  ์ค€๋น„๋ฅผ ๋งˆ์นฉ๋‹ˆ๋‹ค.
  • Spring ํ•„ํ„ฐ Bean์€ ์‹ค์ œ ์š”์ฒญ์ด ๋“ค์–ด์˜ฌ ๋•Œ๋งŒ ์ง€์—ฐ ์กฐํšŒ ๋ฐฉ์‹์œผ๋กœ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.
  • ์ด ๋ฐฉ์‹์„ ํ†ตํ•ด DelegatingFilterProxy๋Š” ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์™€ Spring์˜ ์ดˆ๊ธฐํ™” ์‹œ์  ์ฐจ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ณ , Spring Bean์„ ํ•„ํ„ฐ๋กœ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ์—ฐ๊ฒฐํ•ด ์ค๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ์ง€์—ฐ ์กฐํšŒ ๋ฐฉ์‹ ๋•๋ถ„์—, Spring Bean ์ดˆ๊ธฐํ™”๊ฐ€ ๋Šฆ์–ด์ ธ๋„ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์œผ๋ฉฐ, ํ•„์š”ํ•œ ์‹œ์ ์—๋งŒ ํ•„ํ„ฐ Bean์„ ํ˜ธ์ถœํ•˜์—ฌ ์„ฑ๋Šฅ์„ ์ตœ์ ํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๐ŸŒ๐Ÿ’ก


๐Ÿงฉ ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์™€ ContextLoaderListener์˜ ์—ญํ•  ๋ฐ ์ดˆ๊ธฐํ™” ์ˆœ์„œ: DelegatingFilterProxy๋ฅผ ์ดํ•ดํ•˜๋Š” ํ•ต์‹ฌ ๐Ÿš€

DelegatingFilterProxy์˜ ๋™์ž‘์„ ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์™€ ContextLoaderListener์˜ ์ดˆ๊ธฐํ™” ๊ณผ์ •์„ ํŒŒ์•…ํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ๊ฐ๊ฐ์˜ ์—ญํ• ๊ณผ ์ดˆ๊ธฐํ™” ์ˆœ์„œ๋ฅผ ํ†ตํ•ด Spring์ด ๊ด€๋ฆฌํ•˜๋Š” ํ•„ํ„ฐ๊ฐ€ ์–ด๋–ป๊ฒŒ ์ปจํ…Œ์ด๋„ˆ์—์„œ ์ž‘๋™ํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ๋‹จ๊ณ„๋ณ„๋กœ ์ •๋ฆฌํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.


1๏ธโƒฃ ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ๋ž€? ๐ŸŒ

์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ๋Š” Tomcat ๊ฐ™์€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„œ๋ฒ„๊ฐ€ ์„œ๋ธ”๋ฆฟ์„ ์‹คํ–‰ํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๋Š” ํ™˜๊ฒฝ์ž…๋‹ˆ๋‹ค. ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์‹œ์ž‘๋  ๋•Œ ํ•„ํ„ฐ์™€ ์„œ๋ธ”๋ฆฟ์„ ๋ฏธ๋ฆฌ ๋“ฑ๋ก ๋ฐ ์ดˆ๊ธฐํ™”ํ•˜์—ฌ, ์ดํ›„ ๋“ค์–ด์˜ค๋Š” ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•  ์ค€๋น„๋ฅผ ๊ฐ–์ถฅ๋‹ˆ๋‹ค.

๐Ÿ› ๏ธ ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์˜ ์ดˆ๊ธฐํ™” ๊ณผ์ •

  • ํ•„ํ„ฐ ๋“ฑ๋ก: web.xml ๋˜๋Š” Spring Boot ์„ค์ •์„ ํ†ตํ•ด ํ•„ํ„ฐ๋ฅผ ๋ฏธ๋ฆฌ ๋“ฑ๋กํ•˜๊ณ  ์ค€๋น„ํ•ฉ๋‹ˆ๋‹ค.
  • ์„œ๋ธ”๋ฆฟ ๋“ฑ๋ก: ํ•„ํ„ฐ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์„œ๋ธ”๋ฆฟ๋„ ๋ฏธ๋ฆฌ ์ดˆ๊ธฐํ™”ํ•˜์—ฌ ํŠน์ • ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•  ์ค€๋น„๋ฅผ ์™„๋ฃŒํ•ฉ๋‹ˆ๋‹ค.

์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ๋Š” ํ•„ํ„ฐ์™€ ์„œ๋ธ”๋ฆฟ์„ ๋ชจ๋‘ ์ค€๋น„ํ•˜๊ณ  ๋‚˜์„œ์•ผ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์‹œ์ž‘๋˜๋ฉฐ, ์ดํ›„ ๋“ค์–ด์˜ค๋Š” HTTP ์š”์ฒญ์„ ํ•„ํ„ฐ์™€ ์„œ๋ธ”๋ฆฟ์„ ํ†ตํ•ด ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.


2๏ธโƒฃ ContextLoaderListener๋ž€? โš™๏ธ

ContextLoaderListener๋Š” Spring ApplicationContext๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๋Š” ๋ฆฌ์Šค๋„ˆ์ž…๋‹ˆ๋‹ค. ApplicationContext๋Š” Spring์˜ ๋ชจ๋“  ์ฃผ์š” Bean์„ ๊ด€๋ฆฌํ•˜๋ฉฐ, DelegatingFilterProxy๊ฐ€ ์‚ฌ์šฉํ•  ํ•„ํ„ฐ Bean๋„ ์—ฌ๊ธฐ ๋“ฑ๋ก๋ฉ๋‹ˆ๋‹ค.

๐Ÿ”„ ContextLoaderListener์˜ ์ดˆ๊ธฐํ™” ๊ณผ์ •

  • ApplicationContext ๋กœ๋“œ: ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ContextLoaderListener๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด, Spring์€ ApplicationContext๋ฅผ ๋กœ๋“œํ•˜์—ฌ ํ•„์š”ํ•œ Bean์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
  • ํ•„ํ„ฐ Bean ์ƒ์„ฑ: ApplicationContext์— ๋“ฑ๋ก๋œ ๋ชจ๋“  Spring Bean์ด ์ดˆ๊ธฐํ™”๋˜๋ฉฐ, ํ•„ํ„ฐ Bean ์—ญ์‹œ ์ด ๋‹จ๊ณ„์—์„œ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.

์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ ์ดˆ๊ธฐํ™”๊ฐ€ ๋๋‚œ ๋’ค์— ContextLoaderListener๊ฐ€ ํ˜ธ์ถœ๋˜๋ฏ€๋กœ, ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์ง์ ‘ Spring ํ•„ํ„ฐ Bean์„ ํ•„ํ„ฐ๋กœ ์ธ์‹ํ•˜๊ณ  ๋“ฑ๋กํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.


3๏ธโƒฃ ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์™€ ContextLoaderListener์˜ ์ดˆ๊ธฐํ™” ์ˆœ์„œ ๊ด€๊ณ„ ๐Ÿ“…

  1. ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ ์ดˆ๊ธฐํ™”

    • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์‹œ์ž‘๋˜๋ฉด, ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ๋จผ์ € ํ•„ํ„ฐ์™€ ์„œ๋ธ”๋ฆฟ์„ ๋“ฑ๋ก ๋ฐ ์ค€๋น„ํ•ฉ๋‹ˆ๋‹ค. ์ด ๋‹จ๊ณ„์—์„œ๋Š” Spring ApplicationContext์™€ ๋ฌด๊ด€ํ•˜๊ฒŒ ํ•„ํ„ฐ ๋ฐ ์„œ๋ธ”๋ฆฟ์˜ ๊ธฐ๋ณธ ์„ค์ •๋งŒ ์ด๋ค„์ง‘๋‹ˆ๋‹ค.
  2. ContextLoaderListener ์ดˆ๊ธฐํ™”

    • ์ปจํ…Œ์ด๋„ˆ์˜ ํ•„ํ„ฐ์™€ ์„œ๋ธ”๋ฆฟ์ด ๋ชจ๋‘ ์ค€๋น„๋œ ํ›„ ContextLoaderListener๊ฐ€ ํ˜ธ์ถœ๋˜์–ด, Spring ApplicationContext๊ฐ€ ์ดˆ๊ธฐํ™”๋ฉ๋‹ˆ๋‹ค.
    • ์ด๋•Œ, ApplicationContext์— ๋“ฑ๋ก๋œ ๋ชจ๋“  Spring Bean์ด ์ƒ์„ฑ๋˜๊ณ  ๊ด€๋ฆฌ๋˜๊ธฐ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ”‘ DelegatingFilterProxy์˜ ์—ญํ• ๊ณผ ์ค‘์š”์„ฑ ๐Ÿ”‘

DelegatingFilterProxy๋Š” ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์™€ Spring ApplicationContext ๊ฐ„ ์ดˆ๊ธฐํ™” ์‹œ์  ์ฐจ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋งŒ๋“ค์–ด์กŒ์Šต๋‹ˆ๋‹ค. DelegatingFilterProxy ๋•๋ถ„์—, Spring ApplicationContext์— ์žˆ๋Š” ํ•„ํ„ฐ Bean์ด ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์— ํ•„ํ„ฐ๋กœ ๋“ฑ๋ก๋œ ๊ฒƒ์ฒ˜๋Ÿผ ์ž‘๋™ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ๋Š” DelegatingFilterProxy๋งŒ ํ•„ํ„ฐ๋กœ ๋“ฑ๋กํ•˜๋ฉฐ, DelegatingFilterProxy๋Š” ๋‹จ์ง€ "์ค‘๊ณ„์ž" ์—ญํ• ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  • ์š”์ฒญ์ด ๋“ค์–ด์˜ฌ ๋•Œ DelegatingFilterProxy๊ฐ€ Spring์˜ ํ•„ํ„ฐ Bean์„ ์ง€์—ฐ ์กฐํšŒํ•˜์—ฌ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ์ด๋กœ์จ Spring ํ•„ํ„ฐ Bean์ด ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

โœ๏ธ ์š”์•ฝ โœ๏ธ

  • ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์™€ ContextLoaderListener์˜ ์ดˆ๊ธฐํ™” ์ˆœ์„œ ์ฐจ์ด๋กœ ์ธํ•ด Spring ํ•„ํ„ฐ Bean์„ ์ง์ ‘ ์ปจํ…Œ์ด๋„ˆ์— ํ•„ํ„ฐ๋กœ ๋“ฑ๋กํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
  • DelegatingFilterProxy๋Š” ์ด ๊ฐ„๊ทน์„ ๋ฉ”์šฐ๋Š” ์ค‘๊ณ„ ์—ญํ• ์„ ์ˆ˜ํ–‰ํ•˜์—ฌ, Spring ํ•„ํ„ฐ Bean์ด ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์—์„œ ํ•„ํ„ฐ๋กœ์„œ ๋™์ž‘ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค.
  • DelegatingFilterProxy๋Š” ์š”์ฒญ ์‹œ์ ์— ApplicationContext์—์„œ ํ•„ํ„ฐ Bean์„ ์กฐํšŒํ•˜์—ฌ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•จ์œผ๋กœ์จ Spring๊ณผ ์ปจํ…Œ์ด๋„ˆ ๊ฐ„์˜ ์ดˆ๊ธฐํ™” ์‹œ์  ์ฐจ์ด๋ฅผ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค.

DelegatingFilterProxy๋Š” ์ด์ฒ˜๋Ÿผ ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์™€ Spring ApplicationContext ๊ฐ„์˜ ์—ฐ๊ฒฐ์„ ๋‹ด๋‹นํ•˜์—ฌ Spring์˜ ๋ณด์•ˆ, ํŠธ๋žœ์žญ์…˜ ๊ด€๋ฆฌ ๋“ฑ ํ•„ํ„ฐ ๊ธฐ๋Šฅ์„ ์œ ์—ฐํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ์ง€์›ํ•˜๋Š” ์ค‘์š”ํ•œ ๊ตฌ์„ฑ ์š”์†Œ์ž…๋‹ˆ๋‹ค. ๐Ÿ›ก๏ธโœจ


๐Ÿš€ ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์™€ Spring ApplicationContext์˜ ํ•„ํ„ฐ ๋ฐ Bean ๋“ฑ๋ก ์ฐจ์ด: DelegatingFilterProxy์˜ ํ•„์š”์„ฑ ์ดํ•ดํ•˜๊ธฐ ๐ŸŒ‰

์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ๊ด€๋ฆฌํ•˜๋Š” ํ•„ํ„ฐ์™€ ์„œ๋ธ”๋ฆฟ์˜ ๋“ฑ๋ก๊ณผ Spring์ด ๊ด€๋ฆฌํ•˜๋Š” Bean ๋“ฑ๋ก์€ ์„œ๋กœ ๋‹ค๋ฅธ ์‹œ์Šคํ…œ์—์„œ ์ด๋ฃจ์–ด์ง€๋Š” ๊ฐœ๋…์ž…๋‹ˆ๋‹ค. ๊ฐ๊ฐ์˜ ์ดˆ๊ธฐํ™”์™€ ๋“ฑ๋ก ๊ณผ์ •์˜ ์ฐจ์ด๋ฅผ ์ดํ•ดํ•˜๋ฉด, DelegatingFilterProxy๊ฐ€ ํ•„์š”ํ•œ ์ด์œ ๊ฐ€ ๋ช…ํ™•ํ•ด์ง‘๋‹ˆ๋‹ค.


๐Ÿ” ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์˜ ํ•„ํ„ฐ ๋ฐ ์„œ๋ธ”๋ฆฟ ๋“ฑ๋ก

  • ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ๋Š” Tomcat, Jetty ๋“ฑ๊ณผ ๊ฐ™์€ ์›น ์„œ๋ฒ„๊ฐ€ ๊ด€๋ฆฌํ•˜๋ฉฐ, web.xml ํŒŒ์ผ ๋˜๋Š” Spring Boot์˜ ์ž๋™ ์„ค์ •์„ ํ†ตํ•ด ํ•„ํ„ฐ์™€ ์„œ๋ธ”๋ฆฟ์„ ๋ฏธ๋ฆฌ ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค.
  • ์ด๋•Œ ๋“ฑ๋ก๋œ ํ•„ํ„ฐ์™€ ์„œ๋ธ”๋ฆฟ์€ Spring๊ณผ ๋…๋ฆฝ์ ์œผ๋กœ ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ ์ž์ฒด์—์„œ ๊ด€๋ฆฌ๋˜๋ฉฐ, ๋“ค์–ด์˜ค๋Š” ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•  ์ค€๋น„๊ฐ€ ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ๋Š” ์ด ํ•„ํ„ฐ์™€ ์„œ๋ธ”๋ฆฟ์„ ๊ด€๋ฆฌํ•˜๋ฉฐ, ์š”์ฒญ์ด ๋“ค์–ด์˜ค๋ฉด ์ด๋“ค์„ ํ˜ธ์ถœํ•˜์—ฌ ์ฒ˜๋ฆฌ๋ฅผ ์ง„ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

โš™๏ธ Spring ApplicationContext์˜ Bean ๋“ฑ๋ก

  • Spring์—์„œ๋Š” ContextLoaderListener๊ฐ€ ์ดˆ๊ธฐํ™”๋œ ์ดํ›„, Spring ApplicationContext๊ฐ€ ๊ด€๋ฆฌํ•˜๋Š” Bean๋“ค์ด ๋“ฑ๋ก๋ฉ๋‹ˆ๋‹ค.
  • ApplicationContext์— ๋“ฑ๋ก๋œ Bean์€ ์„œ๋น„์Šค, ๋ฆฌํฌ์ง€ํ† ๋ฆฌ, ์ปจํŠธ๋กค๋Ÿฌ ๋“ฑ ๋‹ค์–‘ํ•œ ๊ฐ์ฒด๋กœ, ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์ง์ ‘ ์•Œ๊ฑฐ๋‚˜ ๊ด€๋ฆฌํ•˜์ง€ ์•Š๋Š” Spring ๊ด€๋ฆฌ ๊ฐ์ฒด๋“ค์ž…๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—๋Š” ํ•„ํ„ฐ ์—ญํ• ์„ ํ•  ์ˆ˜ ์žˆ๋Š” Spring ํ•„ํ„ฐ Bean๋„ ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.

๐Ÿ•ฐ๏ธ ์ดˆ๊ธฐํ™” ๋ฐ ๋“ฑ๋ก ์ˆœ์„œ: ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์™€ Spring ApplicationContext

1๏ธโƒฃ ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ ์ดˆ๊ธฐํ™”

  • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹œ์ž‘ ์‹œ, ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ๋Š” ํ•„ํ„ฐ์™€ ์„œ๋ธ”๋ฆฟ์„ ๋ฏธ๋ฆฌ ๋“ฑ๋กํ•˜์—ฌ ์ค€๋น„ํ•ฉ๋‹ˆ๋‹ค. ์ด๋•Œ Spring์˜ Bean๊ณผ๋Š” ๋ฌด๊ด€ํ•˜๊ฒŒ ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์ง์ ‘ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ์ฒด๋“ค๋งŒ ์ดˆ๊ธฐํ™”๋ฉ๋‹ˆ๋‹ค.

2๏ธโƒฃ Spring ApplicationContext ์ดˆ๊ธฐํ™”

  • ContextLoaderListener๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉด Spring์€ ApplicationContext๋ฅผ ๋กœ๋“œํ•˜๊ณ  Bean์„ ์ดˆ๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค. ์ด ์‹œ์ ์—์„œ DelegatingFilterProxy์™€ ๊ฐ™์€ ํ•„ํ„ฐ Bean๋„ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.

๐Ÿ”‘ DelegatingFilterProxy์˜ ํ•„์š”์„ฑ ๐Ÿ”‘

์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์™€ Spring ApplicationContext์˜ ์ดˆ๊ธฐํ™” ์‹œ์  ์ฐจ์ด๋กœ ์ธํ•ด, Spring ํ•„ํ„ฐ Bean์„ ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์—์„œ ์ง์ ‘ ์ธ์‹ํ•  ์ˆ˜ ์—†๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. DelegatingFilterProxy๋Š” Spring ํ•„ํ„ฐ Bean์„ ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์—์„œ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ๋„๋ก ์—ฐ๊ฒฐํ•ด์ฃผ๋Š” ๋‹ค๋ฆฌ ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.

  • ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ๋Š” DelegatingFilterProxy๋งŒ ํ•„ํ„ฐ๋กœ ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค.
  • ์š”์ฒญ์ด ๋“ค์–ด์˜ค๋ฉด DelegatingFilterProxy๊ฐ€ Spring ApplicationContext์˜ ํ•„ํ„ฐ Bean์„ ์ง€์—ฐ ์กฐํšŒํ•˜์—ฌ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

โœ๏ธ ์š”์•ฝ

  • ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ ๊ด€๋ฆฌ: ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹œ์ž‘ ์‹œ ํ•„ํ„ฐ์™€ ์„œ๋ธ”๋ฆฟ์ด ๋ฏธ๋ฆฌ ๋“ฑ๋ก๋ฉ๋‹ˆ๋‹ค.
  • Spring ApplicationContext ๊ด€๋ฆฌ: ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ ์ดˆ๊ธฐํ™” ํ›„์— ContextLoaderListener๋ฅผ ํ†ตํ•ด Bean๋“ค์ด ๋“ฑ๋ก๋ฉ๋‹ˆ๋‹ค.
  • DelegatingFilterProxy: Spring์˜ ํ•„ํ„ฐ Bean์„ ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ ํ•„ํ„ฐ์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ์ง€์—ฐ๋œ ๋ฐฉ์‹์œผ๋กœ ์—ฐ๊ฒฐํ•˜์—ฌ, ์ดˆ๊ธฐํ™” ์ˆœ์„œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค.

์ด๋กœ์จ DelegatingFilterProxy๋Š” ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์™€ Spring์˜ ์—ฐ๊ฒฐ์„ ํ†ตํ•ด Spring Bean ํ•„ํ„ฐ๊ฐ€ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ฃผ๋Š” ์ค‘์š”ํ•œ ์—ญํ• ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค! ๐ŸŒ๐Ÿ’ก


DelegatingFilterProxy๋Š” ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์™€ Spring ApplicationContext ๊ฐ„์˜ ์ดˆ๊ธฐํ™” ์‹œ์  ์ฐจ์ด๋ฅผ ๋งค๋„๋Ÿฝ๊ฒŒ ํ•ด๊ฒฐํ•˜์—ฌ, Spring์—์„œ ๊ด€๋ฆฌํ•˜๋Š” ํ•„ํ„ฐ Bean์ด ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์˜ ํ•„ํ„ฐ์ฒ˜๋Ÿผ ์ž‘๋™ํ•  ์ˆ˜ ์žˆ๋„๋ก ์ง€์›ํ•˜๋Š” ํ•ต์‹ฌ์ ์ธ ์—ฐ๊ฒฐ ๊ณ ๋ฆฌ์ž…๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ๋ฐฉ์‹ ๋•๋ถ„์—, Spring ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ์ปจํ…Œ์ด๋„ˆ์˜ ํ•„ํ„ฐ ๋“ฑ๋ก ์‹œ์ ๊ณผ๋Š” ๋…๋ฆฝ์ ์œผ๋กœ ์ดˆ๊ธฐํ™”๋˜๋ฉด์„œ๋„, Spring์˜ ์˜์กด์„ฑ ์ฃผ์ž…๊ณผ ๊ด€๋ฆฌ ๊ธฐ๋Šฅ์„ ๊ทธ๋Œ€๋กœ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. DelegatingFilterProxy๋ฅผ ํ†ตํ•ด ์š”์ฒญ ์‹œ์ ์—์„œ๋งŒ ํ•„ํ„ฐ Bean์„ ์ง€์—ฐ ์—ฐ๊ฒฐํ•˜์—ฌ ์„ฑ๋Šฅ์„ ์ตœ์ ํ™”ํ•˜๊ณ , ์ปจํ…Œ์ด๋„ˆ์™€ Spring ํ™˜๊ฒฝ์˜ ํ†ตํ•ฉ์„ ์›ํ™œํžˆ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ•ต์‹ฌ ์š”์ ์ด ์ž˜ ์ •๋ฆฌ๋œ ๋งŒํผ, Spring Security์™€ ๊ฐ™์ด ํ•„ํ„ฐ ๊ธฐ๋ฐ˜ ๋ณด์•ˆ ์„ค์ •์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ DelegatingFilterProxy์˜ ์—ญํ• ์„ ์ž˜ ์ดํ•ดํ•˜๊ณ  ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค! ๐Ÿ’ช๐ŸŒŸ


๐Ÿ›ก๏ธ FilterChainProxy์™€ DelegatingFilterProxy: Spring Security์˜ ๋ณด์•ˆ ํ•„ํ„ฐ ์ฒด์ธ ์ดํ•ดํ•˜๊ธฐ ๐Ÿ”

Spring Security์—์„œ FilterChainProxy๋Š” ์š”์ฒญ์ด ๋“ค์–ด์™”์„ ๋•Œ ๋ณด์•ˆ ํ•„ํ„ฐ๋“ค์„ ๊ด€๋ฆฌํ•˜๊ณ  ์‹คํ–‰ํ•˜๋Š” ์ค‘์š”ํ•œ ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ DelegatingFilterProxy๋Š” FilterChainProxy๊ฐ€ ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์—์„œ ํ˜ธ์ถœ๋  ์ˆ˜ ์žˆ๋„๋ก ์—ฐ๊ฒฐํ•ด ์ฃผ๋Š” ์ค‘์š”ํ•œ ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค. ์•„๋ž˜์—์„œ ๋‘ ๊ตฌ์„ฑ ์š”์†Œ์˜ ์—ญํ• ๊ณผ ๊ด€๊ณ„๋ฅผ ๋‹จ๊ณ„๋ณ„๋กœ ์ž์„ธํžˆ ์„ค๋ช…ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.


๐Ÿ”— FilterChainProxy์˜ ์—ญํ• 

1๏ธโƒฃ ๋‹ค์ค‘ ํ•„ํ„ฐ ์œ„์ž„

  • FilterChainProxy๋Š” ๋‹ค์–‘ํ•œ ๋ณด์•ˆ ํ•„ํ„ฐ๋“ค์„ ํ•˜๋‚˜์˜ ์ฒด์ธ(SecurityFilterChain)์œผ๋กœ ๋ฌถ์–ด ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ์ด ์ฒด์ธ์€ ์š”์ฒญ์ด ๋“ค์–ด์˜ฌ ๋•Œ ํ•„ํ„ฐ๋“ค์ด ์ˆœ์„œ๋Œ€๋กœ ์‹คํ–‰๋˜๋„๋ก ์„ค์ •๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์ธ์ฆ ํ•„ํ„ฐ, ๊ถŒํ•œ ๊ฒ€์ฆ ํ•„ํ„ฐ, CSRF ๋ฐฉ์ง€ ํ•„ํ„ฐ ๋“ฑ์ด SecurityFilterChain์— ํฌํ•จ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

2๏ธโƒฃ SecurityFilterChain ํ™œ์šฉ

  • FilterChainProxy๋Š” ์š”์ฒญ์ด ๋“ค์–ด์˜ค๋ฉด, ์–ด๋–ค ๋ณด์•ˆ ๊ทœ์น™์— ๋งž๋Š”์ง€ ํ™•์ธํ•˜๊ณ , ํ•ด๋‹น ๊ทœ์น™์— ๋งž๋Š” SecurityFilterChain ๋‚ด์˜ ํ•„ํ„ฐ๋“ค์„ ์ˆœ์ฐจ์ ์œผ๋กœ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์ด๋กœ ์ธํ•ด ์š”์ฒญ ๊ฒฝ๋กœ๋‚˜ ์กฐ๊ฑด์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ๋ณด์•ˆ ์ฒด์ธ์„ ์„ ํƒํ•˜์—ฌ ๋ณด์•ˆ ์ •์ฑ…์„ ์„ธ๋ฐ€ํ•˜๊ฒŒ ์ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

3๏ธโƒฃ ๋ณด์•ˆ ๋กœ์ง์˜ ์บก์Аํ™”

  • FilterChainProxy๋Š” Spring Security์˜ ๋ณด์•ˆ ๋กœ์ง์„ ์บก์Аํ™”ํ•˜์—ฌ ์ผ๊ด€๋˜๊ฒŒ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ์ด๋กœ ์ธํ•ด ๊ฐ ํ•„ํ„ฐ๊ฐ€ ์ฒด์ธ ๋‚ด์—์„œ ์„ค์ •๋œ ์ˆœ์„œ์— ๋”ฐ๋ผ ์š”์ฒญ์„ ๊ฒ€์‚ฌํ•˜๊ณ  ํ•„์š”์— ๋”ฐ๋ผ ์ฐจ๋‹จํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ”„ FilterChainProxy์™€ DelegatingFilterProxy์˜ ๊ด€๊ณ„

FilterChainProxy๋Š” Spring์ด ๊ด€๋ฆฌํ•˜๋Š” Bean์ด์ง€๋งŒ, ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ๋Š” ์ง์ ‘ Spring Bean์„ ํ˜ธ์ถœํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด DelegatingFilterProxy๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

  • DelegatingFilterProxy์˜ ์—ญํ• 

    • ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์— ๋“ฑ๋ก๋œ DelegatingFilterProxy๋Š” ๋‹จ์ˆœํžˆ Spring ApplicationContext์— ์žˆ๋Š” FilterChainProxy๋กœ ์š”์ฒญ์„ ์ „๋‹ฌํ•˜๋Š” ์ค‘๊ฐ„ ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.
    • ์ด๋กœ ์ธํ•ด ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ๋Š” FilterChainProxy๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜๊ณ , Spring Security์˜ ๋ณด์•ˆ ํ•„ํ„ฐ ์ฒด์ธ์ด ํ™œ์„ฑํ™”๋ฉ๋‹ˆ๋‹ค.
  • ๋™์ž‘ ํ๋ฆ„

    • ํด๋ผ์ด์–ธํŠธ ์š”์ฒญ์ด ๋“ค์–ด์˜ค๋ฉด ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ๋Š” DelegatingFilterProxy๋ฅผ ํ˜ธ์ถœํ•˜๊ณ , DelegatingFilterProxy๋Š” Spring ApplicationContext์—์„œ ๊ด€๋ฆฌ๋˜๋Š” FilterChainProxy๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.
    • FilterChainProxy๋Š” SecurityFilterChain์— ์„ค์ •๋œ ๋ณด์•ˆ ํ•„ํ„ฐ๋“ค์„ ์ˆœ์„œ๋Œ€๋กœ ์‹คํ–‰ํ•˜๋ฉด์„œ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“‹ ์˜ˆ์‹œ: ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€์— ์ ‘๊ทผํ•˜๋Š” ํด๋ผ์ด์–ธํŠธ ์š”์ฒญ ์ฒ˜๋ฆฌ ํ๋ฆ„

1๏ธโƒฃ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€์— ์ ‘๊ทผํ•˜๋ ค๊ณ  ์š”์ฒญ์„ ๋ณด๋ƒ„
2๏ธโƒฃ ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ๋Š” DelegatingFilterProxy๋ฅผ ํ˜ธ์ถœ
3๏ธโƒฃ DelegatingFilterProxy๋Š” FilterChainProxy๋ฅผ Spring ApplicationContext์—์„œ ์ฐพ์•„ ํ˜ธ์ถœ
4๏ธโƒฃ FilterChainProxy๋Š” SecurityFilterChain์— ์„ค์ •๋œ ํ•„ํ„ฐ๋“ค์„ ์ˆœ์„œ๋Œ€๋กœ ์‹คํ–‰:

  • ์ธ์ฆ ํ•„ํ„ฐ: ์‚ฌ์šฉ์ž๊ฐ€ ์ธ์ฆ๋œ ์ƒํƒœ์ธ์ง€ ํ™•์ธ
  • ๊ถŒํ•œ ๊ฒ€์ฆ ํ•„ํ„ฐ: ํ•ด๋‹น ํŽ˜์ด์ง€์— ์ ‘๊ทผํ•  ๊ถŒํ•œ์ด ์žˆ๋Š”์ง€ ํ™•์ธ
  • CSRF ๋ฐฉ์ง€ ํ•„ํ„ฐ: CSRF ๊ณต๊ฒฉ ๋ฐฉ์ง€ ๋กœ์ง ์‹คํ–‰

5๏ธโƒฃ ๋ชจ๋“  ํ•„ํ„ฐ๋ฅผ ํ†ต๊ณผํ•˜๋ฉด ์š”์ฒญ์ด ์ฒ˜๋ฆฌ๋˜๋ฉฐ, ํ•˜๋‚˜๋ผ๋„ ์‹คํŒจํ•˜๋ฉด ์š”์ฒญ์„ ์ฐจ๋‹จ



๐Ÿ“ ์ •๋ฆฌ

  • FilterChainProxy๋Š” Spring Security์˜ ๋‹ค์–‘ํ•œ ๋ณด์•ˆ ํ•„ํ„ฐ๋“ค์„ ๊ด€๋ฆฌํ•˜๊ณ  ์š”์ฒญ ์‹œ ์ฒด์ธ ์ˆœ์„œ๋Œ€๋กœ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  • DelegatingFilterProxy๋Š” FilterChainProxy๊ฐ€ ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์—์„œ ํ˜ธ์ถœ๋  ์ˆ˜ ์žˆ๋„๋ก ์—ฐ๊ฒฐํ•ด ์ฃผ๋Š” ์ค‘๊ฐ„ ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.
  • DelegatingFilterProxy์™€ FilterChainProxy์˜ ๊ฒฐํ•ฉ์„ ํ†ตํ•ด, Spring Security๋Š” ์„œ๋ธ”๋ฆฟ ํ™˜๊ฒฝ์—์„œ ๋ณด์•ˆ ํ•„ํ„ฐ ์ฒด์ธ์„ ํšจ์œจ์ ์œผ๋กœ ๊ด€๋ฆฌํ•˜๊ณ  ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์ด ๋‘ ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ํ•จ๊ป˜ ์ž‘๋™ํ•จ์œผ๋กœ์จ Spring Security๋Š” ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์—์„œ ๋‹ค์–‘ํ•œ ๋ณด์•ˆ ํ•„ํ„ฐ๋ฅผ ์•ˆ์ •์ ์ด๊ณ  ์ผ๊ด€์„ฑ ์žˆ๊ฒŒ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค! ๐Ÿ›ก๏ธ๐Ÿ’ฅ


SecurityFilterChain

SecurityFilterChain์€ FilterChainProxy๊ฐ€ ํ˜„์žฌ ์š”์ฒญ์— ๋Œ€ํ•ด ํ˜ธ์ถœํ•ด์•ผ ํ•  Spring Security ํ•„ํ„ฐ ์ธ์Šคํ„ด์Šค๋ฅผ ๊ฒฐ์ •ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.


๐Ÿ›ก๏ธ FilterChainProxy์™€ SecurityFilterChain: Spring Security์˜ ์œ ์—ฐํ•œ ๋ณด์•ˆ ํ•„ํ„ฐ ๊ด€๋ฆฌ ์‹œ์Šคํ…œ ๐ŸŒ

FilterChainProxy์™€ SecurityFilterChain์€ Spring Security๊ฐ€ ์ œ๊ณตํ•˜๋Š” ๋ณด์•ˆ ํ•„ํ„ฐ ์ฒด์ธ์„ ์œ ์—ฐํ•˜๊ฒŒ ๊ด€๋ฆฌํ•˜๊ณ , ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์˜ ์ œ์•ฝ์„ ๋„˜์–ด ์ตœ์ ํ™”๋œ ๋ณด์•ˆ ์„ค์ •์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค. ์ด ๋‘ ๊ตฌ์„ฑ ์š”์†Œ์˜ ์—ญํ• ๊ณผ ์ƒํ˜ธ ๊ด€๊ณ„๋ฅผ ์ž์„ธํžˆ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.


๐Ÿ”— SecurityFilterChain๊ณผ FilterChainProxy์˜ ๊ด€๊ณ„

  • SecurityFilterChain์€ ํŠน์ • ์š”์ฒญ์ด ๋“ค์–ด์™”์„ ๋•Œ, ์‹คํ–‰๋  ๋ณด์•ˆ ํ•„ํ„ฐ๋“ค์„ ์„ ํƒํ•˜์—ฌ FilterChainProxy์— ๋“ฑ๋กํ•˜๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.
  • SecurityFilterChain์—๋Š” ์ธ์ฆ, ๊ถŒํ•œ ๋ถ€์—ฌ, CSRF ๋ณดํ˜ธ ๋“ฑ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ํ•„ํ„ฐ๊ฐ€ ํฌํ•จ๋˜๋ฉฐ, ์š”์ฒญ ๊ฒฝ๋กœ๋‚˜ ์กฐ๊ฑด์— ๋”ฐ๋ผ ํ•„ํ„ฐ ์ฒด์ธ์„ ๋‹ค๋ฅด๊ฒŒ ๊ตฌ์„ฑํ•˜์—ฌ ์œ ์—ฐํ•œ ๋ณด์•ˆ ์ฒ˜๋ฆฌ๋ฅผ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.
  • FilterChainProxy๋Š” ์ด SecurityFilterChain์„ ๊ด€๋ฆฌํ•˜์—ฌ, ํ•„ํ„ฐ ์ฒด์ธ ๋‚ด์˜ ๊ฐ ๋ณด์•ˆ ํ•„ํ„ฐ๊ฐ€ ์ˆœ์„œ์— ๋”ฐ๋ผ ์‹คํ–‰๋˜๋„๋ก ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿงฉ FilterChainProxy์˜ ์—ญํ• ๊ณผ ์žฅ์ 

1๏ธโƒฃ ์ค‘์•™ ๊ด€๋ฆฌ ํฌ์ธํŠธ ์ œ๊ณต

  • FilterChainProxy๋Š” Spring Security์˜ ์„œ๋ธ”๋ฆฟ ๊ธฐ๋ฐ˜ ๋ณด์•ˆ ๊ธฐ๋Šฅ์˜ ์‹œ์ž‘ ์ง€์ ์œผ๋กœ, ๋ชจ๋“  ๋ณด์•ˆ ํ•„ํ„ฐ๊ฐ€ FilterChainProxy๋ฅผ ๊ฑฐ์ณ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. ์ด๋กœ ์ธํ•ด ๋ณด์•ˆ ํ๋ฆ„์„ ๋””๋ฒ„๊ทธํ•˜๊ฑฐ๋‚˜ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ๊ฐ€ ์šฉ์ดํ•ฉ๋‹ˆ๋‹ค.
  • ์˜ˆ๋ฅผ ๋“ค์–ด, ํŠน์ • ํ•„ํ„ฐ ๋‹จ๊ณ„์—์„œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด FilterChainProxy์— ๋””๋ฒ„๊ทธ ํฌ์ธํŠธ๋ฅผ ์„ค์ •ํ•˜์—ฌ ์ „์ฒด ๋ณด์•ˆ ๋กœ์ง์˜ ํ๋ฆ„์„ ์ถ”์ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

2๏ธโƒฃ SecurityContext ๊ด€๋ฆฌ

  • FilterChainProxy๋Š” SecurityContext๋ฅผ ๊ด€๋ฆฌํ•˜์—ฌ, ์š”์ฒญ์ด ์™„๋ฃŒ๋˜๋ฉด ์ด๋ฅผ ์ดˆ๊ธฐํ™”ํ•ด ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜๋ฅผ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค.
  • SecurityContext๋Š” ์ธ์ฆ ์ •๋ณด ๋“ฑ์„ ์ €์žฅํ•˜๋Š” ๊ฐ์ฒด์ด๋ฏ€๋กœ ์š”์ฒญ๋งˆ๋‹ค ์•ˆ์ „ํ•˜๊ฒŒ ๊ด€๋ฆฌ๋˜์–ด์•ผ ํ•˜๋ฉฐ, ์š”์ฒญ ํ›„ ์ดˆ๊ธฐํ™”ํ•จ์œผ๋กœ์จ ๋ณด์•ˆ๊ณผ ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ์ธก๋ฉด์—์„œ ์žฅ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

3๏ธโƒฃ HttpFirewall ์ ์šฉ

  • FilterChainProxy๋Š” HttpFirewall์„ ์ ์šฉํ•˜์—ฌ, ๋ณด์•ˆ ํ•„ํ„ฐ ์ฒด์ธ์œผ๋กœ ๋“ค์–ด์˜ค๋Š” ์š”์ฒญ์„ ๊ฒ€์‚ฌํ•˜๊ณ  XSS, ๊ฒฝ๋กœ ํƒ์ƒ‰ ๋“ฑ์˜ ๊ณต๊ฒฉ์„ ์ฐจ๋‹จํ•ฉ๋‹ˆ๋‹ค.
  • HttpFirewall์€ ๊ฒฝ๋กœ ์กฐ์ž‘๊ณผ ๊ฐ™์€ ํŠน์ • ์œ ํ˜•์˜ ๊ณต๊ฒฉ์„ ๋ฐฉ์–ดํ•˜๋ฉฐ, Spring Security์˜ ๋ณด์•ˆ์„ฑ์„ ๊ฐ•ํ™”ํ•˜๋Š” ๋ฐ ์ค‘์š”ํ•œ ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.

๐ŸŒ SecurityFilterChain์˜ ์œ ์—ฐ์„ฑ: URL ๊ธฐ๋ฐ˜ ํ˜ธ์ถœ์„ ๋„˜์–ด์„  ํ•„ํ„ฐ ์กฐ๊ฑด ์„ค์ •

์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ๋Š” ๋ณดํ†ต URL ํŒจํ„ด์— ๋”ฐ๋ผ ํ•„ํ„ฐ๋ฅผ ํ˜ธ์ถœํ•˜์ง€๋งŒ, FilterChainProxy๋Š” SecurityFilterChain์„ ํ†ตํ•ด ์š”์ฒญ์˜ ์„ธ๋ถ€ ์กฐ๊ฑด์— ๋งž์ถฐ ํ•„ํ„ฐ ์ฒด์ธ์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Spring Security์˜ RequestMatcher ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ํ™œ์šฉํ•ด, URL๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์š”์ฒญ ํ—ค๋”, ํŒŒ๋ผ๋ฏธํ„ฐ, ๋ฉ”์„œ๋“œ ๋“ฑ ๋‹ค์–‘ํ•œ ์กฐ๊ฑด์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•„ํ„ฐ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด:

  • ํŠน์ • ํ—ค๋”๊ฐ€ ์žˆ๋Š” ์š”์ฒญ์—๋งŒ ํ•„ํ„ฐ ์ ์šฉ: ํŠน์ • ํ—ค๋”๊ฐ€ ํฌํ•จ๋œ ์š”์ฒญ์— ๋Œ€ํ•ด์„œ๋งŒ ๋ณด์•ˆ ํ•„ํ„ฐ๋ฅผ ์ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • GET๊ณผ POST ์š”์ฒญ์— ๋‹ค๋ฅธ ํ•„ํ„ฐ ์ ์šฉ: GET ์š”์ฒญ์€ ์ธ์ฆ์„ ์š”๊ตฌํ•˜์ง€ ์•Š๊ณ , POST ์š”์ฒญ์—๋Š” ์ธ์ฆ์ด ํ•„์š”ํ•œ ๊ตฌ์กฐ๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ๊ธฐ๋Šฅ์„ ํ†ตํ•ด FilterChainProxy๋Š” ๋‹จ์ˆœ URL ํŒจํ„ด์— ์˜์กดํ•˜์ง€ ์•Š๊ณ , HttpServletRequest์˜ ๋‹ค์–‘ํ•œ ์กฐ๊ฑด์— ๋”ฐ๋ผ ๋ณด์•ˆ ํ•„ํ„ฐ๋ฅผ ์„ธ๋ฐ€ํ•˜๊ฒŒ ์ œ์–ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


๐Ÿ“ ์š”์•ฝ

  • FilterChainProxy๋Š” Spring Security์˜ ์„œ๋ธ”๋ฆฟ ๊ธฐ๋ฐ˜ ๋ณด์•ˆ ํ•„ํ„ฐ๋ฅผ ์ค‘์•™์—์„œ ๊ด€๋ฆฌํ•˜์—ฌ ๋””๋ฒ„๊น…๊ณผ ๋ฌธ์ œ ํ•ด๊ฒฐ์„ ์šฉ์ดํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.
  • SecurityContext ์ดˆ๊ธฐํ™”์™€ HttpFirewall ์ ์šฉ์„ ํ†ตํ•ด ๋ณด์•ˆ์„ฑ์„ ๊ฐ•ํ™”ํ•˜๋ฉฐ, ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ๋„ ํ•จ๊ป˜ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  • SecurityFilterChain์„ ํ†ตํ•ด ์š”์ฒญ ๊ฒฝ๋กœ ์™ธ์—๋„ ์š”์ฒญ์˜ ๋‹ค์–‘ํ•œ ์กฐ๊ฑด์— ๋”ฐ๋ผ ๋ณด์•ˆ ํ•„ํ„ฐ๋ฅผ ์œ ์—ฐํ•˜๊ฒŒ ์ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฒฐ๊ณผ์ ์œผ๋กœ, FilterChainProxy๋Š” Spring Security์˜ ๋ชจ๋“  ๋ณด์•ˆ ํ•„ํ„ฐ๋ฅผ ํ†ตํ•ฉ ๊ด€๋ฆฌํ•˜๊ณ , ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์˜ ๊ธฐ๋ณธ ํ•„ํ„ฐ ๊ด€๋ฆฌ๋ณด๋‹ค ํ›จ์”ฌ ์œ ์—ฐํ•˜๊ณ  ํ™•์žฅ ๊ฐ€๋Šฅํ•œ ๋ณด์•ˆ ์„ค์ •์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ตฌ์กฐ๋Š” Spring Security์˜ ๋ณด์•ˆ ๊ธฐ๋Šฅ์„ ํšจ์œจ์ ์œผ๋กœ ๊ด€๋ฆฌํ•˜๊ณ  ํ™•์žฅํ•  ์ˆ˜ ์žˆ๋Š” ์ค‘์š”ํ•œ ๊ธฐ๋ฐ˜์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๐Ÿ›ก๏ธโœจ


๐Ÿ” SecurityContext: Spring Security์—์„œ ์ธ์ฆ ๋ฐ ๊ถŒํ•œ ์ •๋ณด์˜ ์ค‘์•™ ์ €์žฅ์†Œ ๐ŸŒ

SecurityContext๋Š” Spring Security๊ฐ€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์ธ์ฆ ๋ฐ ๊ถŒํ•œ ์ •๋ณด๋ฅผ ์ €์žฅํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๋Š” ์ค‘์•™ ์ €์žฅ์†Œ๋กœ, ํ˜„์žฌ ์‚ฌ์šฉ์ž์˜ ์ธ์ฆ ์ƒํƒœ์™€ ๊ถŒํ•œ์„ ์‰ฝ๊ฒŒ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๋„๋ก ๋•์Šต๋‹ˆ๋‹ค.


๐Ÿ› ๏ธ SecurityContext์˜ ์ฃผ์š” ๊ธฐ๋Šฅ

1๏ธโƒฃ ์ธ์ฆ ์ •๋ณด ์ €์žฅ

  • SecurityContext๋Š” ํ˜„์žฌ ์ธ์ฆ๋œ ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ๋‹ด๊ณ  ์žˆ์œผ๋ฉฐ, Authentication ๊ฐ์ฒด์— ์‚ฌ์šฉ์ž์˜ ID, ์ธ์ฆ ๋ฐฉ์‹, ๊ถŒํ•œ ์ •๋ณด ๋“ฑ์ด ์ €์žฅ๋ฉ๋‹ˆ๋‹ค.

2๏ธโƒฃ ๊ถŒํ•œ ๊ด€๋ฆฌ

  • SecurityContext์— ์ €์žฅ๋œ ์ •๋ณด๋กœ ์‚ฌ์šฉ์ž๊ฐ€ ํŠน์ • ์ž์›์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์‚ฌ์šฉ์ž์˜ ์—ญํ• (Role)๊ณผ ๊ถŒํ•œ์„ ๋ฐ”ํƒ•์œผ๋กœ ์ ‘๊ทผ ๊ถŒํ•œ์„ ๊ฒ€์‚ฌํ•˜์—ฌ, ์š”์ฒญ์— ๋Œ€ํ•ด ์ ์ ˆํ•œ ๊ถŒํ•œ ๊ฒ€์‚ฌ๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

3๏ธโƒฃ ์ „์—ญ ์ ‘๊ทผ ๊ฐ€๋Šฅ

  • SecurityContext๋Š” ์Šค๋ ˆ๋“œ ๋กœ์ปฌ(ThreadLocal)์— ์ €์žฅ๋˜์–ด, ๋™์ผํ•œ ์š”์ฒญ ํ๋ฆ„ ๋‚ด์—์„œ ์ธ์ฆ ์ •๋ณด๊ฐ€ ์œ ์ง€๋ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋‚ด์—์„œ ์–ด๋””์„œ๋“  ํ˜„์žฌ ์‚ฌ์šฉ์ž์˜ ์ธ์ฆ ์ƒํƒœ๋ฅผ ์‰ฝ๊ฒŒ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • SecurityContextHolder๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ˜„์žฌ ์‚ฌ์šฉ์ž์˜ SecurityContext์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ”„ SecurityContext์˜ ๊ตฌ์กฐ์™€ ์ž‘๋™ ๋ฐฉ์‹

  • SecurityContextHolder๋Š” SecurityContext๋ฅผ ๊ด€๋ฆฌํ•˜๋ฉฐ, ์Šค๋ ˆ๋“œ ๋กœ์ปฌ์— ์ธ์ฆ ์ •๋ณด๋ฅผ ์ €์žฅํ•˜์—ฌ ์š”์ฒญ ํ๋ฆ„ ๋‚ด์—์„œ ์ผ๊ด€์„ฑ ์žˆ๊ฒŒ ์ฐธ์กฐ๋ฉ๋‹ˆ๋‹ค.
  • ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์ธํ•˜๋ฉด ์ธ์ฆ ์ •๋ณด๊ฐ€ SecurityContext์— ์ €์žฅ๋˜๊ณ , ์š”์ฒญ์ด ๋“ค์–ด์˜ฌ ๋•Œ๋งˆ๋‹ค ์ด ์ •๋ณด๋ฅผ ์ฐธ์กฐํ•˜์—ฌ ์ธ์ฆ ์ƒํƒœ์™€ ๊ถŒํ•œ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ“‹ ์˜ˆ์‹œ: SecurityContextHolder๋ฅผ ํ†ตํ•œ ํ˜„์žฌ ์‚ฌ์šฉ์ž ์ •๋ณด ์กฐํšŒ

๋‹ค์Œ ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด SecurityContext์— ์ €์žฅ๋œ ํ˜„์žฌ ์‚ฌ์šฉ์ž ์ด๋ฆ„์„ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String username = authentication.getName();  // ํ˜„์žฌ ์‚ฌ์šฉ์ž ์ด๋ฆ„ ๊ฐ€์ ธ์˜ค๊ธฐ

์ด ์ฝ”๋“œ๋Š” SecurityContextHolder๋ฅผ ํ†ตํ•ด SecurityContext์—์„œ ํ˜„์žฌ ์ธ์ฆ๋œ ์‚ฌ์šฉ์ž์˜ ์ •๋ณด๋ฅผ ์กฐํšŒํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.


๐Ÿ”‘ SecurityContext์˜ ์ดˆ๊ธฐํ™”์™€ ํ•ด์ œ

  • ์ดˆ๊ธฐํ™”: ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์ธํ•  ๋•Œ Spring Security๋Š” ์‚ฌ์šฉ์ž์˜ ์ธ์ฆ ์ •๋ณด๋ฅผ SecurityContext์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.
  • ํ•ด์ œ: ์š”์ฒญ์ด ์™„๋ฃŒ๋˜๋ฉด FilterChainProxy๊ฐ€ SecurityContext๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜์—ฌ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜๋ฅผ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์š”์ฒญ ๋‹จ์œ„๋กœ SecurityContext๊ฐ€ ์•ˆ์ „ํ•˜๊ฒŒ ๊ด€๋ฆฌ๋ฉ๋‹ˆ๋‹ค.

๐Ÿ“ ์š”์•ฝ

SecurityContext๋Š” Spring Security์—์„œ ์ธ์ฆ๋œ ์‚ฌ์šฉ์ž ์ •๋ณด์™€ ๊ถŒํ•œ์„ ์ค‘์•™์—์„œ ๊ด€๋ฆฌํ•˜๋ฉฐ, ์š”์ฒญ๋งˆ๋‹ค ์ธ์ฆ๊ณผ ๊ถŒํ•œ ๊ฒ€์‚ฌ๋ฅผ ์‰ฝ๊ฒŒ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค. ์š”์ฒญ์ด ๋๋‚œ ํ›„์—๋Š” SecurityContext๊ฐ€ ์ดˆ๊ธฐํ™”๋˜์–ด, ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ์—†์ด ์•ˆ์ „ํ•˜๊ฒŒ ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๐Ÿ›ก๏ธ๐Ÿ’ก


๐Ÿงต ThreadLocal: ์Šค๋ ˆ๋“œ๋ณ„ ๋…๋ฆฝ์ ์ธ ๋ฐ์ดํ„ฐ ์ €์žฅ์†Œ ๐ŸŒ

ThreadLocal์€ ๊ฐ ์Šค๋ ˆ๋“œ๋งˆ๋‹ค ๋…๋ฆฝ์ ์œผ๋กœ ๊ฐ’์„ ์ €์žฅํ•  ์ˆ˜ ์žˆ๋Š” ์ €์žฅ์†Œ๋ฅผ ์ œ๊ณตํ•˜์—ฌ, ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ๊ฐ€ ๊ฐ™์€ ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋”๋ผ๋„ ๊ฐ ์Šค๋ ˆ๋“œ๊ฐ€ ์„œ๋กœ ๋‹ค๋ฅธ ๊ฐ’์„ ๊ฐ–๋„๋ก ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋™์‹œ์„ฑ ๋ฌธ์ œ ์—†์ด ์Šค๋ ˆ๋“œ๋ณ„ ๋ฐ์ดํ„ฐ๋ฅผ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


๐Ÿ› ๏ธ ThreadLocal์˜ ์ฃผ์š” ํŠน์ง•

1๏ธโƒฃ ์Šค๋ ˆ๋“œ๋ณ„ ๋…๋ฆฝ์„ฑ

  • ThreadLocal์€ ๊ฐ ์Šค๋ ˆ๋“œ๊ฐ€ ์ž์‹ ๋งŒ์˜ ๊ฐ’์„ ๊ฐ–๋„๋ก ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ๋‘ ๊ฐœ์˜ ์Šค๋ ˆ๋“œ๊ฐ€ ๊ฐ™์€ ThreadLocal ๊ฐ์ฒด์— ์ ‘๊ทผํ•˜๋”๋ผ๋„ ์„œ๋กœ ๋‹ค๋ฅธ ๊ฐ’์„ ์ €์žฅํ•˜๊ณ  ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

2๏ธโƒฃ ๋™์‹œ์„ฑ ๋ฌธ์ œ ํ•ด๊ฒฐ

  • ์ผ๋ฐ˜์ ์œผ๋กœ ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ๊ฐ€ ๊ฐ™์€ ๋ณ€์ˆ˜์— ์ ‘๊ทผํ•˜๋ฉด ๋™๊ธฐํ™”๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ ์ถฉ๋Œ์„ ๋ฐฉ์ง€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ThreadLocal์„ ์‚ฌ์šฉํ•˜๋ฉด ๊ฐ ์Šค๋ ˆ๋“œ๊ฐ€ ๊ณ ์œ ์˜ ๊ฐ’์„ ๊ฐ€์ง€๋ฏ€๋กœ ๋™๊ธฐํ™” ์—†์ด ์•ˆ์ „ํ•˜๊ฒŒ ๊ฐ’์„ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ“‹ ์‚ฌ์šฉ ์˜ˆ์‹œ

์Šค๋ ˆ๋“œ๋งˆ๋‹ค ํŠน์ • ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ์ €์žฅํ•˜๊ณ  ์‹ถ์„ ๋•Œ, ThreadLocal์„ ์ด์šฉํ•˜๋ฉด ๊ฐ ์Šค๋ ˆ๋“œ๊ฐ€ ๋…๋ฆฝ์ ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

public class UserContext {
    private static ThreadLocal<String> userThreadLocal = new ThreadLocal<>();

    public static void setUser(String user) {
        userThreadLocal.set(user); // ํ˜„์žฌ ์Šค๋ ˆ๋“œ์— ์‚ฌ์šฉ์ž ์ •๋ณด ์ €์žฅ
    }

    public static String getUser() {
        return userThreadLocal.get(); // ํ˜„์žฌ ์Šค๋ ˆ๋“œ์˜ ์‚ฌ์šฉ์ž ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ
    }

    public static void clear() {
        userThreadLocal.remove(); // ํ˜„์žฌ ์Šค๋ ˆ๋“œ์˜ ์‚ฌ์šฉ์ž ์ •๋ณด ์‚ญ์ œ
    }
}

์œ„ ์ฝ”๋“œ์—์„œ UserContext ํด๋ž˜์Šค์˜ userThreadLocal ๋ณ€์ˆ˜๋Š” ๊ฐ ์Šค๋ ˆ๋“œ๊ฐ€ ๋…๋ฆฝ์ ์ธ ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ์ €์žฅํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค.


๐Ÿ”’ ThreadLocal์˜ ์‚ฌ์šฉ ์‚ฌ๋ก€: SecurityContext์™€ ๊ฐ™์€ ์ธ์ฆ ์ •๋ณด ๊ด€๋ฆฌ

Spring Security์—์„œ๋Š” SecurityContext๋ฅผ ThreadLocal์„ ํ†ตํ•ด ๊ด€๋ฆฌํ•˜์—ฌ, ๊ฐ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ์Šค๋ ˆ๋“œ์— ์ธ์ฆ ์ •๋ณด๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฐฉ์‹์œผ๋กœ ์š”์ฒญ ์ค‘ ์–ธ์ œ๋“  ํ˜„์žฌ ์Šค๋ ˆ๋“œ์˜ ์‚ฌ์šฉ์ž ์ •๋ณด์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์š”์ฒญ์ด ๋๋‚˜๋ฉด ์ด ์ •๋ณด๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜์—ฌ ๋‹ค๋ฅธ ์š”์ฒญ์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.


โš ๏ธ ์ฃผ์˜์‚ฌํ•ญ

  • ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ๊ฐ€๋Šฅ์„ฑ
    • ThreadLocal์— ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ๊ฐ€ ์ œ๊ฑฐ๋˜์ง€ ์•Š์œผ๋ฉด ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํŠนํžˆ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„œ๋ฒ„์—์„œ ์Šค๋ ˆ๋“œ๊ฐ€ ์žฌ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ, ์š”์ฒญ์ด ๋๋‚  ๋•Œ๋งˆ๋‹ค remove() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ์ •๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“ ์š”์•ฝ

ThreadLocal์€ ์Šค๋ ˆ๋“œ๋ณ„๋กœ ๋…๋ฆฝ์ ์ธ ๊ฐ’์„ ์ œ๊ณตํ•˜์—ฌ ๋™์‹œ์„ฑ ๋ฌธ์ œ ์—†์ด ๋ฐ์ดํ„ฐ๋ฅผ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ์œ ์šฉํ•œ ์ €์žฅ์†Œ์ž…๋‹ˆ๋‹ค. Spring Security์—์„œ๋Š” ์ด ๊ธฐ๋Šฅ์„ ํ™œ์šฉํ•˜์—ฌ ๊ฐ ์š”์ฒญ์— ๋Œ€ํ•œ ์ธ์ฆ ์ •๋ณด๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์ธ์ฆ ์ •๋ณด๊ฐ€ ์Šค๋ ˆ๋“œ ๊ฐ„์— ์„ž์ด๋Š” ๋ฌธ์ œ๋ฅผ ๋ฐฉ์ง€ํ•˜๊ณ , ์š”์ฒญ์ด ๋๋‚  ๋•Œ๋งˆ๋‹ค ๋ฐ์ดํ„ฐ๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜์—ฌ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜๋ฅผ ์˜ˆ๋ฐฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๐Ÿ›ก๏ธ๐Ÿ’ก


๐Ÿ›ก๏ธ HttpFirewall: Spring Security์˜ HTTP ๊ณต๊ฒฉ ๋ฐฉ์–ด์„  ๐ŸŒ

HttpFirewall์€ Spring Security๊ฐ€ ์ˆ˜์‹ ํ•œ HTTP ์š”์ฒญ์„ ๊ฒ€์‚ฌํ•˜๊ณ , ์˜์‹ฌ์Šค๋Ÿฌ์šด ์š”์ฒญ์„ ํ•„ํ„ฐ๋ง ๋ฐ ์ฐจ๋‹จํ•˜์—ฌ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์•ˆ์ „ํ•˜๊ฒŒ ๋™์ž‘ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋•๋Š” ์ค‘์š”ํ•œ ๋ณด์•ˆ ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค. ์ฃผ๋กœ XSS, ๊ฒฝ๋กœ ํƒ์ƒ‰, HTTP ํ—ค๋” ์กฐ์ž‘๊ณผ ๊ฐ™์€ ๋ณด์•ˆ ์œ„ํ˜‘์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค.


๐Ÿงฉ HttpFirewall์˜ ์ฃผ์š” ์—ญํ• 

1๏ธโƒฃ URL ๋ฐ ๊ฒฝ๋กœ ๊ฒ€์‚ฌ

  • ๊ฒฝ๋กœ ํƒ์ƒ‰(Path Traversal)์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด, ์š”์ฒญ URL์„ ๊ฒ€์‚ฌํ•˜๊ณ  ../์™€ ๊ฐ™์€ ์ƒ์œ„ ๋””๋ ‰ํ„ฐ๋ฆฌ ์ด๋™ ์‹œ๋„๋ฅผ ์ฐจ๋‹จํ•ฉ๋‹ˆ๋‹ค.

2๏ธโƒฃ HTTP ํ—ค๋” ๋ฐ ๋ฉ”์„œ๋“œ ๊ฒ€์‚ฌ

  • ๋น„์ •์ƒ์ ์ด๊ฑฐ๋‚˜ ์•…์˜์ ์ธ HTTP ํ—ค๋”๋‚˜ ๋ฉ”์„œ๋“œ๊ฐ€ ํฌํ•จ๋œ ์š”์ฒญ์„ ๊ฑฐ๋ถ€ํ•ฉ๋‹ˆ๋‹ค. ์ž˜ ์•Œ๋ ค์ง€์ง€ ์•Š์€ ๋ฉ”์„œ๋“œ๋‚˜ ์˜ˆ์ƒ ์™ธ์˜ ํ—ค๋”๋Š” ์•…์˜์ ์ผ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’๊ธฐ ๋•Œ๋ฌธ์— ํ•„ํ„ฐ๋งํ•ฉ๋‹ˆ๋‹ค.

3๏ธโƒฃ ํ—ˆ์šฉ๋˜์ง€ ์•Š์€ ๋ฌธ์ž ์ฐจ๋‹จ

  • ์š”์ฒญ URL์— ์•…์„ฑ ์ฝ”๋“œ๋ฅผ ํฌํ•จํ•œ ํŠน์ˆ˜ ๋ฌธ์ž๋‚˜ XSS์™€ ๊ด€๋ จ๋œ ํŒจํ„ด์ด ์žˆ๋Š” ๊ฒฝ์šฐ ์ด๋ฅผ ํƒ์ง€ํ•˜๊ณ  ์ฐจ๋‹จํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“‹ HttpFirewall์˜ ์‚ฌ์šฉ ์˜ˆ์‹œ

Spring Security์—์„œ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ StrictHttpFirewall์„ ํ†ตํ•ด ์š”์ฒญ ๊ฒ€์‚ฌ๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์„ค์ •์„ ํ†ตํ•ด ํŠน์ • ์š”์ฒญ ํŒจํ„ด์„ ํ—ˆ์šฉํ•˜๊ฑฐ๋‚˜ ์ฐจ๋‹จํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.firewall.HttpFirewall;
import org.springframework.security.web.firewall.StrictHttpFirewall;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SecurityConfig {

    @Bean
    public HttpFirewall httpFirewall() {
        StrictHttpFirewall firewall = new StrictHttpFirewall();
        firewall.setAllowUrlEncodedSlash(true); // ํŠน์ • ๋ฌธ์ž ํ—ˆ์šฉ ์„ค์ •
        return firewall;
    }

    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
            .anyRequest().authenticated()
            .and()
            .httpFirewall(httpFirewall()); // ์ปค์Šคํ…€ HttpFirewall ์„ค์ • ์ ์šฉ
    }
}

์œ„ ์˜ˆ์‹œ์—์„œ StrictHttpFirewall์„ ์‚ฌ์šฉํ•ด URL ์ธ์ฝ”๋”ฉ๋œ ์Šฌ๋ž˜์‹œ๋ฅผ ํ—ˆ์šฉํ•˜๋„๋ก ์„ค์ •ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด์ฒ˜๋Ÿผ HttpFirewall ์„ค์ •์„ ํ†ตํ•ด ํŠน์ˆ˜ ๋ฌธ์ž๋‚˜ ์š”์ฒญ ์กฐ๊ฑด์„ ์ปค์Šคํ„ฐ๋งˆ์ด์ง•ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


๐Ÿ”’ HttpFirewall์˜ ์ฃผ์š” ๊ตฌ์„ฑ ์š”์†Œ

  • StrictHttpFirewall
    • ๊ธฐ๋ณธ์ ์œผ๋กœ ์—„๊ฒฉํ•œ ๊ฒ€์‚ฌ ๊ทœ์น™์„ ์ ์šฉํ•˜๋ฉฐ, ์˜ˆ์ƒํ•˜์ง€ ๋ชปํ•œ ๊ฒฝ๋กœ๋‚˜ ์ž˜๋ชป๋œ ํŒจํ„ด์„ ๊ฐ€์ง„ ์š”์ฒญ์„ ์ฐจ๋‹จํ•ฉ๋‹ˆ๋‹ค.
  • RequestRejectedException
    • HttpFirewall์ด ์œ ํšจํ•˜์ง€ ์•Š์€ ์š”์ฒญ์„ ํƒ์ง€ํ•˜๋ฉด RequestRejectedException์„ ๋ฐœ์ƒ์‹œ์ผœ ํ•ด๋‹น ์š”์ฒญ์„ ๊ฑฐ๋ถ€ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ›ก๏ธ HttpFirewall์ด ๋ฐฉ์–ดํ•˜๋Š” ์ฃผ์š” ๊ณต๊ฒฉ ์œ ํ˜•

  1. ๊ฒฝ๋กœ ํƒ์ƒ‰(Path Traversal)

    • ../์™€ ๊ฐ™์€ ๊ฒฝ๋กœ ์ด๋™์„ ํ†ตํ•ด ์‹œ์Šคํ…œ ๋ฏผ๊ฐ ํŒŒ์ผ์— ์ ‘๊ทผํ•˜๋ ค๋Š” ์‹œ๋„๋ฅผ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค.
  2. XSS(Cross-Site Scripting)

    • ์š”์ฒญ URL์ด๋‚˜ ํ—ค๋”์— ์•…์„ฑ JavaScript ์ฝ”๋“œ๊ฐ€ ํฌํ•จ๋œ ๊ฒฝ์šฐ ์ด๋ฅผ ์ฐจ๋‹จํ•˜์—ฌ ํด๋ผ์ด์–ธํŠธ ์ธก์—์„œ ์•…์„ฑ ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋˜์ง€ ์•Š๋„๋ก ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค.
  3. HTTP ํ—ค๋” ์กฐ์ž‘

    • ์ž˜๋ชป๋œ ํ—ค๋” ๋˜๋Š” ์•…์˜์ ์ธ ํ—ค๋” ๊ฐ’์ด ํฌํ•จ๋œ ์š”์ฒญ์„ ๊ฒ€์‚ฌํ•˜์—ฌ ์ฐจ๋‹จํ•ฉ๋‹ˆ๋‹ค.
  4. SQL Injection ๋ฐ ๊ธฐํƒ€ ์ธ์ฝ”๋”ฉ ๊ณต๊ฒฉ

    • URL์— ์˜์‹ฌ์Šค๋Ÿฌ์šด ์ธ์ฝ”๋”ฉ์ด ํฌํ•จ๋˜์–ด ์žˆ๋Š” ๊ฒฝ์šฐ ์ด๋ฅผ ๊ฐ์ง€ํ•˜๊ณ , SQL Injection๊ณผ ๊ฐ™์€ ์ž ์žฌ์  ๊ณต๊ฒฉ์„ ์ฐจ๋‹จํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“ ์š”์•ฝ

HttpFirewall์€ Spring Security์—์„œ ์ œ๊ณตํ•˜๋Š” ํ•„์ˆ˜ ๋ณด์•ˆ ๊ธฐ๋Šฅ์œผ๋กœ, ์˜์‹ฌ์Šค๋Ÿฌ์šด HTTP ์š”์ฒญ์„ ๊ฐ์ง€ํ•˜๊ณ  ์ฐจ๋‹จํ•˜์—ฌ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์ž ์žฌ์  ๋ณด์•ˆ ์œ„ํ˜‘์œผ๋กœ๋ถ€ํ„ฐ ๋ณดํ˜ธํ•ฉ๋‹ˆ๋‹ค. ์ฃผ๋กœ ๊ฒฝ๋กœ ํƒ์ƒ‰, XSS, HTTP ํ—ค๋” ์กฐ์ž‘ ๋“ฑ์˜ ๊ณต๊ฒฉ์„ ๋ฐฉ์–ดํ•˜๋ฉฐ, ๊ธฐ๋ณธ์ ์œผ๋กœ ์—„๊ฒฉํ•œ ์š”์ฒญ ํ•„ํ„ฐ๋ง์„ ์ˆ˜ํ–‰ํ•˜๋Š” StrictHttpFirewall์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์„ค์ •์„ ํ†ตํ•ด ํŠน์ • ํ—ˆ์šฉ ์กฐ๊ฑด์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, Spring Security์˜ ์ค‘์š”ํ•œ ๋ฐฉ์–ด์„  ์—ญํ• ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ๐Ÿ›ก๏ธโœจ


๐Ÿ›ก๏ธ FilterChainProxy์™€ RequestMatcher: Spring Security์˜ ์œ ์—ฐํ•œ ๋ณด์•ˆ ํ•„ํ„ฐ ์ ์šฉ ๐ŸŒ

FilterChainProxy๋Š” Spring Security์—์„œ RequestMatcher ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ํ†ตํ•ด URL ํŒจํ„ด์„ ๋„˜์–ด ์š”์ฒญ์˜ ๋‹ค์–‘ํ•œ ์กฐ๊ฑด์„ ๋ฐ”ํƒ•์œผ๋กœ ๋ณด์•ˆ ํ•„ํ„ฐ๋ฅผ ์„ ํƒ์ ์œผ๋กœ ์ ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค. ์ด๋Š” ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์˜ URL ํŒจํ„ด ๊ธฐ๋ฐ˜ ํ˜ธ์ถœ ๋ฐฉ์‹๊ณผ ์ฐจ๋ณ„ํ™”๋œ ์œ ์—ฐํ•œ ๋ณด์•ˆ ์„ค์ •์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.


๐Ÿงฉ ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์˜ ํ•„ํ„ฐ ํ˜ธ์ถœ ๋ฐฉ์‹: URL ํŒจํ„ด ๊ธฐ๋ฐ˜์˜ ํ•œ๊ณ„

์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ๋Š” ์ฃผ๋กœ URL ํŒจํ„ด์— ๋”ฐ๋ผ ํ•„ํ„ฐ๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, /admin/*์™€ ๊ฐ™์€ URL ํŒจํ„ด์— ๋”ฐ๋ผ ๋ชจ๋“  ์š”์ฒญ์— ๋Œ€ํ•ด ํ•„ํ„ฐ๋ฅผ ์ ์šฉํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด ๋ฐฉ์‹์€ URL ์™ธ์˜ ์กฐ๊ฑด์„ ์„ค์ •ํ•  ์ˆ˜ ์—†์–ด ๋ณด์•ˆ ์ ์šฉ ๋ฐฉ์‹์ด ์ œํ•œ์ ์ž…๋‹ˆ๋‹ค.


๐Ÿ”— FilterChainProxy์™€ RequestMatcher์˜ ์—ญํ• 

FilterChainProxy๋Š” Spring Security์˜ ๋‹ค์–‘ํ•œ ๋ณด์•ˆ ํ•„ํ„ฐ๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ , RequestMatcher ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ํ†ตํ•ด ์š”์ฒญ์˜ ์กฐ๊ฑด์— ๋”ฐ๋ผ ํ•„ํ„ฐ๋ฅผ ์œ ์—ฐํ•˜๊ฒŒ ์ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. RequestMatcher๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด, URL ์™ธ์—๋„ ํ—ค๋”, HTTP ๋ฉ”์„œ๋“œ, ํŒŒ๋ผ๋ฏธํ„ฐ ๋“ฑ์˜ ์กฐ๊ฑด์„ ๋ฐ”ํƒ•์œผ๋กœ ๋ณด์•ˆ ํ•„ํ„ฐ๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


RequestMatcher๋ฅผ ํ†ตํ•œ ์œ ์—ฐํ•œ ์กฐ๊ฑด ์„ค์ • ์˜ˆ์‹œ

1๏ธโƒฃ ํŠน์ • ํ—ค๋” ๊ธฐ๋ฐ˜ ์กฐ๊ฑด ์„ค์ •

์˜ˆ๋ฅผ ๋“ค์–ด, ๋ณด์•ˆ ํ—ค๋”๊ฐ€ ํฌํ•จ๋œ ์š”์ฒญ๋งŒ ํ•„ํ„ฐ๋ฅผ ์ ์šฉํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด RequestMatcher๋กœ ํŠน์ • ํ—ค๋” ์กฐ๊ฑด์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜๋Š” X-Security-Header ํ—ค๋”๊ฐ€ ์žˆ๋Š” ์š”์ฒญ๋งŒ ํ•„ํ„ฐ๋ฅผ ์ ์šฉํ•˜๋Š” ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค:

RequestMatcher headerMatcher = request -> 
        "true".equals(request.getHeader("X-Security-Header"));

http
    .securityMatcher(headerMatcher)
    .authorizeRequests()
    .anyRequest().authenticated();

์ด ์„ค์ •์œผ๋กœ X-Security-Header ํ—ค๋”๊ฐ€ ํฌํ•จ๋œ ์š”์ฒญ๋งŒ ํ•„ํ„ฐ ์ฒด์ธ์„ ๊ฑฐ์น˜๋ฉฐ, ํ—ค๋”๊ฐ€ ์—†๋Š” ์š”์ฒญ์€ ์ ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

2๏ธโƒฃ HTTP ๋ฉ”์„œ๋“œ์— ๋”ฐ๋ฅธ ํ•„ํ„ฐ ์ ์šฉ

RequestMatcher๋Š” HTTP ๋ฉ”์„œ๋“œ์— ๋”ฐ๋ฅธ ํ•„ํ„ฐ ์ ์šฉ๋„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, GET ์š”์ฒญ์€ ์ธ์ฆ์„ ์š”๊ตฌํ•˜์ง€ ์•Š๊ณ  POST ์š”์ฒญ์—๋Š” ์ธ์ฆ์„ ์š”๊ตฌํ•˜๋Š” ๊ฒฝ์šฐ:

RequestMatcher postMatcher = request -> 
        "POST".equals(request.getMethod());

http
    .securityMatcher(postMatcher)
    .authorizeRequests()
    .anyRequest().authenticated();

์ด ์„ค์ •์œผ๋กœ POST ์š”์ฒญ๋งŒ ์ธ์ฆ์ด ํ•„์š”ํ•œ ํ•„ํ„ฐ๋ฅผ ๊ฑฐ์น˜๊ณ , GET ์š”์ฒญ์€ ์ ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

3๏ธโƒฃ ํŒŒ๋ผ๋ฏธํ„ฐ ๊ธฐ๋ฐ˜ ์กฐ๊ฑด ์„ค์ •

RequestMatcher๋Š” ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์กฐ๊ฑด์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, secure=true ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ํฌํ•จ๋œ ์š”์ฒญ์—๋งŒ ํ•„ํ„ฐ๋ฅผ ์ ์šฉํ•˜๋ ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

RequestMatcher parameterMatcher = request -> 
        "true".equals(request.getParameter("secure"));

http
    .securityMatcher(parameterMatcher)
    .authorizeRequests()
    .anyRequest().authenticated();

์ด ์„ค์ •์œผ๋กœ ?secure=true ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ํฌํ•จ๋œ ์š”์ฒญ๋งŒ ํ•„ํ„ฐ๋ฅผ ๊ฑฐ์น˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.


๐ŸŽฏ FilterChainProxy๋ฅผ ํ†ตํ•œ ์œ ์—ฐ์„ฑ์˜ ์žฅ์ 

์ด์™€ ๊ฐ™์€ ์กฐ๊ฑด ์„ค์ •์„ ํ†ตํ•ด FilterChainProxy๋Š” ๋‹จ์ˆœํ•œ URL ํŒจํ„ด์„ ๋„˜์–ด HttpServletRequest์˜ ๋‹ค์–‘ํ•œ ์กฐ๊ฑด์— ๋”ฐ๋ฅธ ๋ณด์•ˆ ํ•„ํ„ฐ๋ง์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

  • ๋งž์ถคํ˜• ๋ณด์•ˆ ์„ค์ •: ์š”์ฒญ์˜ ์ค‘์š”๋„๋‚˜ ์กฐ๊ฑด์— ๋”ฐ๋ผ ์„ธ๋ถ„ํ™”๋œ ๋ณด์•ˆ ์„ค์ •์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ํšจ์œจ์  ํ•„ํ„ฐ๋ง: ํŠน์ • ์กฐ๊ฑด์—๋งŒ ํ•„ํ„ฐ๋ฅผ ์ ์šฉํ•จ์œผ๋กœ์จ ๋ถˆํ•„์š”ํ•œ ํ•„ํ„ฐ ์‹คํ–‰์„ ์ค„์ด๊ณ  ์„ฑ๋Šฅ์„ ํ–ฅ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์ •๋ฐ€ํ•œ ๋ณด์•ˆ ์ •์ฑ…: ๋‹ค์–‘ํ•œ ์กฐ๊ฑด์„ ๋ฐ”ํƒ•์œผ๋กœ ๋ณด์•ˆ ํ•„ํ„ฐ๋ฅผ ์„ธ๋ฐ€ํ•˜๊ฒŒ ๊ด€๋ฆฌํ•˜์—ฌ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋ณด์•ˆ ์ •์ฑ…์„ ๋”์šฑ ๊ฐ•ํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ค์ค‘ SecurityFilterChain ๊ทธ๋ฆผ์—์„œ, FilterChainProxy๋Š” ์–ด๋–ค SecurityFilterChain์„ ์‚ฌ์šฉํ• ์ง€ ๊ฒฐ์ •ํ•ฉ๋‹ˆ๋‹ค. ์ผ์น˜ํ•˜๋Š” ์ฒซ ๋ฒˆ์งธ SecurityFilterChain๋งŒ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, /api/messages/ URL ์š”์ฒญ์ด ๋“ค์–ด์˜ค๋ฉด, /api/** ํŒจํ„ด๊ณผ ์ผ์น˜ํ•˜๋Š” SecurityFilterChain0์ด ๊ฐ€์žฅ ๋จผ์ € ๋งค์นญ๋˜๋ฏ€๋กœ SecurityFilterChain0๋งŒ ํ˜ธ์ถœ๋˜๊ณ , SecurityFilterChainn๊ณผ๋„ ์ผ์น˜ํ•˜๋”๋ผ๋„ ํ˜ธ์ถœ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋ฐ˜๋ฉด, /messages/ URL ์š”์ฒญ์ด ๋“ค์–ด์˜ค๋ฉด SecurityFilterChain0์˜ /api/** ํŒจํ„ด๊ณผ ์ผ์น˜ํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ, FilterChainProxy๋Š” ๊ณ„์†ํ•ด์„œ ๋‹ค๋ฅธ SecurityFilterChain์„ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. ๋งŒ์•ฝ ๋‹ค๋ฅธ SecurityFilterChain์ด ์ผ์น˜ํ•˜์ง€ ์•Š์œผ๋ฉด, ์ตœ์ข…์ ์œผ๋กœ SecurityFilterChainn์ด ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.

SecurityFilterChain0์—๋Š” ๋ณด์•ˆ ํ•„ํ„ฐ ์ธ์Šคํ„ด์Šค๊ฐ€ 3๊ฐœ๋งŒ ์„ค์ •๋œ ๋ฐ˜๋ฉด, SecurityFilterChainn์—๋Š” 4๊ฐœ์˜ ๋ณด์•ˆ ํ•„ํ„ฐ ์ธ์Šคํ„ด์Šค๊ฐ€ ์„ค์ •๋œ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฐ SecurityFilterChain์€ ๊ณ ์œ ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ๋…๋ฆฝ์ ์œผ๋กœ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ํŠน์ • ์š”์ฒญ์„ Spring Security๊ฐ€ ๋ฌด์‹œํ•˜๋„๋ก ์„ค์ •ํ•˜๋ ค๋Š” ๊ฒฝ์šฐ, SecurityFilterChain์— ๋ณด์•ˆ ํ•„ํ„ฐ ์ธ์Šคํ„ด์Šค๊ฐ€ ์—†์„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.


๐Ÿ“ ์š”์•ฝ

FilterChainProxy์™€ RequestMatcher๋Š” ์š”์ฒญ URL ์™ธ์—๋„ ํ—ค๋”, HTTP ๋ฉ”์„œ๋“œ, ํŒŒ๋ผ๋ฏธํ„ฐ ๋“ฑ์˜ ์กฐ๊ฑด์„ ํ™œ์šฉํ•˜์—ฌ Spring Security์˜ ๋ณด์•ˆ ํ•„ํ„ฐ๋ฅผ ์œ ์—ฐํ•˜๊ฒŒ ์ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์˜ ๋‹จ์ˆœ URL ํŒจํ„ด ๊ธฐ๋ฐ˜ ํ˜ธ์ถœ์„ ๋„˜์–ด ๋”์šฑ ์„ธ๋ฐ€ํ•˜๊ณ  ๋งž์ถคํ˜• ๋ณด์•ˆ ์„ค์ •์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๐ŸŒ๐Ÿ’ช


๐Ÿ”’ Spring Security ๋ณด์•ˆ ํ•„ํ„ฐ: SecurityFilterChain์„ ํ†ตํ•œ FilterChainProxy ๋‚ด ํ•„ํ„ฐ ์ˆœ์„œ ๊ด€๋ฆฌ

Spring Security์—์„œ ๋ณด์•ˆ ํ•„ํ„ฐ๋Š” SecurityFilterChain API๋ฅผ ํ†ตํ•ด FilterChainProxy์— ์‚ฝ์ž…๋˜์–ด, ์ธ์ฆ, ๊ถŒํ•œ ๋ถ€์—ฌ, ๊ณต๊ฒฉ ๋ฐฉ์ง€ ๋“ฑ์˜ ๋‹ค์–‘ํ•œ ๋ชฉ์ ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ํ•„ํ„ฐ๋Š” ํŠน์ • ์ˆœ์„œ์— ๋”ฐ๋ผ ์‹คํ–‰๋˜๋ฉฐ, ๊ฐ ํ•„ํ„ฐ๊ฐ€ ์˜ฌ๋ฐ”๋ฅธ ์‹œ์ ์— ํ˜ธ์ถœ๋˜๋„๋ก ๋ณด์žฅ๋ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์ธ์ฆ ํ•„ํ„ฐ๋Š” ๊ถŒํ•œ ๋ถ€์—ฌ ํ•„ํ„ฐ๋ณด๋‹ค ๋จผ์ € ํ˜ธ์ถœ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.


๐Ÿ› ๏ธ ํ•„ํ„ฐ ์ˆœ์„œ ์˜ˆ์‹œ: ๊ธฐ๋ณธ ๋ณด์•ˆ ๊ตฌ์„ฑ

Spring Security์—์„œ ์ž์ฃผ ์‚ฌ์šฉ๋˜๋Š” ๋ณด์•ˆ ํ•„ํ„ฐ๋“ค์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ˆœ์„œ๋กœ ๋ฐฐ์น˜๋˜์–ด ํŠน์ • ๋ชฉ์ ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

ํ•„ํ„ฐ์ถ”๊ฐ€๋œ ์œ„์น˜
CsrfFilterHttpSecurity#csrf
UsernamePasswordAuthenticationFilterHttpSecurity#formLogin
BasicAuthenticationFilterHttpSecurity#httpBasic
AuthorizationFilterHttpSecurity#authorizeHttpRequests

๐Ÿ”— ํ•„ํ„ฐ ์ˆœ์„œ ์„ค๋ช…

1๏ธโƒฃ CsrfFilter

  • ๊ฐ€์žฅ ๋จผ์ € ํ˜ธ์ถœ๋˜๋ฉฐ, CSRF ๊ณต๊ฒฉ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•œ ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋“  ์ธ์ฆ ๋ฐ ๊ถŒํ•œ ๋ถ€์—ฌ ํ•„ํ„ฐ๋ณด๋‹ค ์šฐ์„ ์ ์œผ๋กœ ์‹คํ–‰๋˜์–ด, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด CSRF๋กœ๋ถ€ํ„ฐ ์•ˆ์ „ํ•˜๊ฒŒ ๋ณดํ˜ธ๋˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

2๏ธโƒฃ ์ธ์ฆ ํ•„ํ„ฐ (UsernamePasswordAuthenticationFilter ๋ฐ BasicAuthenticationFilter)

  • UsernamePasswordAuthenticationFilter๋Š” ํผ ๊ธฐ๋ฐ˜ ๋กœ๊ทธ์ธ ์ธ์ฆ์„ ์ˆ˜ํ–‰ํ•˜๋ฉฐ, HttpSecurity#formLogin ์œ„์น˜์—์„œ ์„ค์ •๋ฉ๋‹ˆ๋‹ค.
  • BasicAuthenticationFilter๋Š” HTTP ๊ธฐ๋ณธ ์ธ์ฆ์„ ๋‹ด๋‹นํ•˜๋ฉฐ, HttpSecurity#httpBasic ์œ„์น˜์—์„œ ์„ค์ •๋ฉ๋‹ˆ๋‹ค.
  • ์ด๋“ค ์ธ์ฆ ํ•„ํ„ฐ๋Š” ์‚ฌ์šฉ์ž์˜ ์ธ์ฆ ์ƒํƒœ๋ฅผ ํ™•์ธํ•˜๊ณ , ํ•„์š”ํ•œ ๊ฒฝ์šฐ ๋กœ๊ทธ์ธ ์ฒ˜๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

3๏ธโƒฃ AuthorizationFilter

  • ๋งˆ์ง€๋ง‰์œผ๋กœ ํ˜ธ์ถœ๋˜์–ด, ์š”์ฒญ์— ๋Œ€ํ•ด ์ ‘๊ทผ ๊ถŒํ•œ์„ ๋ถ€์—ฌํ•˜๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค. ์ธ์ฆ์ด ์„ฑ๊ณตํ•œ ์‚ฌ์šฉ์ž๊ฐ€ ํŠน์ • ์ž์›์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ” ํ•„ํ„ฐ ์ˆœ์„œ ํ™•์ธ ๋ฐ ๊ด€๋ฆฌ ๋ฐฉ๋ฒ•

  • ํ•„ํ„ฐ ์ˆœ์„œ ํ™•์ธ
    ์ผ๋ฐ˜์ ์œผ๋กœ Spring Security๋Š” ํ•„ํ„ฐ ์ˆœ์„œ๋ฅผ ์ž๋™์œผ๋กœ ๊ด€๋ฆฌํ•˜๋ฏ€๋กœ ์ˆœ์„œ๋ฅผ ๋ช…ํ™•ํžˆ ์•Œ ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ํ•„์š”ํ•œ ๊ฒฝ์šฐ, FilterOrderRegistration ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด ๊ฐ ํ•„ํ„ฐ์˜ ์ˆœ์„œ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์ถ”๊ฐ€์ ์ธ ํ•„ํ„ฐ ํ™•์ธ
    ๋ณด์•ˆ ๊ตฌ์„ฑ ์™ธ์—๋„ ์ถ”๊ฐ€์ ์œผ๋กœ ์‚ฌ์šฉ์ž ์ •์˜ ํ•„ํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ํŠน์ • ์š”์ฒญ์— ๋Œ€ํ•ด ํ˜ธ์ถœ๋œ ํ•„ํ„ฐ ๋ชฉ๋ก์„ ์ถœ๋ ฅํ•˜์—ฌ ์‹ค์ œ ํ•„ํ„ฐ ์‹คํ–‰ ์ˆœ์„œ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


๐Ÿ“ ์š”์•ฝ

  • SecurityFilterChain์„ ํ†ตํ•ด ๋ณด์•ˆ ํ•„ํ„ฐ๋“ค์€ ํŠน์ • ์ˆœ์„œ๋กœ FilterChainProxy์— ์‚ฝ์ž…๋˜๋ฉฐ, ๊ฐ ํ•„ํ„ฐ๋Š” ์š”์ฒญ์˜ ์•ˆ์ „์„ฑ์„ ๋ณด์žฅํ•˜๊ธฐ ์œ„ํ•ด ์ •ํ™•ํ•œ ์‹œ์ ์— ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.
  • ๊ธฐ๋ณธ ํ•„ํ„ฐ ์ˆœ์„œ๋Š” CsrfFilter, ์ธ์ฆ ํ•„ํ„ฐ, ๊ทธ๋ฆฌ๊ณ  AuthorizationFilter ์ˆœ์œผ๋กœ ๊ตฌ์„ฑ๋ฉ๋‹ˆ๋‹ค.
  • ํ•„ํ„ฐ ์ˆœ์„œ ํ™•์ธ ๋ฐ ๊ด€๋ฆฌ๋Š” FilterOrderRegistration ์ฝ”๋“œ์—์„œ ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์ปค์Šคํ…€ ํ•„ํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ๋ณด์•ˆ ์š”๊ตฌ ์‚ฌํ•ญ์— ๋งž๊ฒŒ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Spring Security์˜ ๋ณด์•ˆ ํ•„ํ„ฐ ์ฒด์ธ์€ ์ด์ฒ˜๋Ÿผ ์ˆœ์„œ์— ๋งž์ถฐ ํ•„ํ„ฐ๋“ค์ด ์‹คํ–‰๋˜๋ฉฐ, ๊ฐ๊ฐ์˜ ํ•„ํ„ฐ๊ฐ€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋ณด์•ˆ์„ ๋‹ค๊ฐ๋„๋กœ ๊ฐ•ํ™”ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋•์Šต๋‹ˆ๋‹ค. ๐Ÿ›ก๏ธโœจ

@Configuration
@EnableWebSecurity
public class SecurityConfig {

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

}

๐Ÿ” Spring Security์—์„œ ๋ณด์•ˆ ํ•„ํ„ฐ ์ถœ๋ ฅ: ํŠน์ • ์š”์ฒญ์— ํ˜ธ์ถœ๋˜๋Š” ๋ณด์•ˆ ํ•„ํ„ฐ ๋ชฉ๋ก ํ™•์ธํ•˜๊ธฐ

ํŠน์ • ์š”์ฒญ์— ๋Œ€ํ•ด ์–ด๋–ค ๋ณด์•ˆ ํ•„ํ„ฐ๊ฐ€ ํ˜ธ์ถœ๋˜๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๊ฒƒ์€ ์œ ์šฉํ•  ๋•Œ๊ฐ€ ๋งŽ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์ถ”๊ฐ€ํ•œ ์ปค์Šคํ…€ ํ•„ํ„ฐ๊ฐ€ ํ•„ํ„ฐ ์ฒด์ธ์— ํฌํ•จ๋˜์–ด ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๊ฑฐ๋‚˜, ๊ฐ ํ•„ํ„ฐ์˜ ์‹คํ–‰ ์ˆœ์„œ๋ฅผ ๋””๋ฒ„๊น…ํ•˜๋Š” ๋ฐ ๋„์›€์„ ์ค๋‹ˆ๋‹ค.


๐Ÿ“‹ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹œ์ž‘ ์‹œ ๋ณด์•ˆ ํ•„ํ„ฐ ๋ชฉ๋ก ์ถœ๋ ฅ

  • Spring Security๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹œ์ž‘ ์‹œ INFO ๋ ˆ๋ฒจ์—์„œ ๊ฐ ํ•„ํ„ฐ ์ฒด์ธ์— ํฌํ•จ๋œ ํ•„ํ„ฐ ๋ชฉ๋ก์„ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค.
  • ์ด๋ฅผ ํ†ตํ•ด ๊ฐ ์š”์ฒญ์— ๋Œ€ํ•ด SecurityFilterChain์— ๋“ฑ๋ก๋œ ๋ณด์•ˆ ํ•„ํ„ฐ ๋ชฉ๋ก์„ ๋ฏธ๋ฆฌ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์ฝ˜์†” ๋กœ๊ทธ์—์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํ•„ํ„ฐ ์ฒด์ธ ๋ชฉ๋ก์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
INFO - Security filter chain: 
 - SecurityContextPersistenceFilter
 - UsernamePasswordAuthenticationFilter
 - BasicAuthenticationFilter
 - CsrfFilter
 - AuthorizationFilter
...

์ด ๋ชฉ๋ก์„ ํ†ตํ•ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์ดˆ๊ธฐํ™”๋  ๋•Œ ์–ด๋–ค ํ•„ํ„ฐ๋“ค์ด ํ™œ์„ฑํ™”๋˜๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


๐Ÿ› ๏ธ ํŠน์ • ์š”์ฒญ์— ๋Œ€ํ•œ ํ•„ํ„ฐ ํ˜ธ์ถœ ๋กœ๊ทธ ์„ค์ •

  • ํŠน์ • ์š”์ฒญ์— ๋Œ€ํ•ด ๊ฐœ๋ณ„ ํ•„ํ„ฐ ํ˜ธ์ถœ ๋‚ด์šฉ์„ ์ถœ๋ ฅํ•˜๋ ค๋ฉด ๋ณด์•ˆ ์ด๋ฒคํŠธ๋ฅผ ๋กœ๊ทธ๋กœ ๊ธฐ๋กํ•˜๋„๋ก ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • Spring Security๋Š” ๊ฐ ๋ณด์•ˆ ํ•„ํ„ฐ๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ๋งˆ๋‹ค ๋กœ๊ทธ๋ฅผ ๋‚จ๊ธธ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๋กœ๊ทธ ๋ ˆ๋ฒจ์„ ์กฐ์ •ํ•˜์—ฌ ํ•„ํ„ฐ ํ˜ธ์ถœ ์‹œ์ ์ด๋‚˜ ์˜ˆ์™ธ ๋ฐœ์ƒ ์œ„์น˜๋ฅผ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฐฉ๋ฒ•: ๋กœ๊น… ์„ค์ • ํŒŒ์ผ์—์„œ ๋กœ๊ทธ ๋ ˆ๋ฒจ ์กฐ์ •

Spring Boot์˜ application.properties ๋˜๋Š” application.yml ํŒŒ์ผ์—์„œ Spring Security์˜ ๋กœ๊น… ๋ ˆ๋ฒจ์„ DEBUG๋กœ ์„ค์ •ํ•˜์—ฌ, ๊ฐ ํ•„ํ„ฐ ํ˜ธ์ถœ ์ด๋ฒคํŠธ๋ฅผ ๊ธฐ๋กํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

logging.level.org.springframework.security.web.FilterChainProxy=DEBUG
logging.level.org.springframework.security=DEBUG

์ด ์„ค์ •์„ ํ†ตํ•ด, ์š”์ฒญ์ด ๋“ค์–ด์˜ฌ ๋•Œ๋งˆ๋‹ค Spring Security์˜ ๊ฐ ํ•„ํ„ฐ ํ˜ธ์ถœ์ด ๋กœ๊ทธ์— ๊ธฐ๋ก๋ฉ๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ํŠน์ • ์š”์ฒญ์— ๋Œ€ํ•ด ์–ด๋–ค ํ•„ํ„ฐ๊ฐ€ ์‹คํ–‰๋˜๋Š”์ง€, ์ถ”๊ฐ€ํ•œ ํ•„ํ„ฐ๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ํ˜ธ์ถœ๋˜๋Š”์ง€, ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ์œ„์น˜๋Š” ์–ด๋””์ธ์ง€ ๋“ฑ์˜ ์ •๋ณด๋ฅผ ๋””๋ฒ„๊น…ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


๐Ÿ“ ์š”์•ฝ

  • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹œ์ž‘ ์‹œ ํ•„ํ„ฐ ๋ชฉ๋ก ์ถœ๋ ฅ: Spring Security๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹œ์ž‘ ์‹œ ๊ฐ SecurityFilterChain์˜ ํ•„ํ„ฐ ๋ชฉ๋ก์„ INFO ๋ ˆ๋ฒจ ๋กœ๊ทธ๋กœ ์ถœ๋ ฅํ•˜์—ฌ, ํ•„ํ„ฐ ๊ตฌ์„ฑ์„ ๋ฏธ๋ฆฌ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์š”์ฒญ ์‹œ ํ•„ํ„ฐ ํ˜ธ์ถœ ๋กœ๊ทธ ์„ค์ •: DEBUG ๋ ˆ๋ฒจ๋กœ ๋กœ๊น…์„ ์„ค์ •ํ•˜์—ฌ, ํŠน์ • ์š”์ฒญ์— ๋Œ€ํ•ด ๊ฐœ๋ณ„ ํ•„ํ„ฐ ํ˜ธ์ถœ ๋‚ด์šฉ๊ณผ ์‹คํ–‰ ์ˆœ์„œ๋ฅผ ๊ธฐ๋กํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด์™€ ๊ฐ™์€ ์„ค์ •์„ ํ†ตํ•ด ๋ณด์•ˆ ํ•„ํ„ฐ ์ฒด์ธ์— ๋Œ€ํ•œ ์ƒ์„ธ ์ •๋ณด๋ฅผ ํ™•์ธํ•˜๊ณ , Spring Security์˜ ํ•„ํ„ฐ ์ฒด์ธ ์ž‘๋™ ๋ฐฉ์‹์„ ํšจ๊ณผ์ ์œผ๋กœ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๐Ÿ›ก๏ธโœจ


๐Ÿ› ๏ธ Spring Security ํ•„ํ„ฐ ์ฒด์ธ์— ์ปค์Šคํ…€ ํ•„ํ„ฐ ์ถ”๊ฐ€: ์ธ์ฆ ํ•„ํ„ฐ ์ดํ›„์˜ ์œ„์น˜ ์„ค์ •

๊ธฐ๋ณธ ๋ณด์•ˆ ํ•„ํ„ฐ๋“ค์ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์ถฉ๋ถ„ํ•œ ๋ณด์•ˆ์„ ์ œ๊ณตํ•˜์ง€๋งŒ, ํŠน์ • ์ƒํ™ฉ์—์„œ ์ปค์Šคํ…€ ํ•„ํ„ฐ๊ฐ€ ํ•„์š”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ํ…Œ๋„ŒํŠธ ID(tenant id) ํ—ค๋”๋ฅผ ํ†ตํ•ด ํ˜„์žฌ ์‚ฌ์šฉ์ž๊ฐ€ ํ•ด๋‹น ํ…Œ๋„ŒํŠธ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ๊ถŒํ•œ์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๋Š” ํ•„ํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ ค๋ฉด ์ธ์ฆ ํ•„ํ„ฐ ์ดํ›„์— ์ปค์Šคํ…€ ํ•„ํ„ฐ๋ฅผ ๋ฐฐ์น˜ํ•˜๋Š” ๊ฒƒ์ด ์ ์ ˆํ•ฉ๋‹ˆ๋‹ค.


๐Ÿ”‘ ์ปค์Šคํ…€ ํ•„ํ„ฐ์˜ ๋ฐฐ์น˜ ์œ„์น˜๊ฐ€ ์ค‘์š”ํ•œ ์ด์œ 

1๏ธโƒฃ ์ธ์ฆ ์ •๋ณด์˜ ํ•„์š”์„ฑ

  • ์ปค์Šคํ…€ ํ•„ํ„ฐ๊ฐ€ tenant id ํ—ค๋”์™€ ํ˜„์žฌ ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ํ™œ์šฉํ•˜์—ฌ ํ…Œ๋„ŒํŠธ ์ ‘๊ทผ ๊ถŒํ•œ์„ ๊ฒ€์‚ฌํ•˜๋ ค๋ฉด, ์ธ์ฆ๋œ ์‚ฌ์šฉ์ž ์ •๋ณด๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.
  • ์ด ์ •๋ณด๋Š” ์ธ์ฆ ํ•„ํ„ฐ(์˜ˆ: UsernamePasswordAuthenticationFilter ๋˜๋Š” BasicAuthenticationFilter)๊ฐ€ ์‹คํ–‰๋œ ํ›„์—๋งŒ SecurityContext์— ์ €์žฅ๋ฉ๋‹ˆ๋‹ค.

2๏ธโƒฃ ์ธ์ฆ ํ•„ํ„ฐ์˜ ์—ญํ• 

  • Spring Security์˜ ์ธ์ฆ ํ•„ํ„ฐ๋Š” ์‚ฌ์šฉ์ž ์ž๊ฒฉ ์ฆ๋ช…์„ ํ™•์ธํ•˜๊ณ , ์ธ์ฆ์ด ์„ฑ๊ณตํ•˜๋ฉด ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ SecurityContext์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.
  • ์ธ์ฆ ํ•„ํ„ฐ๊ฐ€ ๋จผ์ € ์‹คํ–‰๋˜์–ด์•ผ SecurityContext์—์„œ ํ˜„์žฌ ์‚ฌ์šฉ์ž์˜ ์ •๋ณด๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

3๏ธโƒฃ ์ปค์Šคํ…€ ํ•„ํ„ฐ์˜ ์‹คํ–‰ ์œ„์น˜

  • ์ธ์ฆ ํ•„ํ„ฐ ์ด์ „์— ์ปค์Šคํ…€ ํ•„ํ„ฐ๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉด ์•„์ง SecurityContext์— ์‚ฌ์šฉ์ž ์ •๋ณด๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— ํ•„์š”ํ•œ ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ์ฐธ์กฐํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
  • ๋”ฐ๋ผ์„œ ์ปค์Šคํ…€ ํ•„ํ„ฐ๊ฐ€ ์ธ์ฆ๋œ ์‚ฌ์šฉ์ž ์ •๋ณด์— ์˜์กดํ•˜๋Š” ๊ฒฝ์šฐ, ์ธ์ฆ ํ•„ํ„ฐ ์ดํ›„์— ๋ฐฐ์น˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“‹ ์ปค์Šคํ…€ ํ•„ํ„ฐ ์ถ”๊ฐ€ ์˜ˆ์‹œ: ์ธ์ฆ ํ•„ํ„ฐ ์ดํ›„์˜ ์œ„์น˜ ์„ค์ •

์•„๋ž˜๋Š” tenant id ํ—ค๋”์™€ ์‚ฌ์šฉ์ž ์ •๋ณด๋กœ ํ…Œ๋„ŒํŠธ ์ ‘๊ทผ ๊ถŒํ•œ์„ ๊ฒ€์‚ฌํ•˜๋Š” ์ปค์Šคํ…€ ํ•„ํ„ฐ๋ฅผ ์ธ์ฆ ํ•„ํ„ฐ ์ดํ›„์— ์ถ”๊ฐ€ํ•˜๋Š” ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค:

import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.stereotype.Component;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class TenantIdFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        
        String tenantId = request.getHeader("tenant id");
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        
        if (auth != null && tenantId != null) {
            // ํ…Œ๋„ŒํŠธ ์ ‘๊ทผ ๊ถŒํ•œ ๊ฒ€์‚ฌ๋ฅผ ์ˆ˜ํ–‰
            // ์˜ˆ: ํ˜„์žฌ ์‚ฌ์šฉ์ž ์ •๋ณด์™€ tenantId๋ฅผ ์ด์šฉํ•˜์—ฌ ์ ‘๊ทผ ๊ถŒํ•œ ํ™•์ธ ๋กœ์ง ์ถ”๊ฐ€
        }
        
        filterChain.doFilter(request, response); // ๋‹ค์Œ ํ•„ํ„ฐ๋กœ ์ „๋‹ฌ
    }
}

๐Ÿ“Œ ์ปค์Šคํ…€ ํ•„ํ„ฐ ์„ค์ • ๋ฐ ๋ฐฐ์น˜

์œ„์—์„œ ์ž‘์„ฑํ•œ TenantIdFilter๋ฅผ Spring Security์˜ ํ•„ํ„ฐ ์ฒด์ธ์— ์ถ”๊ฐ€ํ•˜๊ณ , ์ธ์ฆ ํ•„ํ„ฐ ์ดํ›„์— ๋ฐฐ์น˜ํ•ฉ๋‹ˆ๋‹ค.

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.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private final TenantIdFilter tenantIdFilter;

    public SecurityConfig(TenantIdFilter tenantIdFilter) {
        this.tenantIdFilter = tenantIdFilter;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .addFilterAfter(tenantIdFilter, UsernamePasswordAuthenticationFilter.class) // ์ธ์ฆ ํ•„ํ„ฐ ํ›„์— ์ปค์Šคํ…€ ํ•„ํ„ฐ ์ถ”๊ฐ€
            .authorizeRequests()
            .anyRequest().authenticated();
    }
}

์œ„ ์ฝ”๋“œ์—์„œ TenantIdFilter๋Š” UsernamePasswordAuthenticationFilter ์ดํ›„์— ์‹คํ–‰๋˜๋ฏ€๋กœ, SecurityContext์—์„œ ์•ˆ์ „ํ•˜๊ฒŒ ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


๐Ÿ”„ ํ๋ฆ„ ์˜ˆ์‹œ

  1. ์ธ์ฆ ํ•„ํ„ฐ ์‹คํ–‰

    • ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์ธํ•˜๋ฉด ์ธ์ฆ ํ•„ํ„ฐ๊ฐ€ ์ž๊ฒฉ ์ฆ๋ช…์„ ํ™•์ธํ•˜๊ณ  SecurityContext์— ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.
  2. ์ปค์Šคํ…€ ํ•„ํ„ฐ ์‹คํ–‰

    • TenantIdFilter๊ฐ€ SecurityContext์—์„œ ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์™€ tenant id ํ—ค๋”์™€ ํ•จ๊ป˜ ์ ‘๊ทผ ๊ถŒํ•œ์„ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
  3. ๊ถŒํ•œ ๋ถ€์—ฌ ํ•„ํ„ฐ ์‹คํ–‰

    • ๋งˆ์ง€๋ง‰์œผ๋กœ ๊ถŒํ•œ ๋ถ€์—ฌ ํ•„ํ„ฐ๊ฐ€ ์‹คํ–‰๋˜์–ด, ์‚ฌ์šฉ์ž๊ฐ€ ์ž์›์— ์ ‘๊ทผํ•  ๊ถŒํ•œ์ด ์žˆ๋Š”์ง€ ์ตœ์ข… ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“ ์š”์•ฝ

  • ์ปค์Šคํ…€ ํ•„ํ„ฐ๊ฐ€ ์ธ์ฆ๋œ ์‚ฌ์šฉ์ž ์ •๋ณด์— ์˜์กดํ•œ๋‹ค๋ฉด, ์ธ์ฆ ํ•„ํ„ฐ ์ดํ›„์— ์ถ”๊ฐ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • TenantIdFilter์™€ ๊ฐ™์ด ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ํ•„์š”๋กœ ํ•˜๋Š” ์ปค์Šคํ…€ ํ•„ํ„ฐ๋Š” ์ธ์ฆ ํ•„ํ„ฐ ์ดํ›„์— ๋ฐฐ์น˜๋˜์–ด SecurityContext์˜ ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • Spring Security ์„ค์ •์—์„œ addFilterAfter๋ฅผ ํ†ตํ•ด ํ•„ํ„ฐ ์ˆœ์„œ๋ฅผ ์กฐ์ •ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ด๋ฅผ ํ†ตํ•ด ์ •ํ™•ํ•œ ์ˆœ์„œ๋กœ ํ•„ํ„ฐ๋“ค์ด ์‹คํ–‰๋˜๋„๋ก ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค. ๐Ÿ›ก๏ธ๐Ÿ’ผ

๐Ÿ› ๏ธ TenantFilter: ์š”์ฒญ ๋‹น ํ•œ ๋ฒˆ๋งŒ ํ˜ธ์ถœ๋˜๋Š” OncePerRequestFilter๋กœ ๋ณ€๊ฒฝ

์œ„ TenantFilter ์ƒ˜ํ”Œ ์ฝ”๋“œ์—์„œ๋Š” Filter ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜์—ฌ, tenant id ํ—ค๋” ๊ธฐ๋ฐ˜์œผ๋กœ ์‚ฌ์šฉ์ž์˜ ์ ‘๊ทผ ๊ถŒํ•œ์„ ํ™•์ธํ•˜๋Š” ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์š”์ฒญ๋งˆ๋‹ค ํ•„ํ„ฐ๊ฐ€ ์‹คํ–‰๋˜๋„๋ก ์„ค์ •๋˜์—ˆ์ง€๋งŒ, Spring Security์—์„œ OncePerRequestFilter๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์š”์ฒญ๋‹น ํ•œ ๋ฒˆ๋งŒ ์‹คํ–‰๋˜๋„๋ก ๋ณด์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

OncePerRequestFilter๋Š” Spring์—์„œ ์ œ๊ณตํ•˜๋Š” ํ•„ํ„ฐ์˜ ๊ธฐ๋ณธ ํด๋ž˜์Šค์ด๋ฉฐ, ๋™์ผํ•œ ์š”์ฒญ ๋‚ด์—์„œ ์ค‘๋ณต ํ˜ธ์ถœ์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค. OncePerRequestFilter๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์š”์ฒญ์ด ์—ฌ๋Ÿฌ ๋ฒˆ ํ•„ํ„ฐ ์ฒด์ธ์„ ๊ฑฐ์น˜๋”๋ผ๋„ ํ•„ํ„ฐ๊ฐ€ ํ•œ ๋ฒˆ๋งŒ ์‹คํ–‰๋˜๋„๋ก ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


โœ๏ธ OncePerRequestFilter๋กœ ๋ณ€ํ™˜๋œ TenantFilter ์˜ˆ์ œ

OncePerRequestFilter๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ์ค‘๋ณต ํ˜ธ์ถœ์„ ๋ฐฉ์ง€ํ•˜๊ณ , HttpServletRequest์™€ HttpServletResponse ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” doFilterInternal ๋ฉ”์„œ๋“œ๋ฅผ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class TenantFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) 
            throws ServletException, IOException {
        
        String tenantId = request.getHeader("X-Tenant-Id");  // ํ—ค๋”์—์„œ tenant id ๊ฐ€์ ธ์˜ค๊ธฐ
        
        // tenant id์— ๋Œ€ํ•œ ์ ‘๊ทผ ๊ถŒํ•œ ํ™•์ธ
        boolean hasAccess = isUserAllowed(tenantId); 
        
        if (hasAccess) {
            filterChain.doFilter(request, response); // ์ฒด์ธ์—์„œ ๋‚˜๋จธ์ง€ ํ•„ํ„ฐ ํ˜ธ์ถœ
        } else {
            throw new AccessDeniedException("Access denied"); // ์ ‘๊ทผ ๊ฑฐ๋ถ€ ์˜ˆ์™ธ ๋ฐœ์ƒ
        }
    }

    private boolean isUserAllowed(String tenantId) {
        // tenant id์— ๋Œ€ํ•œ ์ ‘๊ทผ ๊ถŒํ•œ์„ ํ™•์ธํ•˜๋Š” ๋กœ์ง์„ ์ถ”๊ฐ€ํ•˜์„ธ์š”.
        return tenantId != null && tenantId.equals("authorizedTenantId"); // ์˜ˆ์‹œ๋กœ "authorizedTenantId" ๋น„๊ต
    }
}

๐Ÿ”„ TenantFilter ๊ธฐ๋Šฅ ์„ค๋ช…

  1. OncePerRequestFilter ์ƒ์†
    OncePerRequestFilter๋ฅผ ์ƒ์†ํ•˜์—ฌ, ํ•„ํ„ฐ๊ฐ€ ๋™์ผํ•œ ์š”์ฒญ ๋‚ด์—์„œ ์ค‘๋ณต ํ˜ธ์ถœ๋˜์ง€ ์•Š๋„๋ก ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค.

  2. doFilterInternal ๋ฉ”์„œ๋“œ
    doFilterInternal ๋ฉ”์„œ๋“œ์—์„œ tenant id ํ—ค๋”๋ฅผ ๊ฐ€์ ธ์™€ isUserAllowed ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ์ ‘๊ทผ ๊ถŒํ•œ์„ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

  3. ์ ‘๊ทผ ๊ถŒํ•œ ํ™•์ธ ๋ฐ ์ฒ˜๋ฆฌ

    • isUserAllowed ๋ฉ”์„œ๋“œ๊ฐ€ true๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉด filterChain.doFilter๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์ฒด์ธ์˜ ๋‚˜๋จธ์ง€ ํ•„ํ„ฐ๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.
    • ๊ถŒํ•œ์ด ์—†๋Š” ๊ฒฝ์šฐ AccessDeniedException์„ ๋˜์ ธ ์š”์ฒญ์„ ์ฐจ๋‹จํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“ OncePerRequestFilter ์‚ฌ์šฉ์˜ ์žฅ์ 

  • ์ค‘๋ณต ํ˜ธ์ถœ ๋ฐฉ์ง€: ๋™์ผํ•œ ์š”์ฒญ์ด ์—ฌ๋Ÿฌ ๋ฒˆ ํ•„ํ„ฐ ์ฒด์ธ์„ ๊ฑฐ์น  ๋•Œ, ํ•„ํ„ฐ๊ฐ€ ํ•œ ๋ฒˆ๋งŒ ํ˜ธ์ถœ๋˜๋„๋ก ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์ง๊ด€์ ์ธ ์ฝ”๋“œ ๊ตฌ์„ฑ: HttpServletRequest์™€ HttpServletResponse๋ฅผ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๊ฐ€์ง€๋Š” doFilterInternal ๋ฉ”์„œ๋“œ๋ฅผ ์ œ๊ณตํ•˜์—ฌ Spring ํ™˜๊ฒฝ์—์„œ ํ•„ํ„ฐ ์„ค์ •์ด ์šฉ์ดํ•ฉ๋‹ˆ๋‹ค.

OncePerRequestFilter๋ฅผ ํ†ตํ•ด ํ•„ํ„ฐ๋ฅผ ๊ด€๋ฆฌํ•จ์œผ๋กœ์จ Spring Security์—์„œ ์ค‘๋ณต ํ˜ธ์ถœ ์—†์ด ์š”์ฒญ๋‹น ํ•œ ๋ฒˆ์˜ ํ•„ํ„ฐ๋ง์„ ๋ณด์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


๐Ÿ›ก๏ธ TenantFilter๋ฅผ ๋ณด์•ˆ ํ•„ํ„ฐ ์ฒด์ธ์— ์ถ”๊ฐ€: AuthorizationFilter ์•ž์— ๋ฐฐ์น˜

TenantFilter๋ฅผ AuthorizationFilter ์•ž์— ์ถ”๊ฐ€ํ•จ์œผ๋กœ์จ, Spring Security์˜ ์ธ์ฆ๋œ ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ์‚ฌ์šฉํ•ด ํ…Œ๋„ŒํŠธ ์ ‘๊ทผ ๊ถŒํ•œ์„ ๊ฒ€์‚ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์„ค์ •์€ HttpSecurity#addFilterBefore ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ์ด๋ฃจ์–ด์ง‘๋‹ˆ๋‹ค.

@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
        // ๋‹ค๋ฅธ ๋ณด์•ˆ ์„ค์ •
        .addFilterBefore(new TenantFilter(), AuthorizationFilter.class); 
    return http.build();
}

๐Ÿ”„ ๋ณด์•ˆ ํ•„ํ„ฐ ์ฒด์ธ์—์„œ์˜ ํ•„ํ„ฐ ์ˆœ์„œ

  1. ์ธ์ฆ(Authentication):

    • ์ธ์ฆ ํ•„ํ„ฐ๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ๋ˆ„๊ตฌ์ธ์ง€ ํ™•์ธํ•˜๋Š” ๊ณผ์ •์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, UsernamePasswordAuthenticationFilter๊ฐ€ ๋กœ๊ทธ์ธ ๊ณผ์ •์—์„œ ์‚ฌ์šฉ์ž์˜ ์‹ ์› ํ™•์ธ์„ ์ˆ˜ํ–‰ํ•˜๋ฉฐ, ์„ฑ๊ณต ์‹œ SecurityContext์— ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.
  2. TenantFilter ์ถ”๊ฐ€:

    • TenantFilter๋Š” AuthorizationFilter ์•ž์— ๋ฐฐ์น˜๋˜์–ด, ์ธ์ฆ๋œ ์‚ฌ์šฉ์ž์˜ ์ •๋ณด๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ…Œ๋„ŒํŠธ ์ ‘๊ทผ ๊ถŒํ•œ์„ ๊ฒ€์‚ฌํ•ฉ๋‹ˆ๋‹ค.
    • ์ด ํ•„ํ„ฐ๋Š” tenant id ํ—ค๋”์™€ SecurityContext์— ์ €์žฅ๋œ ์‚ฌ์šฉ์ž ์ •๋ณด๊ฐ€ ํ•„์š”ํ•˜๋ฏ€๋กœ, ์ธ์ฆ ํ•„ํ„ฐ๊ฐ€ ๋จผ์ € ์‹คํ–‰๋œ ํ›„ TenantFilter๊ฐ€ ์‹คํ–‰๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  3. ์ธ๊ฐ€(Authorization):

    • AuthorizationFilter๋Š” ์ตœ์ข…์ ์œผ๋กœ ์‚ฌ์šฉ์ž๊ฐ€ ํŠน์ • ์ž์›์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ๊ถŒํ•œ์ด ์žˆ๋Š”์ง€๋ฅผ ํ™•์ธํ•˜๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.
    • ์ด ๋‹จ๊ณ„์—์„œ๋Š” ์ด๋ฏธ ์‚ฌ์šฉ์ž ์‹ ์›์ด ์ธ์ฆ๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ, ๊ฐ ์ž์›์— ๋Œ€ํ•œ ์ ‘๊ทผ ๊ถŒํ•œ์ด ์ œ๋Œ€๋กœ ๋ถ€์—ฌ๋˜์—ˆ๋Š”์ง€ ๊ฒ€์‚ฌ๋ฅผ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“ ํ•„ํ„ฐ ๋ฐฐ์น˜์˜ ์ด์œ 

  • ์ธ์ฆ ํ›„ ์ ‘๊ทผ ๊ฒ€์‚ฌ๊ฐ€ ํ•„์š”ํ•  ๋•Œ: TenantFilter๊ฐ€ ์‚ฌ์šฉ์ž ์ธ์ฆ ์ •๋ณด์— ์˜์กดํ•˜๋ฏ€๋กœ, ์ธ์ฆ ํ•„ํ„ฐ๊ฐ€ ๋จผ์ € ์‹คํ–‰๋œ ํ›„ AuthorizationFilter๋ณด๋‹ค ์•ž์— ๋ฐฐ์น˜ํ•ฉ๋‹ˆ๋‹ค.
  • ๋ณด์•ˆ ํ๋ฆ„ ์ตœ์ ํ™”: TenantFilter๋Š” tenant id์— ๋Œ€ํ•œ ์ ‘๊ทผ ๊ถŒํ•œ์„ ์‚ฌ์ „์— ๊ฒ€์‚ฌํ•˜์—ฌ, ๊ถŒํ•œ์ด ์—†๋Š” ์š”์ฒญ์„ ๋ฏธ๋ฆฌ ์ฐจ๋‹จํ•˜๊ณ  ๋ถˆํ•„์š”ํ•œ ๊ถŒํ•œ ๊ฒ€์‚ฌ ๊ณผ์ •์„ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด์™€ ๊ฐ™์€ ์ˆœ์„œ๋กœ ํ•„ํ„ฐ๋ฅผ ๋ฐฐ์น˜ํ•จ์œผ๋กœ์จ, Spring Security๋Š” ์ •ํ™•ํ•œ ๋ณด์•ˆ ๊ฒ€์ฆ ์ ˆ์ฐจ๋ฅผ ๋”ฐ๋ฅด๋ฉฐ ์•ˆ์ „ํ•˜๊ฒŒ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


๐Ÿ›ก๏ธ Spring Boot์—์„œ TenantFilter ์ค‘๋ณต ํ˜ธ์ถœ ๋ฐฉ์ง€: FilterRegistrationBean ํ™œ์šฉํ•˜๊ธฐ

Spring Boot์—์„œ ํ•„ํ„ฐ๋ฅผ ๋“ฑ๋กํ•˜๋Š” ๋ฐฉ์‹๊ณผ Spring Security์˜ ๋ณด์•ˆ ํ•„ํ„ฐ ์ฒด์ธ์— ์ถ”๊ฐ€ํ•˜๋Š” ๋ฐฉ์‹์ด ๊ฒน์น  ๋•Œ, ํ•„ํ„ฐ๊ฐ€ ์ค‘๋ณต ํ˜ธ์ถœ๋˜๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด FilterRegistrationBean์„ ์‚ฌ์šฉํ•˜์—ฌ Spring Boot๊ฐ€ ๋‚ด์žฅ ์ปจํ…Œ์ด๋„ˆ์— ํ•„ํ„ฐ๋ฅผ ์ž๋™์œผ๋กœ ๋“ฑ๋กํ•˜์ง€ ์•Š๋„๋ก ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


๐Ÿšฉ ๋ฌธ์ œ ์ƒํ™ฉ: ํ•„ํ„ฐ ์ค‘๋ณต ํ˜ธ์ถœ

  1. Spring Boot์˜ ์ž๋™ ํ•„ํ„ฐ ๋“ฑ๋ก

    • @Component๋‚˜ @Bean์„ ์‚ฌ์šฉํ•ด ํ•„ํ„ฐ๋ฅผ Spring Bean์œผ๋กœ ๋“ฑ๋กํ•˜๋ฉด, Spring Boot๋Š” ์ด๋ฅผ ๋‚ด์žฅ ์›น ์ปจํ…Œ์ด๋„ˆ(Tomcat ๋“ฑ)์— ์ž๋™์œผ๋กœ ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค.
    • ๋‚ด์žฅ ์ปจํ…Œ์ด๋„ˆ์— ๋“ฑ๋ก๋œ ํ•„ํ„ฐ๋Š” ๋ชจ๋“  ์š”์ฒญ๋งˆ๋‹ค ํ˜ธ์ถœ๋˜๋ฉฐ, ์ผ๋ฐ˜์ ์ธ ํ•„ํ„ฐ๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.
  2. Spring Security์˜ ๋ณด์•ˆ ํ•„ํ„ฐ ์ฒด์ธ ๋“ฑ๋ก

    • Spring Security ์„ค์ •์—์„œ HttpSecurity.addFilterBefore() ๋˜๋Š” HttpSecurity.addFilterAfter()๋ฅผ ํ†ตํ•ด ํ•„ํ„ฐ๋ฅผ ๋ณด์•ˆ ํ•„ํ„ฐ ์ฒด์ธ์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
    • ์ด๋ ‡๊ฒŒ ๋ณด์•ˆ ํ•„ํ„ฐ ์ฒด์ธ์— ์ถ”๊ฐ€๋œ ํ•„ํ„ฐ๋Š” ๋ณด์•ˆ ํ•„ํ„ฐ ์ฒด์ธ์— ๋”ฐ๋ผ ํ•œ ๋ฒˆ ๋” ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ๋™์ผํ•œ ํ•„ํ„ฐ๊ฐ€ ๋‚ด์žฅ ์ปจํ…Œ์ด๋„ˆ์™€ Spring Security์˜ ๋ณด์•ˆ ํ•„ํ„ฐ ์ฒด์ธ์—์„œ ๊ฐ๊ฐ ํ•œ ๋ฒˆ์”ฉ ํ˜ธ์ถœ๋˜์–ด ์ค‘๋ณต ํ˜ธ์ถœ๋˜๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


โœ… ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•: FilterRegistrationBean์„ ์‚ฌ์šฉํ•˜์—ฌ Spring Boot์˜ ์ž๋™ ๋“ฑ๋ก ๋ฐฉ์ง€

ํ•„ํ„ฐ๊ฐ€ ์ค‘๋ณต ํ˜ธ์ถœ๋˜์ง€ ์•Š๋„๋ก ํ•˜๋ฉด์„œ๋„ ์˜์กด์„ฑ ์ฃผ์ž…์ด ํ•„์š”ํ•  ๋•Œ๋Š” FilterRegistrationBean์„ ์‚ฌ์šฉํ•ด Spring Boot๊ฐ€ ๋‚ด์žฅ ์ปจํ…Œ์ด๋„ˆ์— ํ•„ํ„ฐ๋ฅผ ๋“ฑ๋กํ•˜์ง€ ์•Š๋„๋ก ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

FilterRegistrationBean ์„ค์ • ์˜ˆ์‹œ

@Bean
public FilterRegistrationBean<TenantFilter> tenantFilterRegistration(TenantFilter tenantFilter) {
    FilterRegistrationBean<TenantFilter> registrationBean = new FilterRegistrationBean<>(tenantFilter);
    registrationBean.setEnabled(false); // ๋‚ด์žฅ ์ปจํ…Œ์ด๋„ˆ์— ์ž๋™ ๋“ฑ๋ก ๋ฐฉ์ง€
    return registrationBean;
}
  • setEnabled(false)๋ฅผ ์„ค์ •ํ•˜๋ฉด, Spring Boot๊ฐ€ ํ•ด๋‹น ํ•„ํ„ฐ๋ฅผ ๋‚ด์žฅ ์ปจํ…Œ์ด๋„ˆ์— ์ž๋™์œผ๋กœ ๋“ฑ๋กํ•˜์ง€ ์•Š๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
  • ์ด์ œ TenantFilter๋Š” ๋ณด์•ˆ ํ•„ํ„ฐ ์ฒด์ธ์—์„œ๋งŒ ํ˜ธ์ถœ๋˜๋ฉฐ, ์ค‘๋ณต ํ˜ธ์ถœ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๐Ÿ”„ ์ตœ์ข… ์„ค์ •: ๋ณด์•ˆ ํ•„ํ„ฐ ์ฒด์ธ์—๋งŒ ํ•„ํ„ฐ ์ถ”๊ฐ€

์ด์ œ TenantFilter๊ฐ€ ๋‚ด์žฅ ์ปจํ…Œ์ด๋„ˆ์—์„œ ํ˜ธ์ถœ๋˜์ง€ ์•Š๊ณ , ์˜ค์ง Spring Security ๋ณด์•ˆ ํ•„ํ„ฐ ์ฒด์ธ์—์„œ๋งŒ ํ˜ธ์ถœ๋˜๋„๋ก ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
        // ๋‹ค๋ฅธ ๋ณด์•ˆ ์„ค์ •
        .addFilterBefore(new TenantFilter(), AuthorizationFilter.class); 
    return http.build();
}

์ด ์„ค์ •์„ ํ†ตํ•ด TenantFilter๋Š” ๋ณด์•ˆ ํ•„ํ„ฐ ์ฒด์ธ์—์„œ AuthorizationFilter ์•ž์— ์œ„์น˜ํ•˜์—ฌ ์ธ์ฆ๋œ ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ…Œ๋„ŒํŠธ ์ ‘๊ทผ ๊ถŒํ•œ์„ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.


๐Ÿ“ ์š”์•ฝ

  1. ์ค‘๋ณต ํ˜ธ์ถœ ๋ฐฉ์ง€: FilterRegistrationBean์„ ํ†ตํ•ด Spring Boot๊ฐ€ TenantFilter๋ฅผ ๋‚ด์žฅ ์ปจํ…Œ์ด๋„ˆ์— ๋“ฑ๋กํ•˜์ง€ ์•Š๋„๋ก ์„ค์ •ํ•˜์—ฌ, ํ•„ํ„ฐ๊ฐ€ ์ค‘๋ณต ํ˜ธ์ถœ๋˜์ง€ ์•Š๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
  2. ๋ณด์•ˆ ํ•„ํ„ฐ ์ฒด์ธ์—๋งŒ ์ถ”๊ฐ€: Spring Security์˜ HttpSecurity.addFilterBefore() ๋“ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ ํ•„ํ„ฐ๋ฅผ ๋ณด์•ˆ ํ•„ํ„ฐ ์ฒด์ธ์—๋งŒ ์ถ”๊ฐ€ํ•ด, ์˜๋„ํ•œ ๋Œ€๋กœ ์ˆœ์„œ์— ๋”ฐ๋ผ ํ˜ธ์ถœ๋˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
  3. ์˜์กด์„ฑ ์ฃผ์ž… ์ง€์›: TenantFilter๋ฅผ Spring Bean์œผ๋กœ ๊ด€๋ฆฌํ•˜๋ฉด์„œ, ์˜์กด์„ฑ ์ฃผ์ž…์„ ํ™œ์šฉํ•ด ํ•„ํ„ฐ์˜ ๊ธฐ๋Šฅ์„ ํ™•์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ์„ค์ •์„ ํ†ตํ•ด ํ•„ํ„ฐ๊ฐ€ ๋ณด์•ˆ ํ•„ํ„ฐ ์ฒด์ธ์—์„œ๋งŒ ํ˜ธ์ถœ๋˜๋ฉฐ ์ค‘๋ณต ํ˜ธ์ถœ์„ ๋ฐฉ์ง€ํ•˜๊ณ , Spring Security ๋ณด์•ˆ ๋กœ์ง์— ๋งž๊ฒŒ ์ •ํ™•ํ•˜๊ฒŒ ๋™์ž‘ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๐Ÿ›ก๏ธ


๐Ÿ›ก๏ธ ExceptionTranslationFilter: Spring Security์—์„œ ์ธ์ฆ ๋ฐ ๊ถŒํ•œ ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ

ExceptionTranslationFilter๋Š” Spring Security์—์„œ ์ธ์ฆ ์‹คํŒจ(AuthenticationException) ๋ฐ ๊ถŒํ•œ ๋ถ€์กฑ(AccessDeniedException) ์˜ˆ์™ธ๋ฅผ ๊ฐ์ง€ํ•˜๊ณ , ์ด๋ฅผ ์ ์ ˆํ•œ HTTP ์‘๋‹ต์œผ๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ฐ˜ํ™˜ํ•˜๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค. ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜์ง€ ์•Š์•„๋„, ๋ณด์•ˆ ๊ด€๋ จ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•  ๋•Œ ์ผ๊ด€์„ฑ ์žˆ๋Š” ์‘๋‹ต์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


ExceptionTranslationFilter์˜ ์ฃผ์š” ์—ญํ• ๊ณผ ๋™์ž‘ ๋ฐฉ์‹

1๏ธโƒฃ ์˜ˆ์™ธ ๊ฐ์ง€

  • ExceptionTranslationFilter๋Š” ํ•„ํ„ฐ ์ฒด์ธ ๋‚ด์—์„œ ๋ฐœ์ƒํ•˜๋Š” ์ธ์ฆ ๋ฐ ๊ถŒํ•œ ์˜ค๋ฅ˜๋ฅผ ๊ฐ์ง€ํ•ฉ๋‹ˆ๋‹ค.
  • ์ธ์ฆ ์‹คํŒจ๋‚˜ ๊ถŒํ•œ ๋ถ€์กฑ๊ณผ ๊ฐ™์€ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ์ด๋ฅผ ๊ฐ์ง€ํ•˜์—ฌ ์ ์ ˆํ•œ ํ›„์† ์ฒ˜๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

2๏ธโƒฃ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ๋ฐ HTTP ์‘๋‹ต ๋ณ€ํ™˜

  • ์ธ์ฆ ์˜ˆ์™ธ (AuthenticationException):
    ์ธ์ฆ๋˜์ง€ ์•Š์€ ์‚ฌ์šฉ์ž๊ฐ€ ๋ณดํ˜ธ๋œ ๋ฆฌ์†Œ์Šค์— ์ ‘๊ทผํ•˜๋ ค๊ณ  ํ•  ๋•Œ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
    ExceptionTranslationFilter๋Š” ์ด๋Ÿฌํ•œ ์˜ˆ์™ธ๋ฅผ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋””๋ ‰์…˜ํ•˜๊ฑฐ๋‚˜, 401 Unauthorized ์‘๋‹ต์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

  • ๊ถŒํ•œ ์˜ˆ์™ธ (AccessDeniedException):
    ์ธ์ฆ๋œ ์‚ฌ์šฉ์ž๊ฐ€ ๊ถŒํ•œ์ด ์—†๋Š” ๋ฆฌ์†Œ์Šค์— ์ ‘๊ทผํ•˜๋ ค๊ณ  ํ•  ๋•Œ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
    ์ด ๊ฒฝ์šฐ ExceptionTranslationFilter๋Š” 403 Forbidden ์ƒํƒœ ์ฝ”๋“œ๋กœ ์‘๋‹ต์„ ๋ณ€ํ™˜ํ•˜์—ฌ, ์ ‘๊ทผ์ด ๊ฑฐ๋ถ€๋˜์—ˆ์Œ์„ ์‚ฌ์šฉ์ž์—๊ฒŒ ์•Œ๋ฆฝ๋‹ˆ๋‹ค.

3๏ธโƒฃ ํ•„ํ„ฐ ์ฒด์ธ์—์„œ์˜ ์œ„์น˜

  • ExceptionTranslationFilter๋Š” Spring Security์˜ ํ•„ํ„ฐ ์ฒด์ธ ๋‚ด์—์„œ ๋ณด์•ˆ ํ•„ํ„ฐ ์ค‘ ํ•˜๋‚˜๋กœ ์œ„์น˜ํ•˜๋ฉฐ, ๋‹ค๋ฅธ ๋ณด์•ˆ ํ•„ํ„ฐ๋“ค์ด ํ˜ธ์ถœ๋˜๋Š” ๊ณผ์ •์—์„œ ๋ฐœ์ƒํ•˜๋Š” ์˜ˆ์™ธ๋ฅผ ์ตœ์ข…์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
  • ์˜ˆ๋ฅผ ๋“ค์–ด, ์ธ์ฆ ํ•„ํ„ฐ์—์„œ ์ธ์ฆ ์‹คํŒจ๊ฐ€ ๋ฐœ์ƒํ•˜๊ฑฐ๋‚˜ ๊ถŒํ•œ ํ•„ํ„ฐ์—์„œ ๊ถŒํ•œ ๋ถ€์กฑ์œผ๋กœ ์ ‘๊ทผ์ด ๊ฑฐ๋ถ€๋˜๋ฉด, ExceptionTranslationFilter๊ฐ€ ์ด๋ฅผ ๊ฐ์ง€ํ•˜๊ณ  ์ ์ ˆํ•œ ์‘๋‹ต์œผ๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“‹ ์˜ˆ์‹œ: ExceptionTranslationFilter์˜ ๋™์ž‘ ํ๋ฆ„

  1. ์š”์ฒญ ์ฒ˜๋ฆฌ ์ค‘ ์˜ˆ์™ธ ๋ฐœ์ƒ

    • ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์ธํ•˜์ง€ ์•Š์€ ์ƒํƒœ์—์„œ ๋ณดํ˜ธ๋œ ํŽ˜์ด์ง€์— ์ ‘๊ทผํ•˜๋ฉด AuthenticationException์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
    • ๋˜๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์ธ์ฆ๋˜์—ˆ์ง€๋งŒ ํ•ด๋‹น ์ž์›์— ์ ‘๊ทผํ•  ๊ถŒํ•œ์ด ์—†์œผ๋ฉด AccessDeniedException์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
  2. ExceptionTranslationFilter๊ฐ€ ์˜ˆ์™ธ๋ฅผ ๊ฐ์ง€ ๋ฐ ์ฒ˜๋ฆฌ

    • ExceptionTranslationFilter๋Š” ์ด ์˜ˆ์™ธ๋ฅผ ๊ฐ์ง€ํ•˜๊ณ , ์˜ˆ์™ธ์— ๋งž๋Š” HTTP ์‘๋‹ต์„ ์ค€๋น„ํ•ฉ๋‹ˆ๋‹ค.
  3. HTTP ์‘๋‹ต ๋ฐ˜ํ™˜

    • ์ธ์ฆ ์‹คํŒจ์˜ ๊ฒฝ์šฐ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋””๋ ‰์…˜ํ•˜๊ฑฐ๋‚˜ 401 Unauthorized ์‘๋‹ต์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
    • ๊ถŒํ•œ ๋ถ€์กฑ์˜ ๊ฒฝ์šฐ 403 Forbidden ์‘๋‹ต์„ ๋ฐ˜ํ™˜ํ•˜์—ฌ ์ ‘๊ทผ์ด ๊ฑฐ๋ถ€๋˜์—ˆ์Œ์„ ์•Œ๋ฆฝ๋‹ˆ๋‹ค.

๐Ÿ“ ExceptionTranslationFilter ์‚ฌ์šฉ์˜ ์žฅ์ 

  • ์ค‘์•™ ์ง‘์ค‘ํ™”๋œ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ
    ExceptionTranslationFilter๋ฅผ ํ†ตํ•ด ์ธ์ฆ ๋ฐ ๊ถŒํ•œ ์˜ค๋ฅ˜์— ๋Œ€ํ•œ ์ผ๊ด€์„ฑ ์žˆ๋Š” ์‘๋‹ต์„ ์ œ๊ณตํ•˜์—ฌ, ๋ณด์•ˆ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ์˜ ๋ณต์žก์„ฑ์„ ์ค„์ด๊ณ  ์ฝ”๋“œ ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ๊ฐœ๋ฐœ์ž ํŽธ์˜์„ฑ
    ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜์ง€ ์•Š์•„๋„ ๋˜๋ฏ€๋กœ, ๋ณด์•ˆ ์˜ˆ์™ธ์— ๋Œ€ํ•œ ์‘๋‹ต ์ฒ˜๋ฆฌ๊ฐ€ ๊ฐ„์†Œํ™”๋ฉ๋‹ˆ๋‹ค.

  • ์‚ฌ์šฉ์ž ๊ฒฝํ—˜ ํ–ฅ์ƒ
    ExceptionTranslationFilter๋Š” ์ธ์ฆ ๋ฐ ๊ถŒํ•œ ์˜ค๋ฅ˜ ์‹œ ์ ์ ˆํ•œ ๋ฆฌ๋””๋ ‰์…˜๊ณผ ์‘๋‹ต ๋ณ€ํ™˜์„ ํ†ตํ•ด ์‚ฌ์šฉ์ž๊ฐ€ ์˜ค๋ฅ˜๋ฅผ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋„๋ก ๋•์Šต๋‹ˆ๋‹ค.


๐Ÿ”‘ ์ •๋ฆฌ

ExceptionTranslationFilter๋Š” Spring Security์—์„œ ์ธ์ฆ ์‹คํŒจ์™€ ๊ถŒํ•œ ๋ถ€์กฑ๊ณผ ๊ฐ™์€ ๋ณด์•ˆ ์˜ˆ์™ธ๋ฅผ ๊ฐ์ง€ํ•˜์—ฌ ์ ์ ˆํ•œ HTTP ์‘๋‹ต์œผ๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์ด๋กœ ์ธํ•ด ๋ณด์•ˆ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•  ๋•Œ ์ค‘์•™ํ™”๋œ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ์™€ ์ผ๊ด€๋œ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ์ œ๊ณตํ•˜๋ฉฐ, ๊ฐœ๋ฐœ์ž๋Š” ๋ณด์•ˆ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ์— ๋Œ€ํ•œ ๋ถ€๋‹ด์„ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๐Ÿ›ก๏ธ


๐Ÿ›ก๏ธ ExceptionTranslationFilter์˜ ๋™์ž‘ ๋‹จ๊ณ„: ์ธ์ฆ ๋ฐ ์ ‘๊ทผ ๊ถŒํ•œ ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ

ExceptionTranslationFilter๋Š” Spring Security์—์„œ ๋ฐœ์ƒํ•˜๋Š” ์ธ์ฆ ๋ฐ ๊ถŒํ•œ ์˜ค๋ฅ˜๋ฅผ ์ ์ ˆํžˆ ์ฒ˜๋ฆฌํ•˜๋Š” ํ•„ํ„ฐ๋กœ, ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ์ธ์ฆ ์š”์ฒญ์ด๋‚˜ ์ ‘๊ทผ ๊ฑฐ๋ถ€ ์ฒ˜๋ฆฌ๋ฅผ ์ž๋™์œผ๋กœ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์•„๋ž˜๋Š” ExceptionTranslationFilter๊ฐ€ ๋™์ž‘ํ•˜๋Š” ๊ตฌ์ฒด์ ์ธ ๋‹จ๊ณ„์™€ ๊ฐ ๊ณผ์ •์˜ ์˜๋ฏธ์ž…๋‹ˆ๋‹ค.


1๏ธโƒฃ FilterChain.doFilter(request, response) ํ˜ธ์ถœ

  • ๊ธฐ๋ณธ ๋™์ž‘: ์š”์ฒญ์ด ๋“ค์–ด์˜ค๋ฉด, ExceptionTranslationFilter๋Š” ๋จผ์ € FilterChain.doFilter(request, response)๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๋‚˜๋จธ์ง€ ํ•„ํ„ฐ์™€ ์ž์›(Resource)์„ ์‹คํ–‰ํ•˜๋„๋ก ๋„˜๊น๋‹ˆ๋‹ค.
  • ์˜๋„: ํ•„ํ„ฐ ์ฒด์ธ ์‹คํ–‰ ์ค‘์— ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ์ธ์ฆ ๋˜๋Š” ๊ถŒํ•œ ๊ด€๋ จ ์˜ˆ์™ธ๋ฅผ ๊ฐ์ง€ํ•˜๊ณ , ๋ณด์•ˆ ์˜ˆ์™ธ๋กœ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•จ์ž…๋‹ˆ๋‹ค.

2๏ธโƒฃ ์ธ์ฆ๋˜์ง€ ์•Š๊ฑฐ๋‚˜ AuthenticationException ๋ฐœ์ƒ ์‹œ: ์ธ์ฆ ์‹œ์ž‘

  • ์˜ˆ์™ธ ๋ฐœ์ƒ ์ƒํ™ฉ: ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์ธํ•˜์ง€ ์•Š์€ ์ƒํƒœ๋กœ ๋ณดํ˜ธ๋œ ์ž์›์— ์ ‘๊ทผํ•˜๋ ค๊ณ  ํ•  ๋•Œ ๋ฐœ์ƒํ•˜๋ฉฐ, ์ด๋Š” AuthenticationException์œผ๋กœ ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค.
  • ์˜๋ฏธ: "์‚ฌ์šฉ์ž๊ฐ€ ์ธ์ฆ๋˜์ง€ ์•Š์•˜์œผ๋ฏ€๋กœ, ์ธ์ฆ์ด ํ•„์š”ํ•˜๋‹ค"๋Š” ๋œป์ž…๋‹ˆ๋‹ค.

์ฒ˜๋ฆฌ ๊ณผ์ •

  1. SecurityContextHolder ์ดˆ๊ธฐํ™”

    • SecurityContextHolder๋Š” ํ˜„์žฌ์˜ ์ธ์ฆ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜๋Š” ์ €์žฅ์†Œ์ž…๋‹ˆ๋‹ค.
    • ์ธ์ฆ ํ”„๋กœ์„ธ์Šค๋ฅผ ๋‹ค์‹œ ์‹œ์ž‘ํ•˜๊ธฐ ์œ„ํ•ด SecurityContextHolder๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜์—ฌ, ์ด์ „ ์š”์ฒญ์˜ ์ธ์ฆ ์ •๋ณด๊ฐ€ ๋‚จ์ง€ ์•Š๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
  2. HttpServletRequest ์ €์žฅ

    • ์›๋ž˜ ์š”์ฒญ์„ ์ €์žฅํ•ด ๋‘์–ด, ์ธ์ฆ ์„ฑ๊ณต ํ›„ ๋‹ค์‹œ ์š”์ฒญ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
    • ์ด๋ฅผ ํ†ตํ•ด ์‚ฌ์šฉ์ž๊ฐ€ ์ž๊ฒฉ ์ฆ๋ช…์„ ์™„๋ฃŒํ•œ ๋’ค ์›๋ž˜ ์š”์ฒญ์„ ์ด์–ด์„œ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
  3. AuthenticationEntryPoint ํ˜ธ์ถœ

    • AuthenticationEntryPoint๋Š” ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ์ž๊ฒฉ ์ฆ๋ช…(๋กœ๊ทธ์ธ)์„ ์š”๊ตฌํ•˜๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.
    • ์˜ˆ๋ฅผ ๋“ค์–ด, formLogin์„ ์„ค์ •ํ•œ ๊ฒฝ์šฐ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋””๋ ‰์…˜ํ•˜๊ณ , httpBasic์„ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ WWW-Authenticate ํ—ค๋”๋ฅผ ํ†ตํ•ด ์‚ฌ์šฉ์ž ์ž๊ฒฉ์„ ์š”์ฒญํ•ฉ๋‹ˆ๋‹ค.

3๏ธโƒฃ AccessDeniedException ๋ฐœ์ƒ ์‹œ: ์ ‘๊ทผ ๊ฑฐ๋ถ€ ์ฒ˜๋ฆฌ

  • ์˜ˆ์™ธ ๋ฐœ์ƒ ์ƒํ™ฉ: ์‚ฌ์šฉ์ž๊ฐ€ ์ธ์ฆ๋œ ์ƒํƒœ์ด์ง€๋งŒ, ํŠน์ • ์ž์›์— ๋Œ€ํ•œ ์ ‘๊ทผ ๊ถŒํ•œ์ด ์—†์„ ๋•Œ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
  • ์˜๋ฏธ: ์‚ฌ์šฉ์ž๋Š” ์ž๊ฒฉ ์ฆ๋ช…์„ ์™„๋ฃŒํ–ˆ์œผ๋‚˜, ์š”์ฒญํ•œ ์ž์›์— ์ ‘๊ทผํ•  ๊ถŒํ•œ์ด ์—†์Šต๋‹ˆ๋‹ค.

์ฒ˜๋ฆฌ ๊ณผ์ •

  1. AccessDeniedHandler ํ˜ธ์ถœ
    • AccessDeniedHandler๋Š” AccessDeniedException์ด ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ํ˜ธ์ถœ๋˜์–ด, ์ ‘๊ทผ ๊ฑฐ๋ถ€ ์ƒํ™ฉ์„ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
    • ๊ธฐ๋ณธ์ ์œผ๋กœ 403 Forbidden ์‘๋‹ต ์ฝ”๋“œ๋ฅผ ๋ฐ˜ํ™˜ํ•˜์—ฌ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ์ž์›์— ์ ‘๊ทผํ•  ์ˆ˜ ์—†์Œ์„ ์•Œ๋ฆฝ๋‹ˆ๋‹ค.
    • ํ•„์š”์— ๋”ฐ๋ผ AccessDeniedHandler๋ฅผ ์ปค์Šคํ„ฐ๋งˆ์ด์ง•ํ•˜์—ฌ ํŠน์ • ์ ‘๊ทผ ๊ฑฐ๋ถ€ ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋””๋ ‰์…˜ํ•˜๊ฑฐ๋‚˜ ์‚ฌ์šฉ์ž์—๊ฒŒ ์ ์ ˆํ•œ ๋ฉ”์‹œ์ง€๋ฅผ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ“ ExceptionTranslationFilter์˜ ์‚ฌ์šฉ ์ด์œ ์™€ ์žฅ์ 

  1. ์ค‘์•™ ์ง‘์ค‘ํ™”๋œ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ
    ExceptionTranslationFilter๋Š” ์ธ์ฆ ๋ฐ ๊ถŒํ•œ ์˜ค๋ฅ˜๋ฅผ ํ†ต์ผ๋œ ๋ฐฉ์‹์œผ๋กœ ์ฒ˜๋ฆฌํ•˜์—ฌ ์ฝ”๋“œ์˜ ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•˜๊ณ , ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ๋กœ์ง์„ ๋‹จ์ˆœํ™”ํ•ฉ๋‹ˆ๋‹ค.

  2. ๊ฐœ๋ฐœ์ž ํŽธ์˜์„ฑ
    ๊ฐœ๋ฐœ์ž๊ฐ€ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ํ•„์š” ์—†์ด, Spring Security๊ฐ€ ๊ธฐ๋ณธ์ ์ธ ๋ณด์•ˆ ์˜ˆ์™ธ์— ๋Œ€ํ•ด ์ž๋™์œผ๋กœ ์‘๋‹ต์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

  3. ์‚ฌ์šฉ์ž ๊ฒฝํ—˜ ํ–ฅ์ƒ
    ExceptionTranslationFilter๋Š” ์ธ์ฆ ์‹คํŒจ ์‹œ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€ ๋ฆฌ๋””๋ ‰์…˜์ด๋‚˜, ๊ถŒํ•œ ๋ถ€์กฑ ์‹œ 403 ์‘๋‹ต์„ ํ†ตํ•ด ์‚ฌ์šฉ์ž๊ฐ€ ์˜ค๋ฅ˜๋ฅผ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋„๋ก ๋•์Šต๋‹ˆ๋‹ค.


๐Ÿ”‘ ์ •๋ฆฌ

  • ์ธ์ฆ ์˜ˆ์™ธ (AuthenticationException): ์‚ฌ์šฉ์ž๊ฐ€ ์ธ์ฆ๋˜์ง€ ์•Š์€ ์ƒํƒœ๋กœ ๋ณดํ˜ธ๋œ ์ž์›์— ์ ‘๊ทผํ•  ๊ฒฝ์šฐ, AuthenticationEntryPoint๊ฐ€ ์ž๊ฒฉ ์ฆ๋ช…์„ ์š”์ฒญํ•ฉ๋‹ˆ๋‹ค.
  • ์ ‘๊ทผ ๊ฑฐ๋ถ€ ์˜ˆ์™ธ (AccessDeniedException): ์ธ์ฆ๋œ ์‚ฌ์šฉ์ž๊ฐ€ ๊ถŒํ•œ์ด ์—†๋Š” ์ž์›์— ์ ‘๊ทผํ•  ๊ฒฝ์šฐ, AccessDeniedHandler๊ฐ€ 403 ์‘๋‹ต์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

ExceptionTranslationFilter๋Š” ์ธ์ฆ ๋ฐ ๊ถŒํ•œ ์˜ค๋ฅ˜๋ฅผ ์ฒ˜๋ฆฌํ•˜์—ฌ HTTP ์‘๋‹ต์„ ์ ์ ˆํžˆ ๋ณ€ํ™˜ํ•˜๋Š” ์—ญํ• ์„ ๋‹ด๋‹นํ•˜๋ฉฐ, Spring Security์—์„œ ์ค‘์•™ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ๋ฐ ๋ณด์•ˆ ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•œ ์ค‘์š”ํ•œ ๊ตฌ์„ฑ ์š”์†Œ์ž…๋‹ˆ๋‹ค. ๐Ÿ›ก๏ธ


์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด AccessDeniedException์ด๋‚˜ AuthenticationException์„ ๋ฐœ์ƒ์‹œํ‚ค์ง€ ์•Š์œผ๋ฉด, ExceptionTranslationFilter๋Š” ์•„๋ฌด๋Ÿฐ ์ž‘์—…๋„ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.


ExceptionTranslationFilter ์˜์‚ฌ ์ฝ”๋“œ: ์ธ์ฆ ๋ฐ ์ ‘๊ทผ ๊ฑฐ๋ถ€ ์ฒ˜๋ฆฌ

ExceptionTranslationFilter๋Š” ํ•„ํ„ฐ ์ฒด์ธ์—์„œ ๋ฐœ์ƒํ•˜๋Š” ๋ณด์•ˆ ์˜ˆ์™ธ๋ฅผ ์ฒ˜๋ฆฌํ•˜์—ฌ, ์ธ์ฆ์ด ํ•„์š”ํ•˜๋ฉด ์ธ์ฆ ์ ˆ์ฐจ๋ฅผ ์‹œ์ž‘ํ•˜๊ณ , ์ ‘๊ทผ ๊ถŒํ•œ์ด ์—†์œผ๋ฉด ์ ‘๊ทผ์„ ๊ฑฐ๋ถ€ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค. ์•„๋ž˜๋Š” ExceptionTranslationFilter์˜ ์˜์‚ฌ ์ฝ”๋“œ์™€ ํ•ด๋‹น ๋™์ž‘์„ ์„ค๋ช…ํ•˜๋Š” ๋‹จ๊ณ„๋ณ„ ๋ฆฌ๋ทฐ์ž…๋‹ˆ๋‹ค.


try {
    filterChain.doFilter(request, response); 
} catch (AccessDeniedException | AuthenticationException ex) {
    if (!authenticated || ex instanceof AuthenticationException) {
        startAuthentication(); // ์ธ์ฆ ์‹œ์ž‘
    } else {
        accessDenied(); // ์ ‘๊ทผ ๊ฑฐ๋ถ€
    }
}

๐Ÿ”„ ExceptionTranslationFilter์˜ ๋™์ž‘ ๋‹จ๊ณ„

1๏ธโƒฃ filterChain.doFilter(request, response) ํ˜ธ์ถœ

  • ๊ธฐ๋ณธ ๋™์ž‘: ExceptionTranslationFilter๋Š” ์š”์ฒญ์ด ๋“ค์–ด์˜ค๋ฉด ๋จผ์ € filterChain.doFilter(request, response)๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋‚˜๋จธ์ง€ ๋ถ€๋ถ„(์˜ˆ: FilterSecurityInterceptor ๋˜๋Š” ๋ฉ”์„œ๋“œ ๋ณด์•ˆ)์œผ๋กœ ์š”์ฒญ์„ ๋„˜๊น๋‹ˆ๋‹ค.
  • ์˜ˆ์™ธ ๋ฐœ์ƒ ๊ฐ์ง€: ์ด ๊ณผ์ •์—์„œ ๋‹ค๋ฅธ ํ•„ํ„ฐ ๋˜๋Š” ๋ณด์•ˆ ์ธํ„ฐ์…‰ํ„ฐ์—์„œ AuthenticationException์ด๋‚˜ AccessDeniedException์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ExceptionTranslationFilter๋Š” ์ด๋ฅผ ๊ฐ์ง€ํ•˜์—ฌ ๋ณด์•ˆ ์˜ˆ์™ธ๋กœ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

2๏ธโƒฃ ์˜ˆ์™ธ ๋ฐœ์ƒ ์‹œ ์ธ์ฆ ๋˜๋Š” ์ ‘๊ทผ ๊ฑฐ๋ถ€ ์ฒ˜๋ฆฌ

  • ์ธ์ฆ๋˜์ง€ ์•Š์•˜๊ฑฐ๋‚˜ AuthenticationException์ด ๋ฐœ์ƒํ•œ ๊ฒฝ์šฐ

    • ์กฐ๊ฑด: !authenticated๊ฐ€ ์ฐธ์ด๊ฑฐ๋‚˜, ์˜ˆ์™ธ๊ฐ€ AuthenticationException์ธ ๊ฒฝ์šฐ.
    • ๋™์ž‘: startAuthentication() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์ธ์ฆ ํ”„๋กœ์„ธ์Šค๋ฅผ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.
    • ์„ค๋ช…: ์‚ฌ์šฉ์ž๊ฐ€ ์ธ์ฆ๋˜์ง€ ์•Š์•˜๊ฑฐ๋‚˜, ์ธ์ฆ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•œ ๊ฒฝ์šฐ, ExceptionTranslationFilter๋Š” AuthenticationEntryPoint๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ์ธ์ฆ ์ ˆ์ฐจ๋ฅผ ์š”์ฒญํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋””๋ ‰์…˜ํ•˜๊ฑฐ๋‚˜, WWW-Authenticate ํ—ค๋”๋กœ ์ž๊ฒฉ ์ฆ๋ช…์„ ์š”์ฒญํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๊ทธ ์™ธ์˜ ๊ฒฝ์šฐ (AccessDeniedException)

    • ์กฐ๊ฑด: ์‚ฌ์šฉ์ž๊ฐ€ ์ด๋ฏธ ์ธ์ฆ๋œ ์ƒํƒœ์ด๋ฉฐ, ์˜ˆ์™ธ๊ฐ€ AccessDeniedException์ธ ๊ฒฝ์šฐ.
    • ๋™์ž‘: accessDenied() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์ ‘๊ทผ ๊ฑฐ๋ถ€๋ฅผ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
    • ์„ค๋ช…: ์‚ฌ์šฉ์ž๊ฐ€ ์ธ์ฆ๋œ ์ƒํƒœ์ด์ง€๋งŒ ํŠน์ • ์ž์›์— ์ ‘๊ทผํ•  ๊ถŒํ•œ์ด ์—†์„ ๋•Œ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. AccessDeniedHandler๊ฐ€ 403 Forbidden ์‘๋‹ต์„ ๋ฐ˜ํ™˜ํ•˜์—ฌ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ์ ‘๊ทผ ๊ฑฐ๋ถ€ ์ƒํƒœ๋ฅผ ์•Œ๋ฆฝ๋‹ˆ๋‹ค. ํ•„์š”์— ๋”ฐ๋ผ, ํŠน์ • ์ ‘๊ทผ ๊ฑฐ๋ถ€ ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋””๋ ‰์…˜ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

ExceptionTranslationFilter ์˜์‚ฌ ์ฝ”๋“œ ๋ฆฌ๋ทฐ

  • filterChain.doFilter(request, response)๋Š” ์š”์ฒญ์ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋‚˜๋จธ์ง€ ๋ถ€๋ถ„์œผ๋กœ ์ „๋‹ฌ๋˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์ด๋•Œ ๋ฐœ์ƒํ•˜๋Š” AuthenticationException ๋˜๋Š” AccessDeniedException์€ ExceptionTranslationFilter์—์„œ ์žก์•„ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
  • ์ธ์ฆ ํ•„์š”: ์‚ฌ์šฉ์ž๊ฐ€ ์ธ์ฆ๋˜์ง€ ์•Š์•˜๊ฑฐ๋‚˜ ์ธ์ฆ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด, ์ธ์ฆ ์ ˆ์ฐจ๋ฅผ ์‹œ์ž‘ํ•˜์—ฌ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋””๋ ‰์…˜ํ•˜๊ฑฐ๋‚˜ ์ž๊ฒฉ ์ฆ๋ช…์„ ์š”์ฒญํ•ฉ๋‹ˆ๋‹ค.
  • ์ ‘๊ทผ ๊ฑฐ๋ถ€: ์ธ์ฆ๋œ ์‚ฌ์šฉ์ž๊ฐ€ ๊ถŒํ•œ์ด ์—†๋Š” ์ž์›์— ์ ‘๊ทผํ•  ๋•Œ๋Š” 403 Forbidden ์‘๋‹ต์„ ๋ฐ˜ํ™˜ํ•˜์—ฌ ์ ‘๊ทผ ๊ฑฐ๋ถ€ ์ƒํƒœ๋ฅผ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ์•Œ๋ฆฝ๋‹ˆ๋‹ค.

๐Ÿ“ ์š”์•ฝ

ExceptionTranslationFilter๋Š” ๋ณด์•ˆ ํ•„ํ„ฐ ์ฒด์ธ์—์„œ ๋ฐœ์ƒํ•˜๋Š” AuthenticationException ๋ฐ AccessDeniedException์„ ๊ฐ์ง€ํ•˜๊ณ , ์ƒํ™ฉ์— ๋งž๊ฒŒ ์ธ์ฆ ์š”์ฒญ ๋˜๋Š” ์ ‘๊ทผ ๊ฑฐ๋ถ€ ์ฒ˜๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

  • ์ธ์ฆ ์˜ˆ์™ธ: ์ธ์ฆ์ด ํ•„์š”ํ•˜๋ฏ€๋กœ AuthenticationEntryPoint๋ฅผ ํ†ตํ•ด ์ž๊ฒฉ ์ฆ๋ช…์„ ์š”์ฒญํ•ฉ๋‹ˆ๋‹ค.
  • ์ ‘๊ทผ ๊ฑฐ๋ถ€ ์˜ˆ์™ธ: ์ธ์ฆ์€ ๋˜์—ˆ์œผ๋‚˜ ๊ถŒํ•œ์ด ๋ถ€์กฑํ•œ ๊ฒฝ์šฐ 403 Forbidden ์‘๋‹ต์„ ๋ฐ˜ํ™˜ํ•˜์—ฌ ์ ‘๊ทผ ๊ฑฐ๋ถ€ ์ƒํƒœ๋ฅผ ์•Œ๋ฆฝ๋‹ˆ๋‹ค.

์ด ํ•„ํ„ฐ๋Š” Spring Security์—์„œ ์˜ˆ์™ธ๋ฅผ ์ผ๊ด€๋˜๊ฒŒ ์ฒ˜๋ฆฌํ•˜๊ณ  ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ํ–ฅ์ƒ์‹œํ‚ค๋Š” ๋ฐ ์ค‘์š”ํ•œ ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค. ๐Ÿ›ก๏ธ


๐Ÿ›ก๏ธ Spring Security์˜ RequestCache: ์ธ์ฆ ํ›„ ์›๋ž˜ ์š”์ฒญ์œผ๋กœ ๋ณต๊ท€ํ•˜๊ธฐ

RequestCache๋Š” Spring Security์—์„œ ์ธ์ฆ์ด ํ•„์š”ํ•œ ์ž์›์— ๋Œ€ํ•œ ์š”์ฒญ์„ ์ž„์‹œ๋กœ ์ €์žฅํ•˜๊ณ , ์‚ฌ์šฉ์ž๊ฐ€ ์ธ์ฆ์„ ์™„๋ฃŒํ•œ ํ›„ ์›๋ž˜ ์š”์ฒญ์„ ๋‹ค์‹œ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋•๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์‚ฌ์šฉ์ž๋Š” ์ธ์ฆ ๊ณผ์ • ์ดํ›„์—๋„ ์›๋ž˜ ์š”์ฒญํ•œ ์ž์›์œผ๋กœ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


RequestCache์˜ ์—ญํ• ๊ณผ ํ•„์š”์„ฑ

1๏ธโƒฃ ์ธ์ฆ๋˜์ง€ ์•Š์€ ์ƒํƒœ๋กœ ๋ณดํ˜ธ๋œ ์ž์› ์š”์ฒญ ์‹œ

  • ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์ธํ•˜์ง€ ์•Š์€ ์ƒํƒœ์—์„œ ๋ณดํ˜ธ๋œ ์ž์›(์˜ˆ: ํšŒ์› ์ „์šฉ ํŽ˜์ด์ง€)์— ์ ‘๊ทผํ•˜๋ ค๊ณ  ํ•˜๋ฉด, Spring Security๋Š” ์ธ์ฆ ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค.
  • ์ด๋•Œ ExceptionTranslationFilter๊ฐ€ ์˜ˆ์™ธ๋ฅผ ๊ฐ์ง€ํ•˜๊ณ  ์ธ์ฆ ์ ˆ์ฐจ๋ฅผ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.
  • ์›๋ž˜ ์š”์ฒญ์„ ์ €์žฅํ•˜์—ฌ ์ธ์ฆ ์™„๋ฃŒ ํ›„ ๋‹ค์‹œ ์š”์ฒญํ•  ์ˆ˜ ์žˆ๋„๋ก RequestCache๊ฐ€ ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.

2๏ธโƒฃ RequestCache๋ฅผ ํ†ตํ•œ ์š”์ฒญ ์ €์žฅ

  • Spring Security๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ RequestCache ์ธํ„ฐํŽ˜์ด์Šค์˜ ๊ตฌํ˜„์ฒด์ธ HttpSessionRequestCache๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์š”์ฒญ์„ ์ž„์‹œ๋กœ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.
  • HttpSessionRequestCache๋Š” HttpSession์— HttpServletRequest ๊ฐ์ฒด๋ฅผ ์ €์žฅํ•˜์—ฌ, ์ธ์ฆ์ด ์™„๋ฃŒ๋˜๋ฉด ์ด๋ฅผ ๋‹ค์‹œ ๊บผ๋‚ด์™€ ์›๋ž˜ ์ž์›์„ ์š”์ฒญํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

3๏ธโƒฃ ์ธ์ฆ ํ›„ ์›๋ž˜ ์š”์ฒญ์œผ๋กœ ๋ณต๊ท€

  • ์‚ฌ์šฉ์ž๊ฐ€ ์ธ์ฆ์— ์„ฑ๊ณตํ•˜๋ฉด, RequestCache๋Š” ์„ธ์…˜์— ์ €์žฅ๋œ ์›๋ž˜ ์š”์ฒญ์„ ์‚ฌ์šฉํ•˜์—ฌ ์ธ์ฆ๋œ ์ƒํƒœ๋กœ ๋‹ค์‹œ ์ž์›์— ์ ‘๊ทผํ•˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
  • ์ด๋ฅผ ํ†ตํ•ด ์‚ฌ์šฉ์ž๋Š” ์ธ์ฆ ํ›„์—๋„ ๋ณ„๋‹ค๋ฅธ ์กฐ์ž‘ ์—†์ด ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์›๋ž˜ ์š”์ฒญํ•œ ์ž์›์— ๋„๋‹ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

RequestCache์˜ ๋™์ž‘ ๊ณผ์ • ์˜ˆ์‹œ

  1. ๋ณดํ˜ธ๋œ ํŽ˜์ด์ง€์— ์ ‘๊ทผ ์‹œ๋„

    • ์‚ฌ์šฉ์ž๊ฐ€ ์ธ์ฆ ์—†์ด /member/profile ํŽ˜์ด์ง€์— ์ ‘๊ทผํ•˜๋ ค ํ•ฉ๋‹ˆ๋‹ค.
    • Spring Security๋Š” ํ•ด๋‹น ์ž์›์ด ์ธ์ฆ์„ ํ•„์š”๋กœ ํ•œ๋‹ค๋Š” ์ ์„ ์ธ์‹ํ•˜๊ณ , ์ธ์ฆ์ด ํ•„์š”ํ•˜๋‹ค๋Š” ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค.
  2. ์š”์ฒญ์„ ์ €์žฅ

    • HttpSessionRequestCache๊ฐ€ ํ˜„์žฌ HttpServletRequest ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉ์ž์˜ ์„ธ์…˜์— ์ €์žฅํ•˜์—ฌ, ์ธ์ฆ ์ดํ›„์— ์ด ์š”์ฒญ์„ ๋‹ค์‹œ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ์ค€๋น„ํ•ฉ๋‹ˆ๋‹ค.
  3. ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋””๋ ‰์…˜

    • AuthenticationEntryPoint๊ฐ€ ํ˜ธ์ถœ๋˜์–ด ์‚ฌ์šฉ์ž๋Š” ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
  4. ์ธ์ฆ ํ›„ ์›๋ž˜ ์š”์ฒญ์œผ๋กœ ๋ฆฌ๋””๋ ‰์…˜

    • ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์ธ์— ์„ฑ๊ณตํ•˜๋ฉด, RequestCache๋Š” ์„ธ์…˜์— ์ €์žฅ๋œ ์›๋ž˜ ์š”์ฒญ์„ ๋‹ค์‹œ ๋ถˆ๋Ÿฌ์™€ /member/profile ํŽ˜์ด์ง€๋ฅผ ์š”์ฒญํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.
    • ์ด๋กœ์จ ์‚ฌ์šฉ์ž๋Š” ์ธ์ฆ์ด ์™„๋ฃŒ๋œ ํ›„ ์›๋ž˜ ์š”์ฒญํ•œ ํŽ˜์ด์ง€๋กœ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋Œ์•„๊ฐ€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

RequestCache ๊ตฌํ˜„์ฒด

Spring Security๋Š” RequestCache ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ๊ตฌํ˜„์ฒด๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ๋Š” HttpSessionRequestCache๊ฐ€ ์‚ฌ์šฉ๋˜๋ฉฐ, ํ•„์š”์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ๊ตฌํ˜„์ฒด๋ฅผ ์„ ํƒํ•˜๊ฑฐ๋‚˜ ์‚ฌ์šฉ์ž ์ •์˜ ๊ตฌํ˜„์ฒด๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • HttpSessionRequestCache

    • HttpSession์— ์š”์ฒญ์„ ์ €์žฅํ•˜๋Š” ๊ธฐ๋ณธ ๊ตฌํ˜„์ฒด๋กœ, ์ธ์ฆ ํ›„ ์›๋ž˜ ์š”์ฒญ์œผ๋กœ ๋ณต๊ท€ํ•  ๋•Œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
  • NullRequestCache

    • ์š”์ฒญ์„ ์ €์žฅํ•˜์ง€ ์•Š๋„๋ก ์„ค์ •ํ•  ๋•Œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ํŠน์ • API์—์„œ๋Š” ์ด์ „ ์š”์ฒญ์„ ์ €์žฅํ•˜์ง€ ์•Š๋„๋ก ์„ค์ •ํ•˜๋Š” ๊ฒƒ์ด ์œ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ“ ์š”์•ฝ

RequestCache๋Š” ์ธ์ฆ์ด ํ•„์š”ํ•œ ์ž์›์— ๋Œ€ํ•ด ์›๋ž˜ ์š”์ฒญ์„ ์ €์žฅํ•˜๊ณ , ์‚ฌ์šฉ์ž๊ฐ€ ์ธ์ฆ์„ ์™„๋ฃŒํ•œ ํ›„ ์ €์žฅ๋œ ์š”์ฒญ์„ ๋‹ค์‹œ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋•๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์‚ฌ์šฉ์ž๋Š” ์ธ์ฆ ๊ณผ์ • ์ดํ›„์—๋„ ์›๋ž˜ ์š”์ฒญํ•œ ํŽ˜์ด์ง€์— ์‰ฝ๊ฒŒ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, Spring Security๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ HttpSessionRequestCache๋ฅผ ํ†ตํ•ด ์ด ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

์ด ๊ธฐ๋Šฅ์€ ์ธ์ฆ ํ›„ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ๊ฐœ์„ ํ•˜์—ฌ, ์ž์› ์ ‘๊ทผ์„ ๋ณด๋‹ค ์ž์—ฐ์Šค๋Ÿฝ๊ณ  ๋งค๋„๋Ÿฝ๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค. ๐Ÿ›ก๏ธ


๐Ÿ› ๏ธ RequestCache ์„ค์ •: ํŠน์ • ํŒŒ๋ผ๋ฏธํ„ฐ์— ๋”ฐ๋ผ ์ €์žฅ๋œ ์š”์ฒญ ํ™•์ธ

์œ„ ์ฝ”๋“œ์—์„œ๋Š” HttpSessionRequestCache๊ฐ€ continue๋ผ๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ํฌํ•จ๋œ ์š”์ฒญ์— ๋Œ€ํ•ด์„œ๋งŒ ์ €์žฅ๋œ ์š”์ฒญ์„ ํ™•์ธํ•˜๋„๋ก ์„ค์ •ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด ์„ค์ •์„ ํ†ตํ•ด ํŠน์ • ์กฐ๊ฑด์— ๋”ฐ๋ผ ์ €์žฅ๋œ ์š”์ฒญ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ๋”์šฑ ์„ธ๋ฐ€ํ•˜๊ฒŒ ์ œ์–ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@Bean
DefaultSecurityFilterChain springSecurity(HttpSecurity http) throws Exception {
    HttpSessionRequestCache requestCache = new HttpSessionRequestCache();
    requestCache.setMatchingRequestParameterName("continue"); // "continue" ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ์žˆ์„ ๋•Œ๋งŒ ์š”์ฒญ ํ™•์ธ
    http
        .requestCache((cache) -> cache
            .requestCache(requestCache)
        );
    return http.build();
}

๐Ÿ“‹ ์ฝ”๋“œ ์„ค๋ช…

  1. HttpSessionRequestCache ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ ๋ฐ ํŒŒ๋ผ๋ฏธํ„ฐ ์„ค์ •

    • HttpSessionRequestCache ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•œ ํ›„, setMatchingRequestParameterName("continue")๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ continue ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ํฌํ•จ๋œ ์š”์ฒญ์— ๋Œ€ํ•ด์„œ๋งŒ ์ €์žฅ๋œ ์š”์ฒญ์„ ํ™•์ธํ•˜๋„๋ก ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
    • ์ด ์„ค์ •์ด ์—†์„ ๊ฒฝ์šฐ, HttpSessionRequestCache๋Š” ๋ชจ๋“  ์ธ์ฆ๋˜์ง€ ์•Š์€ ์š”์ฒญ์„ ์ €์žฅํ•˜์ง€๋งŒ, ํŠน์ • ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ง€์ •ํ•จ์œผ๋กœ์จ ์ €์žฅ๋œ ์š”์ฒญ ํ™•์ธ ์กฐ๊ฑด์„ ์ œํ•œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  2. HttpSecurity ์„ค์ •์—์„œ RequestCache ์ ์šฉ

    • .requestCache((cache) -> cache.requestCache(requestCache))๋ฅผ ํ†ตํ•ด, Spring Security์˜ ๋ณด์•ˆ ์„ค์ •์— ์ปค์Šคํ…€ requestCache๋ฅผ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค.
    • ์ด์ œ continue ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ํฌํ•จ๋œ ์š”์ฒญ๋งŒ RequestCache์— ์˜ํ•ด ํ™•์ธ๋˜๊ณ , ์ธ์ฆ ํ›„ ์ €์žฅ๋œ ์š”์ฒญ์„ ๋‹ค์‹œ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๐Ÿ“ ๋™์ž‘ ๋ฐฉ์‹ ์˜ˆ์‹œ

  1. ์š”์ฒญ์ด ์ €์žฅ๋˜๋Š” ๊ฒฝ์šฐ

    • ์‚ฌ์šฉ์ž๊ฐ€ ์ธ์ฆ๋˜์ง€ ์•Š์€ ์ƒํƒœ์—์„œ /protected/resource?continue=true์™€ ๊ฐ™์ด continue ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ํฌํ•จ๋œ URL์— ์ ‘๊ทผํ•ฉ๋‹ˆ๋‹ค.
    • HttpSessionRequestCache๋Š” ์ด ์š”์ฒญ์„ ์‚ฌ์šฉ์ž ์„ธ์…˜์— ์ €์žฅํ•˜์—ฌ, ์ธ์ฆ์ด ์™„๋ฃŒ๋œ ํ›„ ์š”์ฒญ์„ ๋‹ค์‹œ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ์ค€๋น„ํ•ฉ๋‹ˆ๋‹ค.
  2. ์š”์ฒญ์ด ์ €์žฅ๋˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ

    • ์‚ฌ์šฉ์ž๊ฐ€ continue ํŒŒ๋ผ๋ฏธํ„ฐ ์—†์ด /protected/resource์— ์ ‘๊ทผํ•˜๋ฉด, HttpSessionRequestCache๋Š” ์š”์ฒญ์„ ์ €์žฅํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
    • ์ด๋กœ ์ธํ•ด ์ธ์ฆ ํ›„ ์›๋ž˜ ์š”์ฒญ์œผ๋กœ ๋Œ์•„๊ฐ€๋Š” ๋™์ž‘์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๐Ÿ’ก ์ด ์„ค์ •์˜ ์žฅ์ 

  • ์„ธ๋ฐ€ํ•œ ์š”์ฒญ ํ™•์ธ ์ œ์–ด: continue ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ํ†ตํ•ด ํŠน์ • ์š”์ฒญ์— ๋Œ€ํ•ด์„œ๋งŒ RequestCache๋ฅผ ํ™œ์„ฑํ™”ํ•˜์—ฌ, ๋ถˆํ•„์š”ํ•œ ์š”์ฒญ ์ €์žฅ์„ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์‚ฌ์šฉ์ž ๊ฒฝํ—˜ ๊ฐœ์„ : ์ธ์ฆ ํ›„ ํŠน์ • ์กฐ๊ฑด์— ๋งž๋Š” ์š”์ฒญ๋งŒ ๋‹ค์‹œ ์‹คํ–‰ํ•˜๋ฏ€๋กœ, ์‚ฌ์šฉ์ž์—๊ฒŒ ์›์น˜ ์•Š๋Š” ์š”์ฒญ ๋ณต๊ท€๋ฅผ ๋ฐฉ์ง€ํ•˜๊ณ  ๋” ๋‚˜์€ ์ œ์–ด๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

์ด ์„ค์ •์€ RequestCache๊ฐ€ ํŠน์ • ์š”์ฒญ๋งŒ ์ €์žฅํ•˜๋„๋ก ํ•˜์—ฌ, ์ธ์ฆ ํ›„ ์›๋ž˜ ์š”์ฒญ์œผ๋กœ ๋Œ์•„๊ฐ€๋Š” ๊ธฐ๋Šฅ์„ ๋” ์„ธ๋ฐ€ํ•˜๊ฒŒ ์ œ์–ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๐Ÿ›ก๏ธ


๐Ÿ› ๏ธ NullRequestCache ์„ค์ •: ์š”์ฒญ์„ ์„ธ์…˜์— ์ €์žฅํ•˜์ง€ ์•Š๋„๋ก ์„ค์ •

NullRequestCache๋Š” Spring Security์—์„œ ์ธ์ฆ๋˜์ง€ ์•Š์€ ์š”์ฒญ์„ ์„ธ์…˜์— ์ €์žฅํ•˜์ง€ ์•Š๋„๋ก ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋Š” RequestCache ๊ตฌํ˜„์ฒด์ž…๋‹ˆ๋‹ค. ํŠน์ • ์ƒํ™ฉ์—์„œ ์š”์ฒญ์„ ์ €์žฅํ•˜์ง€ ์•Š์œผ๋ ค๋ฉด NullRequestCache๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์š”์ฒญ์„ ๋ณ„๋„๋กœ ๊ธฐ๋กํ•˜์ง€ ์•Š๊ณ , ์ธ์ฆ ํ›„์— ํ•ญ์ƒ ์ง€์ •๋œ ํŽ˜์ด์ง€(์˜ˆ: ํ™ˆ ํŽ˜์ด์ง€)๋กœ ๋ฆฌ๋””๋ ‰์…˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


NullRequestCache ์„ค์ • ์˜ˆ์ œ ์ฝ”๋“œ

@Bean
SecurityFilterChain springSecurity(HttpSecurity http) throws Exception {
    RequestCache nullRequestCache = new NullRequestCache();
    http
        .requestCache((cache) -> cache
            .requestCache(nullRequestCache) // NullRequestCache๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์š”์ฒญ์„ ์ €์žฅํ•˜์ง€ ์•Š๋„๋ก ์„ค์ •
        );
    return http.build();
}

๐Ÿ“‹ ์ฝ”๋“œ ์„ค๋ช…

  1. NullRequestCache ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ
    • NullRequestCache ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜์—ฌ, ์ธ์ฆ๋˜์ง€ ์•Š์€ ์š”์ฒญ์„ ์„ธ์…˜์— ์ €์žฅํ•˜์ง€ ์•Š๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
  2. HttpSecurity ์„ค์ •์—์„œ RequestCache ์ ์šฉ
    • .requestCache((cache) -> cache.requestCache(nullRequestCache))๋ฅผ ํ†ตํ•ด, Spring Security์˜ ๋ณด์•ˆ ์„ค์ •์— NullRequestCache๋ฅผ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค.
    • ์ด๋กœ์จ ์ธ์ฆ๋˜์ง€ ์•Š์€ ์š”์ฒญ์€ ์ €์žฅ๋˜์ง€ ์•Š์œผ๋ฉฐ, ์ธ์ฆ ํ›„ ์›๋ž˜ ์š”์ฒญ์œผ๋กœ ๋Œ์•„๊ฐ€์ง€ ์•Š๊ณ  ์ง€์ •๋œ ๊ธฐ๋ณธ ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋””๋ ‰์…˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์‚ฌ์šฉ ์‚ฌ๋ก€: NullRequestCache ํ™œ์šฉ

  • ํ™ˆ ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋””๋ ‰์…˜
    ์‚ฌ์šฉ์ž๊ฐ€ ์ธ์ฆ๋˜์ง€ ์•Š์€ ์ƒํƒœ์—์„œ ๋ณดํ˜ธ๋œ ์ž์›์— ์ ‘๊ทผํ•˜๋”๋ผ๋„, ์›๋ž˜ ์š”์ฒญ์„ ์ €์žฅํ•˜์ง€ ์•Š๊ณ  ํ•ญ์ƒ ํ™ˆ ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋””๋ ‰์…˜๋˜๋„๋ก ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋‹ค๋ฅธ ์ €์žฅ ๋ฐฉ์‹ ์‚ฌ์šฉ
    ์š”์ฒญ์„ ์„ธ์…˜์ด ์•„๋‹Œ ๋ธŒ๋ผ์šฐ์ €์˜ ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€๋‚˜ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ €์žฅํ•˜๋ ค๊ณ  ํ•  ๋•Œ, NullRequestCache๋ฅผ ์„ค์ •ํ•˜์—ฌ ์„ธ์…˜์— ์ €์žฅ๋˜์ง€ ์•Š๋„๋ก ํ•ฉ๋‹ˆ๋‹ค. ์ดํ›„ ๋งž์ถคํ˜• ๋กœ์ง์œผ๋กœ ์š”์ฒญ์„ ๋ณต๊ตฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ“ NullRequestCache ์„ค์ •์˜ ์žฅ์ 

  • ์š”์ฒญ ์ €์žฅ ๋ฐฉ์ง€: ์ธ์ฆ๋˜์ง€ ์•Š์€ ์š”์ฒญ์„ ๋”ฐ๋กœ ์ €์žฅํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์—, ๋ถˆํ•„์š”ํ•œ ์„ธ์…˜ ๋ฐ์ดํ„ฐ์˜ ์ฆ๊ฐ€๋ฅผ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์ปค์Šคํ…€ ๋ฆฌ๋””๋ ‰์…˜: ์ธ์ฆ ํ›„ ์›๋ž˜ ์š”์ฒญ์„ ์ฐธ์กฐํ•˜์ง€ ์•Š๊ณ  ํ•ญ์ƒ ํŠน์ • ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•˜๋„๋ก ์„ค์ •ํ•˜์—ฌ ์ผ๊ด€๋œ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

NullRequestCache๋ฅผ ํ†ตํ•ด ์„ธ์…˜์— ์š”์ฒญ์„ ์ €์žฅํ•˜์ง€ ์•Š๋„๋ก ์„ค์ •ํ•จ์œผ๋กœ์จ, Spring Security๊ฐ€ ์ธ์ฆ ํ›„ ํŠน์ • ํŽ˜์ด์ง€๋กœ ์ผ๊ด€๋˜๊ฒŒ ๋ฆฌ๋””๋ ‰์…˜ํ•˜๊ฑฐ๋‚˜ ๋‹ค๋ฅธ ์ €์žฅ ๋ฐฉ์‹์„ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๐Ÿ›ก๏ธ


๐Ÿ› ๏ธ RequestCacheAwareFilter: ์ธ์ฆ ํ›„ ์›๋ž˜ ์š”์ฒญ ์ž๋™ ์ ‘๊ทผ

RequestCacheAwareFilter๋Š” Spring Security์—์„œ ์ธ์ฆ ์™„๋ฃŒ ํ›„, ์ธ์ฆ ์ „ ์š”์ฒญํ–ˆ๋˜ ์ž์›์— ์ž๋™์œผ๋กœ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ฃผ๋Š” ํ•„ํ„ฐ์ž…๋‹ˆ๋‹ค. ์ด ํ•„ํ„ฐ๋Š” RequestCache์— ์ €์žฅ๋œ ์›๋ž˜ ์š”์ฒญ์„ ๋ถˆ๋Ÿฌ์™€ ๋‹ค์‹œ ์ฒ˜๋ฆฌํ•˜์—ฌ, ์‚ฌ์šฉ์ž๊ฐ€ ์ธ์ฆ ์ „์— ์š”์ฒญํ–ˆ๋˜ ์ž์›์œผ๋กœ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋ณต๊ท€ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.


RequestCacheAwareFilter์˜ ์ฃผ์š” ์—ญํ• 

  1. RequestCache์—์„œ ์›๋ž˜ ์š”์ฒญ ํ™•์ธ ๋ฐ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ

    • RequestCacheAwareFilter๋Š” ์ธ์ฆ์ด ์™„๋ฃŒ๋œ ํ›„ RequestCache์— ์ €์žฅ๋œ ์š”์ฒญ์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
    • ์ €์žฅ๋œ ์š”์ฒญ์ด ์žˆ์œผ๋ฉด ํ•ด๋‹น ์š”์ฒญ์„ ๊ฐ€์ ธ์™€ ํ•„ํ„ฐ ์ฒด์ธ์„ ํ†ตํ•ด ๋‹ค์‹œ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
  2. ์ž๋™ ์ ‘๊ทผ ๊ธฐ๋Šฅ

    • RequestCacheAwareFilter๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์ธ์ฆ ํ›„ ์›๋ž˜ ์š”์ฒญํ•œ ์ž์›์— ์ž๋™์œผ๋กœ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋„๋ก ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.
    • ์ด๋ฅผ ํ†ตํ•ด ์‚ฌ์šฉ์ž๋Š” ์ธ์ฆ ๊ณผ์ • ํ›„์—๋„ ์ž์› ์ ‘๊ทผ ํ๋ฆ„์„ ์ค‘๋‹จํ•˜์ง€ ์•Š๊ณ  ์›๋ž˜ ์š”์ฒญํ•œ ํŽ˜์ด์ง€๋กœ ๋งค๋„๋Ÿฝ๊ฒŒ ์ด๋™ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

RequestCacheAwareFilter์˜ ๋™์ž‘ ๊ณผ์ • ์˜ˆ์‹œ

  1. ๋ณดํ˜ธ๋œ ํŽ˜์ด์ง€ ์ ‘๊ทผ ์‹œ๋„ ๋ฐ ์ธ์ฆ ์š”์ฒญ

    • ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์ธํ•˜์ง€ ์•Š์€ ์ƒํƒœ์—์„œ /protected/resource ํŽ˜์ด์ง€์— ์ ‘๊ทผํ•˜๋ฉด Spring Security๋Š” ์ธ์ฆ ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๊ณ , ExceptionTranslationFilter๊ฐ€ ์ด๋ฅผ ๊ฐ์ง€ํ•˜์—ฌ ์ธ์ฆ์„ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.
  2. ์›๋ž˜ ์š”์ฒญ ์ €์žฅ

    • RequestCache (์˜ˆ: HttpSessionRequestCache)๊ฐ€ ์›๋ž˜ ์š”์ฒญ(/protected/resource)์„ ์„ธ์…˜์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.
  3. ์‚ฌ์šฉ์ž ์ธ์ฆ ์™„๋ฃŒ ํ›„

    • ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์ธํ•˜์—ฌ ์ธ์ฆ์— ์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค.
  4. RequestCacheAwareFilter๊ฐ€ ์›๋ž˜ ์š”์ฒญ ํ™•์ธ ๋ฐ ์žฌ์‹คํ–‰

    • RequestCacheAwareFilter๊ฐ€ RequestCache์— ์ €์žฅ๋œ ์›๋ž˜ ์š”์ฒญ์„ ํ™•์ธํ•˜๊ณ , ํ•ด๋‹น ์š”์ฒญ์„ ๋‹ค์‹œ ์ฒ˜๋ฆฌํ•˜๋„๋ก ํ•„ํ„ฐ ์ฒด์ธ์„ ํ†ตํ•ด ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.
    • ์ด๋กœ์จ ์‚ฌ์šฉ์ž๋Š” ๋กœ๊ทธ์ธ ํ›„ ์›๋ž˜ ์š”์ฒญํ•œ ํŽ˜์ด์ง€์— ์ž๋™์œผ๋กœ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

RequestCacheAwareFilter์˜ ์žฅ์ 

  • ์›๋ž˜ ์š”์ฒญ์œผ๋กœ ๋งค๋„๋Ÿฌ์šด ๋ณต๊ท€
    RequestCacheAwareFilter๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์ธ์ฆ ํ›„ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์›๋ž˜ ์š”์ฒญํ•œ ์ž์›์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜์—ฌ, ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ๋งค๋„๋Ÿฝ๊ฒŒ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.

  • ์ž๋™ ์š”์ฒญ ์‹คํ–‰
    ์ธ์ฆ ํ›„ ๋ณ„๋„์˜ ์กฐ์ž‘ ์—†์ด RequestCache์— ์ €์žฅ๋œ ์›๋ž˜ ์š”์ฒญ์„ ์ž๋™์œผ๋กœ ์‹คํ–‰ํ•˜์—ฌ, ์ผ๊ด€๋œ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.


๐Ÿ“ ์š”์•ฝ

RequestCacheAwareFilter๋Š” RequestCache์— ์ €์žฅ๋œ ์›๋ž˜ ์š”์ฒญ์„ ์ธ์ฆ ํ›„ ์ž๋™์œผ๋กœ ๋ถˆ๋Ÿฌ์™€ ๋‹ค์‹œ ์‹คํ–‰ํ•˜์—ฌ, ์‚ฌ์šฉ์ž๊ฐ€ ์ธ์ฆ ์ „์— ์š”์ฒญํ–ˆ๋˜ ์ž์›์œผ๋กœ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋ณต๊ท€ํ•  ์ˆ˜ ์žˆ๋„๋ก ์ง€์›ํ•˜๋Š” ์ค‘์š”ํ•œ ํ•„ํ„ฐ์ž…๋‹ˆ๋‹ค. ์ด๋กœ ์ธํ•ด ์‚ฌ์šฉ์ž๋Š” ์ธ์ฆ ํ›„์—๋„ ์›๋ž˜ ์š”์ฒญํ•œ ์ž์›์— ์ค‘๋‹จ ์—†์ด ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์–ด, ๋งค๋„๋Ÿฌ์šด ๋ณด์•ˆ ํ๋ฆ„๊ณผ ์ผ๊ด€๋œ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๐Ÿ›ก๏ธ


๐Ÿ› ๏ธ Spring Security ๋กœ๊ทธ ๊ธฐ๋Šฅ: ๋ณด์•ˆ ์ด๋ฒคํŠธ ์ถ”์ ๊ณผ ๋ฌธ์ œ ํ•ด๊ฒฐ

Spring Security๋Š” ๋ณด์•ˆ ๊ด€๋ จ ์ด๋ฒคํŠธ์— ๋Œ€ํ•ด ํฌ๊ด„์ ์ธ ๋กœ๊ทธ๋ฅผ ์ œ๊ณตํ•˜์—ฌ, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋””๋ฒ„๊น…ํ•˜๊ฑฐ๋‚˜ ์š”์ฒญ์ด ๊ฑฐ๋ถ€๋œ ์ด์œ ๋ฅผ ์ดํ•ดํ•  ๋•Œ ๋งค์šฐ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. Spring Security๋Š” ๋ณด์•ˆ ์กฐ์น˜๋กœ ์ธํ•ด ๋ฐœ์ƒํ•œ 401 ๋ฐ 403 ์˜ค๋ฅ˜์˜ ์„ธ๋ถ€ ์ •๋ณด๋ฅผ ์‘๋‹ต ๋ณธ๋ฌธ์— ํฌํ•จํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์—, ๋กœ๊ทธ๋ฅผ ํ†ตํ•ด ๋ฌด์Šจ ์ผ์ด ๋ฐœ์ƒํ–ˆ๋Š”์ง€ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


๋กœ๊ทธ์˜ ์ค‘์š”์„ฑ: CSRF ์˜ˆ์‹œ

์˜ˆ๋ฅผ ๋“ค์–ด, ์‚ฌ์šฉ์ž๊ฐ€ CSRF ๋ณดํ˜ธ๊ฐ€ ํ™œ์„ฑํ™”๋œ ์ž์›์— CSRF ํ† ํฐ ์—†์ด POST ์š”์ฒญ์„ ์‹œ๋„ํ•˜๋Š” ๊ฒฝ์šฐ๋ฅผ ๊ฐ€์ •ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

  • ๋กœ๊ทธ ๋น„ํ™œ์„ฑํ™” ์‹œ: ์‚ฌ์šฉ์ž๋Š” ๋‹จ์ˆœํžˆ 403 ์˜ค๋ฅ˜๋งŒ ๋ณด๊ฒŒ ๋˜์–ด ์š”์ฒญ์ด ๊ฑฐ๋ถ€๋œ ์ด์œ ๋ฅผ ์•Œ๊ธฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค.
  • ๋กœ๊ทธ ํ™œ์„ฑํ™” ์‹œ: DEBUG ๋ฐ TRACE ๋กœ๊ทธ ์ˆ˜์ค€์—์„œ CSRF ํ† ํฐ ๊ฒ€์‚ฌ๊ฐ€ ์‹คํŒจํ–ˆ์Œ์„ ๋ณด์—ฌ์ฃผ๋Š” ์ƒ์„ธํ•œ ๋ฉ”์‹œ์ง€๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ์‹œ ๋กœ๊ทธ

Securing POST /hello
... (๋‹ค์–‘ํ•œ ํ•„ํ„ฐ ํ˜ธ์ถœ)
Invalid CSRF token found for http://localhost:8080/hello
Responding with 403 status code

๋กœ๊ทธ ํ•ด์„

  1. Securing POST /hello

    • /hello ๊ฒฝ๋กœ์— ๋Œ€ํ•œ POST ์š”์ฒญ ๋ณดํ˜ธ๊ฐ€ ์‹œ์ž‘๋˜์—ˆ์Œ์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.
  2. ์—ฌ๋Ÿฌ ํ•„ํ„ฐ ํ˜ธ์ถœ

    • DisableEncodeUrlFilter, WebAsyncManagerIntegrationFilter, SecurityContextHolderFilter, HeaderWriterFilter, CsrfFilter ๋“ฑ ์—ฌ๋Ÿฌ ํ•„ํ„ฐ๊ฐ€ ์š”์ฒญ์„ ๋ณดํ˜ธํ•˜๊ธฐ ์œ„ํ•ด ์ˆœ์„œ๋Œ€๋กœ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.
  3. Invalid CSRF token found

    • CsrfFilter๊ฐ€ ์œ ํšจํ•˜์ง€ ์•Š์€ CSRF ํ† ํฐ์„ ๋ฐœ๊ฒฌํ•˜์—ฌ ์š”์ฒญ์ด ๊ฑฐ๋ถ€๋˜์—ˆ์Œ์„ ์•Œ๋ฆฝ๋‹ˆ๋‹ค.
  4. Responding with 403 status code

    • AccessDeniedHandlerImpl์ด 403 ์ƒํƒœ ์ฝ”๋“œ๋กœ ์‘๋‹ตํ•˜๊ณ  ์žˆ์Œ์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.

์ด ๋กœ๊ทธ ๋ฉ”์‹œ์ง€๋ฅผ ํ†ตํ•ด CSRF ํ† ํฐ์ด ์—†์–ด์„œ ์š”์ฒญ์ด ๊ฑฐ๋ถ€๋œ ์ด์œ ๋ฅผ ๋ช…ํ™•ํžˆ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


๐Ÿ”ง Spring Security์˜ ๋กœ๊น… ํ™œ์„ฑํ™” ์„ค์ •

Spring Security์˜ ๋ชจ๋“  ๋ณด์•ˆ ์ด๋ฒคํŠธ๋ฅผ ๊ธฐ๋กํ•˜๋ ค๋ฉด, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„ค์ • ํŒŒ์ผ์— ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์„ค์ •์„ ์ถ”๊ฐ€ํ•˜์„ธ์š”.

logging.level.org.springframework.security=DEBUG
logging.level.org.springframework.security.web.FilterChainProxy=TRACE
  • logging.level.org.springframework.security=DEBUG
    Spring Security์˜ ๋ณด์•ˆ ์ด๋ฒคํŠธ๋ฅผ DEBUG ์ˆ˜์ค€์—์„œ ๊ธฐ๋กํ•ฉ๋‹ˆ๋‹ค.

  • logging.level.org.springframework.security.web.FilterChainProxy=TRACE
    ๋ณด์•ˆ ํ•„ํ„ฐ ์ฒด์ธ์˜ ์ƒ์„ธ ๋กœ๊ทธ๋ฅผ TRACE ์ˆ˜์ค€์—์„œ ๊ธฐ๋กํ•˜์—ฌ, ํ•„ํ„ฐ์˜ ํ˜ธ์ถœ ์ˆœ์„œ์™€ ๋™์ž‘์„ ์ƒ์„ธํžˆ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


๐Ÿ“ ์š”์•ฝ

Spring Security์˜ ๋กœ๊ทธ ๊ธฐ๋Šฅ์„ ํ†ตํ•ด ๋ณด์•ˆ ์ด๋ฒคํŠธ์— ๋Œ€ํ•œ ์ƒ์„ธ ์ •๋ณด๋ฅผ ํ™•์ธํ•˜๊ณ , ๋ฌธ์ œ๋ฅผ ๋ณด๋‹ค ๋น ๋ฅด๊ฒŒ ์ง„๋‹จํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. DEBUG ๋ฐ TRACE ๋กœ๊ทธ๋Š” ๋ณด์•ˆ ์š”์ฒญ์ด ๊ฑฐ๋ถ€๋œ ์ด์œ ์™€ ๋ณด์•ˆ ํ•„ํ„ฐ ์ฒด์ธ์˜ ๋™์ž‘์„ ์ƒ์„ธํžˆ ๋ณด์—ฌ์ฃผ์–ด, ํŠนํžˆ CSRF ์˜ค๋ฅ˜์™€ ๊ฐ™์€ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. ๐Ÿ›ก๏ธ

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