2. CSRF

(1) CSRF์˜ ๊ตฌ์กฐ

1) ์ดํ•ด

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

2) ๊ณต๊ฒฉ ์‹œ๋‚˜๋ฆฌ์˜ค ์˜ˆ์‹œ

[๊ทธ๋ฆผ 2-1] CSRF์˜ ๊ตฌ์กฐ[๊ทธ๋ฆผ 2-1] CSRF์˜ ๊ตฌ์กฐ
[๊ทธ๋ฆผ 2-1] CSRF์˜ ๊ตฌ์กฐ
์ด๋ฉ”์ผ์„ ํ†ตํ•œ ๊ฐœ์ธ์ •๋ณด ๋ณ€๊ฒฝ ์‹œ๋‚˜๋ฆฌ์˜ค
์ด๋ฉ”์ผ์„ ํ†ตํ•œ ๊ฐœ์ธ์ •๋ณด ๋ณ€๊ฒฝ ์‹œ๋‚˜๋ฆฌ์˜ค
  1. ํ”ผํ•ด์ž๊ฐ€ ์›น ์‚ฌ์ดํŠธ์— ๋กœ๊ทธ์ธํ•˜๋ฉด ์ธ์ฆ ์ •๋ณด(์„ธ์…˜ ID, ํ† ํฐ ๋“ฑ)๊ฐ€ ๋ธŒ๋ผ์šฐ์ € ์ €์žฅ์†Œ์— ์ €์žฅ๋จ
  1. ๊ณต๊ฒฉ์ž๋Š” ํ”ผํ•ด์ž์˜ ๋ธŒ๋ผ์šฐ์ € ์ธ์ฆ ์ •๋ณด๋ฅผ ์ด์šฉํ•ด ์‚ฌ์ดํŠธ ๊ฐœ์ธ์ •๋ณด๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ์•…์„ฑ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋งŒ๋“ฆ
  1. ๊ณต๊ฒฉ์ž๋Š” ์œ„ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์›น ํŽ˜์ด์ง€๋‚˜ ํ”„๋กœ๊ทธ๋žจ์œผ๋กœ ์ œ์ž‘ํ•˜๊ณ , ํ”ผํ•ด์ž์—๊ฒŒ ์›น ํŽ˜์ด์ง€ ๋งํฌ๋‚˜ ํ”„๋กœ๊ทธ๋žจ ์ฒจ๋ถ€ํŒŒ์ผ์ด ํฌํ•จ๋œ ์ด๋ฉ”์ผ์„ ๋ฐœ์†กํ•จ
  1. ํ”ผํ•ด์ž๊ฐ€ CSRF ์ทจ์•ฝ์ ์ด ์žˆ๋Š” ์›น ์‚ฌ์ดํŠธ์— ๋กœ๊ทธ์ธํ•œ ์ƒํƒœ๋กœ ๊ณต๊ฒฉ์ž์˜ ์ด๋ฉ”์ผ์„ ์—ด์–ด ๋ด„. ๊ทธ๋ฆฌ๊ณ  ๊ทธ ์•ˆ์˜ ๋งํฌ๋ฅผ ํด๋ฆญํ•˜๊ฑฐ๋‚˜ ์ฒจ๋ถ€ํŒŒ์ผ์„ ๋‹ค์šด๋กœ๋“œ ๋ฐ›์•„ ์‹คํ–‰ํ•จ
  1. ํ”ผํ•ด์ž์˜ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์ž๋™์œผ๋กœ ์•…์„ฑ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‹คํ–‰ํ•ด, ํ”ผํ•ด์ž ๋ชจ๋ฅด๊ฒŒ ์„œ๋ฒ„๋กœ ์š”์ฒญ์„ ์ „์†กํ•จ
  1. ์„œ๋ฒ„๋Š” ์š”์ฒญ์— ํฌํ•จ๋œ ์ธ์ฆ ์ •๋ณด๋ฅผ ํ™•์ธํ•˜์—ฌ ์š”์ฒญ์ž๋ฅผ ์ง์ž‘ํ•˜๊ณ , ์š”์ฒญ์„ ์ •์ƒ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•จ
  1. ๊ฒฐ๊ตญ ์‚ฌ์ดํŠธ ๋‚ด ํ”ผํ•ด์ž์˜ ๊ฐœ์ธ์ •๋ณด๋Š” ๊ณต๊ฒฉ์ž๊ฐ€ ์˜๋„ํ•œ ๋Œ€๋กœ ๋ณ€๊ฒฝ๋จ
์ด ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ ๊ณต๊ฒฉ์ž๋Š” ํ”ผํ•ด์ž์˜ ์ธ์ฆ ์„ธ์…˜์„ ์ง์ ‘ ํƒˆ์ทจํ•˜์ง€ ์•Š์•˜๋‹ค. ์ฆ‰ CSRF๋Š” ํ”ผํ•ด์ž์˜ ๋ธŒ๋ผ์šฐ์ €๋ฅผ ํ†ตํ•œ ๊ฐ„์ ‘์ ์ธ ๋ฐฉ์‹์œผ๋กœ ํ”ผํ•ด์ž์˜ ๊ถŒํ•œ์„ ์œ„์กฐํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.ยนโพ ์ด์ œ ๊ณต๊ฒฉ์ž๋Š” ํ”ผํ•ด์ž๋„ ๋ชจ๋ฅด๋Š” ์ƒˆ์— ์€ํ–‰ ์‚ฌ์ดํŠธ์—์„œ์˜ ์ž”๊ณ  ์ด์ฒด, ์ปค๋ฎค๋‹ˆํ‹ฐ ์‚ฌ์ดํŠธ์—์„œ ๊ฒŒ์‹œ๋ฌผ ์ž‘์„ฑ, ๋ฐ์ดํŒ… ์‚ฌ์ดํŠธ์—์„œ ํ”„๋กœํ•„ ์•…์šฉ ๋“ฑ ๋‹ค์–‘ํ•œ ์•…์˜์ ์ธ ํ–‰์œ„๋ฅผ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

3) XSS์™€ ๋น„๊ต

CSRF๋Š” ์•ž์„œ ์‚ดํŽด๋ณธ XSS์™€ 'ํ”ผํ•ด์ž์˜ ๋ธŒ๋ผ์šฐ์ €์—์„œ ํŠน์ • ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‹คํ–‰ํ•œ๋‹ค'๋Š” ์ ์—์„œ ๊ฐ™๋‹ค. ํ•˜์ง€๋งŒ ๋‘ ๊ณต๊ฒฉ์˜ ๋ชฉ์ ๊ณผ ๋ฐฉ์‹์—๋Š” ์ฐจ์ด๊ฐ€ ์žˆ๋‹ค. XSS๊ฐ€ ์•…์„ฑ ์Šคํฌ๋ฆฝํŠธ ์‹คํ–‰์„ ํ†ตํ•ด ์ง์ ‘์ ์œผ๋กœ ๋ฏผ๊ฐ ์ •๋ณด๋ฅผ ํƒˆ์ทจํ•˜๊ณ  ์•…์šฉยฒโพํ•œ๋‹ค๋ฉด, CSRF๋Š” ๊ธฐ์กด์— ์ธ์ฆ๋œ ํ”ผํ•ด์ž์˜ ์„ธ์…˜์„ ํ†ตํ•ด ๊ฐ„์ ‘์ ์œผ๋กœ๋งŒ ํ–‰๋™ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋•Œ๋ฌธ์— ์ผ๋ฐ˜์ ์œผ๋กœ XSS์˜ ํ”ผํ•ด๊ฐ€ CSRF์˜ ํ”ผํ•ด๋ณด๋‹ค ์‹ฌ๊ฐํ•˜๋‹ค.
๋˜ํ•œ XSS๊ฐ€ ํด๋ผ์ด์–ธํŠธ ์ธก์—์„œ ์‚ฌ์šฉ์ž ์ž…๋ ฅ๊ฐ’์ด ์ ์ ˆํžˆ ์ฒ˜๋ฆฌ๋˜์ง€ ์•Š๋Š” ์ทจ์•ฝ์ ์„ ์ด์šฉํ•œ๋‹ค๋ฉด, CSRF๋Š” ์„œ๋ฒ„ ์ธก์—์„œ ์š”์ฒญ์˜ ์ถœ์ฒ˜๋ฅผ ์ œ๋Œ€๋กœ ๊ฒ€์ฆํ•˜์ง€ ์•Š๋Š” ์ทจ์•ฝ์ ์„ ๋…ธ๋ฆฐ๋‹ค. ๋”ฐ๋ผ์„œ ๊ณต๊ฒฉ ๋ฐฉ์–ด๋„ XSS๋Š” ํด๋ผ์ด์–ธํŠธ, CSRF๋Š” ์„œ๋ฒ„์ธก์˜ ์—ญํ• ์ด๋ผ ํ•  ์ˆ˜ ์žˆ๋‹ค.
์ถ”๊ฐ€๋กœ, ๋‘ ๊ณต๊ฒฉ ๋ฐฉ์‹์ด ์™„์ „ํžˆ ๋…๋ฆฝ์ ์ด์ง€๋งŒ์€ ์•Š๋‹ค. XSS ์ทจ์•ฝ์ ์„ ์ด์šฉํ•˜์—ฌ CSRF ๊ณต๊ฒฉ์„ ์‹œ๋„ํ•˜๋Š” ๋ณตํ•ฉ์ ์ธ ๋ฐฉ๋ฒ•์ด ์กด์žฌํ•˜๋Š”๋ฐ, ์ด๋Ÿฌํ•œ ๋ณตํ•ฉ ๊ณต๊ฒฉ์€ XSS์˜ ์ง์ ‘์ ์ธ ์œ„ํ—˜์„ฑ๊ณผ CSRF์˜ ์€๋ฐ€ํ•จ์„ ๊ฒฐํ•ฉํ•˜์—ฌ ๋”์šฑ ๊ฐ•๋ ฅํ•˜๊ณ  ํƒ์ง€ํ•˜๊ธฐ ์–ด๋ ค์šด ์œ„ํ˜‘์ด ๋œ๋‹ค. ์ด์ฒ˜๋Ÿผ ์›น ๋ณด์•ˆ์—์„œ ๋‹ค์–‘ํ•œ ์ทจ์•ฝ์ ๋“ค์€ ์„œ๋กœ ์—ฐ๊ด€๋˜์–ด ์žˆ์–ด ๊ฐ๊ฐ์„ ๊ฐœ๋ณ„์ ์œผ๋กœ ๋Œ€์‘ํ•ด์•ผ ํ•  ๋ฟ ์•„๋‹ˆ๋ผ ์ข…ํ•ฉ์ ์ธ ๋ณด์•ˆ ์ „๋žต์„ ์ˆ˜๋ฆฝํ•ด์•ผ ํ•œ๋‹ค.

ยนโพ ๋ฐ˜๋Œ€๋กœ ํ”ผํ•ด์ž์˜ ์„ธ์…˜ ํ† ํฐ์ด๋‚˜ ์ฟ ํ‚ค ๋“ฑ์„ ์ง์ ‘ ํƒˆ์ทจํ•˜์—ฌ ํ”ผํ•ด์ž๋กœ ์œ„์žฅํ•˜๋Š” ๊ณต๊ฒฉ ๋ฐฉ๋ฒ•์„ ์„ธ์…˜ ํ•˜์ด์žฌํ‚น์ด๋ผ๊ณ  ํ•œ๋‹ค.
ยฒโพ XSS๋ฅผ ์ด์šฉํ•œ ์„ธ์…˜ ํ•˜์ด์žฌํ‚น
ย 

(2) ๋Œ€์ฑ… ๋ฐฉ๋ฒ•

CSRF ์ทจ์•ฝ์ ์˜ ํ•ต์‹ฌ์€ ์„œ๋ฒ„์—์„œ ์š”์ฒญ์˜ ์ถœ์ฒ˜๋ฅผ ์ฒ ์ €ํžˆ ํ™•์ธํ•˜์ง€ ์•Š๊ณ  ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐ ์žˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ CSRF ๋ฐฉ์–ด๋ฅผ ์œ„ํ•ด์„œ๋Š” ์„œ๋ฒ„ ์ธก์—์„œ ์š”์ฒญ์˜ ์ถœ์ฒ˜์™€ ์ •๋‹น์„ฑ์„ ๊ฒ€์ฆํ•˜๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค. ํ”„๋ก ํŠธ์—”๋“œ๋Š” ์ด ๊ณผ์ •์„ ์ดํ•ดํ•˜๊ณ , ํ•„์š”ํ•œ ๊ฒ€์ฆ ์ •๋ณด๋ฅผ ์š”์ฒญ์— ํฌํ•จ์‹œ์ผœ ์„œ๋ฒ„๋ฅผ ๋ณด์กฐํ•˜๋Š” ์—ญํ• ์„ ํ•œ๋‹ค.

1) CSRF ํ† ํฐ(๋™๊ธฐํ™” ํ† ํฐ) ํŒจํ„ด

์„ธ์…˜๋ณ„ ๊ณ ์œ ํ•œ ํ† ํฐ์„ ์ƒ์„ฑํ•ด ์œ ํšจ์„ฑ์„ ๊ฒ€์ฆํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๊ฐ€์žฅ ์ผ๋ฐ˜์ ์ธ CSRF ๋ฐฉ์–ด๋ฒ• ์ค‘ ํ•˜๋‚˜์ด๋‹ค.
์‚ฌ์šฉ์ž ๋กœ๊ทธ์ธ ์‹œ ์„œ๋ฒ„๋Š” ์„ธ์…˜ยนโพ์„ ์‹œ์ž‘ํ•œ๋‹ค. ๊ฐ ์„ธ์…˜๋งˆ๋‹ค ์„œ๋ฒ„๋Š” ๋žœ๋ค ๋ฌธ์ž์—ด์ธ CSRF ํ† ํฐ์„ ์ƒ์„ฑ, ์ €์žฅํ•˜๊ณ  ํด๋ผ์ด์–ธํŠธ์— ์ „๋‹ฌํ•œ๋‹ค. ์ดํ›„ ํด๋ผ์ด์–ธํŠธ ์š”์ฒญ๋งˆ๋‹ค ์ด ํ† ํฐ์„ ํฌํ•จํ•˜๋„๋ก ํ•˜๋ฉด, ์„œ๋ฒ„๋Š” ์ €์žฅ๋œ ํ† ํฐ๊ณผ ์š”์ฒญ์˜ ํ† ํฐ์ด ์ผ์น˜ํ•˜๋Š”์ง€ ๋น„๊ตํ•ด ์š”์ฒญ์˜ ์ •์ƒ ์—ฌ๋ถ€๋ฅผ ๊ฐ€๋ ค๋‚ผ ์ˆ˜ ์žˆ๋‹ค. ์ด ํŒจํ„ด์€ ์„œ๋ฒ„์™€ ํด๋ผ์ด์–ธํŠธ ํ† ํฐ์˜ ๋น„๊ต ๊ณผ์ • ๋•Œ๋ฌธ์— ๋™๊ธฐํ™” ํ† ํฐ ํŒจํ„ด์ด๋ผ๊ณ ๋„ ๋ถ€๋ฅธ๋‹ค.
<form action="/" method="POST"> <input type="hidden" name="CSRF_TOKEN" value="SEcretTOken%1234&5678*90" /> <!-- ๋‹ค๋ฅธ form ์š”์†Œ๋“ค... --> </form>
์œ„์™€ ๊ฐ™์ด HTML์— ํ† ํฐ์„ ์‚ฝ์ž…ํ•˜๊ณ  <form>์„ ์ „์†กํ•œ๋‹ค๋ฉด, ํด๋ผ์ด์–ธํŠธ๋Š” ์š”์ฒญ์— ์ž๋™์œผ๋กœ CSRF ํ† ํฐ์„ ์ฒจ๋ถ€ํ•  ์ˆ˜ ์žˆ๋‹ค. CSRF ํ† ํฐ๊ฐ’์€ ์„ธ์…˜๋งˆ๋‹ค ๋ณ€๊ฒฝ๋˜๋ฏ€๋กœ ๊ณต๊ฒฉ์ž๋Š” ํ† ํฐ๊ฐ’์„ ์•Œ ์ˆ˜ ์—†๊ณ , ์œ ํšจํ•œ CSRF ํ† ํฐ์ด ์ฒจ๋ถ€๋˜์ง€ ์•Š์€ ์š”์ฒญ์€ ์„œ๋ฒ„์—์„œ ์ฐจ๋‹จ๋œ๋‹ค.

2) Double Submit ์ฟ ํ‚ค ํŒจํ„ด

CSRF ํ† ํฐ ํŒจํ„ด์€ ์„ธ์…˜ ๋™์•ˆ ์„œ๋ฒ„์— ํ† ํฐ์„ ์œ ์ง€ํ•ด์•ผ ํ•œ๋‹ค. ์ด ๋ฐฉ์‹์€ ์‚ฌ์ดํŠธ ์ ‘์†์ž๊ฐ€ ๋งŽ์•„ ์„ธ์…˜ ์ •๋ณด๊ฐ€ ์ปค์ง€๋ฉด ์„œ๋ฒ„์— ๋ถ€ํ•˜๊ฐ€ ๋  ์ˆ˜ ์žˆ๋‹ค. ์ด์— ๋Œ€ํ•œ ๋Œ€์•ˆ์œผ๋กœ Double Submit ์ฟ ํ‚ค ํŒจํ„ด์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ํŒจํ„ด์—์„œ ํ† ํฐ ๋‘๊ฐœ์˜ ์ผ์น˜์„ฑ์„ ๊ฒ€์ฆํ•˜๋Š” ๋กœ์ง์€ CSRF ํ† ํฐ ํŒจํ„ด๊ณผ ๋™์ผํ•˜์ง€๋งŒ, ๋‘ ํ† ํฐ์„ ๋ชจ๋‘ ์„œ๋ฒ„๊ฐ€ ์•„๋‹Œ ๋ธŒ๋ผ์šฐ์ €์— ์ €์žฅํ•œ๋‹ค๋Š” ์ ์—์„œ ์„œ๋ฒ„์˜ ๋ถ€ํ•˜๋ฅผ ์ค„์ธ๋‹ค.
์‚ฌ์šฉ์ž ๋กœ๊ทธ์ธ์‹œ ์„œ๋ฒ„๋Š” ๋žœ๋ค ๋ฌธ์ž์—ด ํ† ํฐ์„ ์ƒ์„ฑํ•˜๊ณ  HttpOnly ํ”Œ๋ž˜๊ทธยฒโพ๋ฅผ ์„ค์ •ํ•˜์ง€ ์•Š์€ ์ฟ ํ‚ค์— ๋„ฃ์–ด ํด๋ผ์ด์–ธํŠธ๋กœ ์ „๋‹ฌํ•œ๋‹ค. ์ฟ ํ‚ค๋Š” ๋ธŒ๋ผ์šฐ์ €์— ์ €์žฅ๋˜๋ฉฐ ์ดํ›„ ํด๋ผ์ด์–ธํŠธ ์š”์ฒญ์— ์ž๋™์œผ๋กœ ํฌํ•จ๋œ๋‹ค. ๊ฐœ๋ฐœ์ž๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ด ์ฟ ํ‚ค์˜ ํ† ํฐ ๊ฐ’์„ ์ฝ์–ด์™€ ์š”์ฒญ์˜ ๋ณธ๋ฌธ์ด๋‚˜ ์ปค์Šคํ…€ ํ—ค๋”์— ์ถ”๊ฐ€๋กœ ํฌํ•จ์‹œ์ผœ์•ผ ํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ์„œ๋ฒ„๋Š” ์ฟ ํ‚ค์™€ ์š”์ฒญ์— ํฌํ•จ๋œ ํ† ํฐ์„ ๋น„๊ตํ•ด ์ผ์น˜ ์—ฌ๋ถ€๋ฅผ ๊ฒ€์‚ฌํ•œ๋‹ค. ์ด๋ ‡๊ฒŒ ๋™์ผํ•œ ํ† ํฐ์„ ์ฟ ํ‚ค์™€ ์š”์ฒญ ๋ฐ์ดํ„ฐ์— ์ด์ค‘์œผ๋กœ ๋ณด๋‚ด๊ธฐ ๋•Œ๋ฌธ์— Double Submit(์ด์ค‘ ์ „์†ก) ์ฟ ํ‚ค ํŒจํ„ด์ด๋ผ๊ณ  ํ•œ๋‹ค.
๋ธŒ๋ผ์šฐ์ €์— ์ €์žฅ๋œ ์ฟ ํ‚ค๋Š” SOP(๋™์ผ ์ถœ์ฒ˜ ์ •์ฑ…)์— ์˜ํ•ด ๋‹ค๋ฅธ ๋„๋ฉ”์ธ์—์„œ๋Š” ์ ‘๊ทผํ•  ์ˆ˜ ์—†์œผ๋ฏ€๋กœ CSRF ๊ณต๊ฒฉ์— ์•ˆ์ „ํ•˜๋‹ค. ํ•˜์ง€๋งŒ XSS ๊ณต๊ฒฉ์€ ๋™์ผ ๋„๋ฉ”์ธ์—์„œ ์ผ์–ด๋‚˜๋ฏ€๋กœ SOP์˜ ์ œํ•œ์„ ๋ฐ›์ง€ ์•Š์œผ๋‹ˆ ์ฃผ์˜๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

3) SameSite ์ฟ ํ‚ค ์†์„ฑ ์‚ฌ์šฉ

CSRF๋Š” ๊ต์ฐจ ์‚ฌ์ดํŠธ ์š”์ฒญ์„ ํ†ตํ•ด ๋ธŒ๋ผ์šฐ์ €์˜ ์ธ์ฆ ์ •๋ณด๋ฅผ ์•…์šฉํ•˜๋Š” ๊ณต๊ฒฉ ๋ฐฉ๋ฒ•์ด๋‹ค. ์ธ์ฆ ์ •๋ณด๋กœ ์ฟ ํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๊ฒฝ์šฐ, ์ฟ ํ‚ค์˜ SameSite ์†์„ฑ์„ ์„ค์ •ํ•ด ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๊ต์ฐจ ์‚ฌ์ดํŠธ ์š”์ฒญ์— ์ฟ ํ‚ค๋ฅผ ํฌํ•จ์‹œํ‚ค์ง€ ์•Š๋„๋ก ์ œํ•œํ•  ์ˆ˜ ์žˆ๋‹ค.
/* ์„œ๋ฒ„ ์ธก ์ฝ”๋“œ */ const express = require('express'); const session = require('express-session'); // express ์•ฑ์˜ ์„ธ์…˜ ๊ด€๋ฆฌ์šฉ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ const app = express(); // ์„œ๋ฒ„ ์•ฑ ์ƒ์„ฑ app.use(session({ // ์„ธ์…˜ ๋ฏธ๋“ค์›จ์–ด ์„ค์ • cookie: { sameSite: 'strict', // sameSite ์†์„ฑ ์„ค์ • secure: true // HTTPS ์‚ฌ์šฉ } }));
SameSite ์†์„ฑ์ด ๋™์ผ ์‚ฌ์ดํŠธ๋ฅผ ํŒ๋‹จํ•˜๋Š” ๊ธฐ์ค€์€ eTLD+1(effective Top Level Domain+1)์ด๋‹ค. ์œ ํšจํ•œ ์ตœ์ƒ์œ„ ๋„๋ฉ”์ธ(eTLD)๊ณผ ๊ทธ ์„œ๋ธŒ๋„๋ฉ”์ธ์„ ํฌํ•จํ•˜๋ฏ€๋กœ, ์˜ˆ๋ฅผ ๋“ค์–ด static.example.com๊ณผ api.example.com์€ ๋™์ผ ์‚ฌ์ดํŠธ์ด๊ณ , cross-site.com๋Š” ๊ทธ๋ ‡์ง€ ์•Š์€ ๊ฒƒ์ด๋‹ค.
SameSite์˜ ๊ฐ’์œผ๋กœ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋Š” ์˜ต์…˜์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.
SameSite
์˜๋ฏธ
Strict
๋™์ผํ•œ ์‚ฌ์ดํŠธ ์š”์ฒญ์—์„œ๋งŒ ์ฟ ํ‚ค ํฌํ•จ
Lax(๊ธฐ๋ณธ๊ฐ’)
GET ์š”์ฒญ๊ณผ ์ตœ์ƒ์œ„ ๋ ˆ๋ฒจ ํƒ์ƒ‰์—๋Š” ์ฟ ํ‚ค ํฌํ•จ. ๊ทธ ์™ธ์˜ ๊ต์ฐจ ์‚ฌ์ดํŠธ ์š”์ฒญ์—๋Š” ์ œํ•œ
None
์‚ฌ์ดํŠธ์— ๊ด€๊ณ„์—†์ด ๋ชจ๋“  ์š”์ฒญ์— ์ฟ ํ‚ค ํฌํ•จ

4) Origin ํ—ค๋” ๊ฒ€์‚ฌ

์„œ๋ฒ„์— ๋“ค์–ด์˜จ ์š”์ฒญ์˜ Origin ํ—ค๋”๋ฅผ ๊ฒ€์‚ฌํ•ด์„œ ์ถœ์ฒ˜์˜ ์‹ ๋ขฐ์„ฑ์„ ๊ฒ€์‚ฌํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค. Origin ํ—ค๋”๋Š” ํด๋ผ์ด์–ธํŠธ ์š”์ฒญ์‹œ ๋ธŒ๋ผ์šฐ์ €์— ์˜ํ•ด ์ž๋™์œผ๋กœ ์„ค์ •๋˜๊ณ  JavaScript๋กœ ์กฐ์ž‘ํ•  ์ˆ˜ ์—†์–ด ๋ฏฟ์„ ์ˆ˜ ์žˆ๋Š” ์ •๋ณด๋ฅผ ์ œ๊ณตํ•œ๋‹ค.
/* ์„œ๋ฒ„ ์ธก ์ฝ”๋“œ */ const express = require('express'); const app = express(); // ์„œ๋ฒ„ ์•ฑ ์ƒ์„ฑ app.use((req, res, next) => { // ์ถœ์ฒ˜ ๊ฒ€์ฆ ๋ฏธ๋“ค์›จ์–ด ์„ค์ • const allowedOrigins = ['https://example1.com', 'https://example2.com']; // ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ๋Š” ์ถœ์ฒ˜ ๋ชฉ๋ก const origin = req.headers.origin; if (allowedOrigins.includes(origin)) { next(); } else { res.status(403).json({ error: 'Forbidden - Invalid Origin' }); } });
์ด ๋ฐฉ๋ฒ•์€ ๊ตฌํ˜„์ด ๊ฐ€์žฅ ๊ฐ„๋‹จํ•˜์ง€๋งŒ, ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ๋Š” ์ถœ์ฒ˜ ๋ชฉ๋ก์„ ์ง€์†์ ์œผ๋กœ ๊ด€๋ฆฌํ•ด์•ผ ํ•œ๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ๋‹ค. ๋˜ํ•œ CDN์ด๋‚˜ ํ”„๋ก์‹œ ์„œ๋ฒ„๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ๋Š” ๊ณ ๋ คํ•˜๊ธฐ ๊นŒ๋‹ค๋กœ์›Œ ์ฃผ๋กœ ๋‹ค๋ฅธ CSRF ๋ฐฉ์–ด ๊ธฐ๋ฒ•์˜ ๋ณด์กฐ ์ˆ˜๋‹จ์œผ๋กœ ์‚ฌ์šฉ๋œ๋‹ค.

ยนโพ ์‚ฌ์šฉ์ž์™€ ์„œ๋ฒ„ ๊ฐ„์˜ ์—ฐ๊ฒฐ, ๋˜๋Š” ๊ทธ ์—ฐ๊ฒฐ ์œ ์ง€ ์ƒํƒœ๋ฅผ ์„œ๋ฒ„์— ๊ธฐ๋กํ•œ ๊ฒƒ
ยฒโพ ์ฟ ํ‚ค ์ƒ์„ฑ์‹œ HttpOnly ํ”Œ๋ž˜๊ทธ๋ฅผ ์„ค์ •ํ•˜๋ฉด ์ฟ ํ‚ค์— HTTP(S)๋กœ๋งŒ ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•˜๊ณ  ์Šคํฌ๋ฆฝํŠธ ์–ธ์–ด๋กœ๋Š” ์ ‘๊ทผํ•  ์ˆ˜ ์—†๊ฒŒ ๋œ๋‹ค. ๋ฐ˜๋Œ€๋กœ ์ด ํ”Œ๋ž˜๊ทธ๋ฅผ ์„ค์ •ํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ๊ฐœ๋ฐœ์ž๊ฐ€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค.
ย