Post

[Security] Secure Coding(5-2) - OAuth2

[Security] Secure Coding(5-2) - OAuth2

๐Ÿ”’ ์‹œํ์–ด ์ฝ”๋”ฉ ์ˆ˜์—… ์ •๋ฆฌ

OAuth2

๐Ÿ“šOAuth2: ์‚ฌ์šฉ์ž ์ธ์ฆ(Authentication)๊ณผ ๊ถŒํ•œ ๋ถ€์—ฌ(Authorization)๋ฅผ ๋ถ„๋ฆฌํ•˜์—ฌ, ์ œ3์ž ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์‚ฌ์šฉ์ž์˜ ์ž์›(Resource)์— ์•ˆ์ „ํ•˜๊ฒŒ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋„๋ก ์ง€์›ํ•˜๋Š” ํ”„๋กœํ† ์ฝœ

  • ๋ณต์žกํ•œ ์•”ํ˜ธํ™”๋‚˜ ์„œ๋ช… ์—†์ด๋„ HTTPS ์—ฐ๊ฒฐ๋งŒ์œผ๋กœ ์•ก์„ธ์Šค ํ† ํฐ์„ ์ฃผ๊ณ ๋ฐ›์•„ ๊ถŒํ•œ์„ ์œ„์ž„ํ•  ์ˆ˜ ์žˆ๋‹ค
  • ๊ฐ€๋ณ๊ณ , ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ํ™˜๊ฒฝ์— ๊ตฌ์• ๋ฐ›์ง€ ์•Š๋Š” ์œ ์—ฐ์„ฑ์„ ํ™•๋ณด, ๊ตฌํ˜„ ๋‚œ์ด๋„๋ฅผ ํฌ๊ฒŒ ๋‚ฎ์ถค

  • ์˜ˆ: ์–ด๋–ค ์‡ผํ•‘๋ชฐ์—์„œ โ€˜๊ตฌ๊ธ€ ๊ณ„์ •์œผ๋กœ ๋กœ๊ทธ์ธโ€™ ๋ฒ„ํŠผ์„ ๋ˆŒ๋ €์„ ๋•Œ ์‡ผํ•‘๋ชฐ ์‚ฌ์ดํŠธ๊ฐ€ ์—ฌ๋Ÿฌ๋ถ„์˜ ๊ตฌ๊ธ€ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์•Œ๊ณ  ์žˆ์ง€ ์•Š์ง€๋งŒ, ๊ตฌ๊ธ€ ์ธ์ฆ ์„œ๋ฒ„๊ฐ€ ์‚ฌ์šฉ์ž๋ฅผ ๋Œ€์‹ ํ•ด ๋ฐœ๊ธ‰ํ•ด ์ค€ ์•ก์„ธ์Šค ํ† ํฐ๋งŒ ์ „๋‹ฌ๋ฐ›์•„, ์ด๋ฉ”์ผ ์ฃผ์†Œ๋‚˜ ํ”„๋กœํ•„ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ํ๋ฆ„

OAuth2 ๊ตฌ์„ฑ ์š”์†Œ

alt text

alt text

Client Application (ํด๋ผ์ด์–ธํŠธ)

  • ์—ญํ• : ์‚ฌ์šฉ์ž๋ฅผ ๋Œ€์‹ ํ•ด ๋ฆฌ์†Œ์Šค์— ์ ‘๊ทผํ•˜๋ ค๋Š” ์•ฑ/์›น์‚ฌ์ดํŠธ
  • ์‹๋ณ„์ •๋ณด: Client ID (๊ณต๊ฐœ), Client Secret (๋น„๋ฐ€ ํ‚ค)

โœ…์ฃผ์š” ๋™์ž‘:

  • ๊ถŒํ•œ ์„œ๋ฒ„์— ์ธ์ฆ ์š”์ฒญ
  • Authorization Code ๋ฐ›์Œ
  • Access Token ์š”์ฒญ ๋ฐ ์ˆ˜์‹ 
  • API ํ˜ธ์ถœ

Resource Owner (๋ฆฌ์†Œ์Šค ์†Œ์œ ์ž)

  • ์—ญํ• : ์‹ค์ œ ๋ฐ์ดํ„ฐ์˜ ์ฃผ์ธ = ์‚ฌ์šฉ์ž(๋‹น์‹ )

โœ…์ฃผ์š” ๋™์ž‘:

  • ๊ถŒํ•œ ์„œ๋ฒ„์˜ ๋กœ๊ทธ์ธ ์ฐฝ์—์„œ ์ธ์ฆ
  • ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์š”์ฒญํ•œ ๊ถŒํ•œ์— ๋™์˜/๊ฑฐ๋ถ€

  • ์ค‘์š”: ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ํด๋ผ์ด์–ธํŠธ์— ์ฃผ์ง€ ์•Š๊ณ , ๊ถŒํ•œ ์„œ๋ฒ„์—๋งŒ ์ž…๋ ฅ

Authorization Server (๊ถŒํ•œ ์„œ๋ฒ„)

  • ์—ญํ• : ์‚ฌ์šฉ์ž ์ธ์ฆ + ํ† ํฐ ๋ฐœ๊ธ‰

โœ…์ฃผ์š” ๋™์ž‘:

  • ์‚ฌ์šฉ์ž ๋กœ๊ทธ์ธ ํ™•์ธ
  • Authorization Code ๋ฐœ๊ธ‰ (์ž„์‹œ ์ฝ”๋“œ)
  • Access Token ๋ฐœ๊ธ‰ (์งง์€ ์œ ํšจ๊ธฐ๊ฐ„, ์‹ค์ œ API ํ˜ธ์ถœ์šฉ)
  • Refresh Token ๋ฐœ๊ธ‰ (๊ธด ์œ ํšจ๊ธฐ๊ฐ„, ํ† ํฐ ๊ฐฑ์‹ ์šฉ)

  • ๊ฒ€์ฆ: Client ID/Secret ํ™•์ธ, Scope ๊ฒ€์ฆ

Resource Server (๋ฆฌ์†Œ์Šค ์„œ๋ฒ„)

  • ์—ญํ• : ์‹ค์ œ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๊ณ  API ์ œ๊ณต

โœ…์ฃผ์š” ๋™์ž‘:

  • Access Token์ด ์œ ํšจํ•œ๊ฐ€?
  • Token์˜ scope์— ์ด API ์ ‘๊ทผ ๊ถŒํ•œ์ด ์žˆ๋Š”๊ฐ€?
  • Token์ด ๋งŒ๋ฃŒ๋˜์ง€ ์•Š์•˜๋Š”๊ฐ€?

  • ๋™์ž‘: ๊ฒ€์ฆ ํ†ต๊ณผ ์‹œ โ†’ ๋ฐ์ดํ„ฐ ๋ฐ˜ํ™˜

OAuth2 ์ธ์ฆ ํ๋ฆ„: Authorization Code Grant

alt text

  1. ์‚ฌ์šฉ์ž: ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์„œ๋น„์Šค ์ ‘์† ์‹œ๋„
  2. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜: ๊ทธ ์ฆ‰์‹œ ๊ถŒํ•œ ์„œ๋ฒ„์˜ ์ธ์ฆ ์š”์ฒญ ํŽ˜์ด์ง€๋ฅผ ๋„์šฐ๋„๋ก redirect
  3. ๊ถŒํ•œ ์„œ๋ฒ„: redirect๋œ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€์—์„œ ์ •๋ณด ์ž…๋ ฅ ์š”์ฒญ
  4. ์‚ฌ์šฉ์ž: ๋กœ๊ทธ์ธ ์ •๋ณด ์ž…๋ ฅ ๋ฐ ๊ถŒํ•œ โ€˜ํ—ˆ์šฉโ€™
  5. ๊ถŒํ•œ ์„œ๋ฒ„: Authirization code, ์ฆ‰ ์ธ๊ฐ€ ์ฝ”๋“œ๋ฅผ ๋ฐœ๊ธ‰ํ•˜์—ฌ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์ „๋‹ฌ
  6. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜: ๋ฐ›์€ ์ธ๊ฐ€ ์ฝ”๋“œ ๊ธฐ๋ฐ˜์œผ๋กœ ๋ฆฌ์†Œ์Šค ์„œ๋ฒ„ ์•ก์„ธ์Šค ํ† ํฐ(Access Token) ์š”์ฒญ์„ ๊ถŒํ•œ ์„œ๋ฒ„์— ๋ณด๋‚ธ๋‹ค
    • ์ด๋•Œ Client Secret๊ณผ ํ•จ๊ป˜ ์ธ๊ฐ€ ์ฝ”๋“œ๋ฅผ ์ „์†กํ•ด์„œ ์ž์‹ ์„ ์ธ์ฆ
  7. ๊ถŒํ•œ ์„œ๋ฒ„: ์ด๋ฅผ ๊ฒ€์ฆํ•˜๊ณ  Access Token์„ ๋ฐœ๊ธ‰
  8. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜: ๋ฐœ๊ธ‰๋ฐ›์€ Access Token์œผ๋กœ ๋ฆฌ์†Œ์Šค ์„œ๋ฒ„์— ํ•„์š”ํ•œ ์‚ฌ์šฉ์ž ๋ฆฌ์†Œ์Šค ์š”์ฒญ
  9. ๋ฆฌ์†Œ์Šค ์„œ๋ฒ„: ๋ฐฉ๊ธˆ ๋ฐœ๊ธ‰ ๋ฐ›์€ Access Token์ด ๋งž๋Š”์ง€ ๊ถŒํ•œ์„œ๋ฒ„์™€ ํฌ๋กœ์Šค ์ฒดํฌ
  10. ์œ ํšจํ•˜๋ฉด OK ์‘๋‹ต ๋ฐ›์Œ
  11. ๋ฆฌ์†Œ์Šค ์„œ๋ฒ„: ์š”์ฒญํ•œ ๋ฆฌ์†Œ์Šค ์ œ๊ณต
  12. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜: ์„œ๋น„์Šค ์ด์šฉ ํ™”๋ฉด ๋ Œ๋”๋ง ํ›„ ์‚ฌ์šฉ์ž์—๊ฒŒ ์„œ๋น„์Šค ์ œ๊ณต

alt text

์ธ์ฆ ํ๋ฆ„์˜ ์‹œํ€€์Šค ๋‹ค์ด์–ด๊ทธ๋žจ


OAuth2์˜ ์žฅ๋‹จ์ 

โœ…์žฅ์ :

  1. ๋น„๋ฐ€๋ฒˆํ˜ธ ๋…ธ์ถœ ์œ„ํ—˜ ๊ฐ์†Œ
    • ์‚ฌ์šฉ์ž ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ํด๋ผ์ด์–ธํŠธ์— ์ „๋‹ฌ X(๊ถŒํ•œ์„œ๋ฒ„์—์„œ๋งŒ ๊ด€๋ฆฌ) โ†’ ๋ณด์•ˆ์„ฑ ํ–ฅ์ƒ
  2. SSO (Single Sign-On) ์ง€์›
    • ํ•œ ๋ฒˆ์˜ ๋กœ๊ทธ์ธ์œผ๋กœ ์—ฌ๋Ÿฌ App์— ์ ‘๊ทผ ๊ฐ€๋Šฅ โ†’ ํŽธ์˜์„ฑ ํ–ฅ์ƒ
  3. ํ† ํฐ ๊ธฐ๋ฐ˜ ์ธ์ฆ
    • Access Token, Refresh Token์„ ํ™œ์šฉํ•˜์—ฌ ์„ธ์…˜ ๊ด€๋ฆฌ ๋ฐ ๊ถŒํ•œ ๊ฒ€์ฆ์— ํšจ๊ณผ์ 
    • ์œ ํšจ๊ธฐ๊ฐ„์„ ์งง๊ฒŒํ•˜์—ฌ ํ† ํฐ ํƒˆ์ทจ ํ”ผํ•ด ์ตœ์†Œํ™”
  4. ๋‹ค์–‘ํ•œ ํด๋ผ์ด์–ธํŠธ ์ง€์›
    • ์—ฌ๋Ÿฌ ํด๋ผ์ด์–ธํŠธ์— ์œ ์—ฐํ•˜๊ฒŒ ์ ์šฉ ๊ฐ€๋Šฅ, ํ™•์žฅ์„ฑ ํ–ฅ์ƒ
  5. ์™ธ๋ถ€ ์ธ์ฆ ์—ฐ๋™ ์šฉ์ด

OAuth2์˜ ๋‹จ์ 

โŒ๋‹จ์ :

  1. ๊ตฌํ˜„ ๋ณต์žก์„ฑ
    • ๋‹ค์–‘ํ•œ ์ธ์ฆํ๋ฆ„๊ณผ ํ† ํฐ ๊ด€๋ฆฌ๊ฐ€ ๋ณต์žกํ•˜์—ฌ ์ž˜๋ชป ๊ตฌํ˜„ํ•˜๋ฉด ๋ณด์•ˆ ์ทจ์•ฝ์ ์ด ๋ฐœ์ƒ
  2. ํด๋ผ์ด์–ธํŠธ ๋น„๋ฐ€ ๊ด€๋ฆฌ ๋ฌธ์ œ
  3. ํ‘œ์ค€ ํ•ด์„ ์ฐจ์ด
    • OAuth2๋Š” ํ‘œ์ค€ ์ž์ฒด๊ฐ€ ์œ ์—ฐํ•˜๊ฒŒ ๋˜์–ด์žˆ์–ด์„œ ์—ฐ๋™ ์‹œ์Šคํ…œ ๊ฐ„ ๊ตฌํ˜„ ์ฐจ์ด ๋ฐœ์ƒ
  4. ์ถ”๊ฐ€ ๋ณด์•ˆ ๊ณ ๋ ค ํ•„์š”
    • PKCE, ํ† ํฐ ์ทจ์†Œ(Token Revocation), ํƒ€์ž„์Šคํƒฌํ”„/Nonce ๋“ฑ ์ถ”๊ฐ€ ๋ณด์•ˆ ๋Œ€์ฑ…์ด ์—†์œผ๋ฉด ๋ฆฌํ”Œ๋ ˆ์ด ๊ณต๊ฒฉ, ํ† ํฐ ํƒˆ์ทจ ๋“ฑ์˜ ์œ„ํ—˜ ์กด์žฌ
  5. ์„œ๋ฒ„ ๊ฐ„ ์‹ ๋ขฐ ๊ด€๊ณ„ ๊ตฌ์„ฑ ํ•„์š”
  • PKCE: ์ค‘๊ฐ„์ž ๊ณต๊ฒฉ์„ ๋ฐฉ์–ดํ•˜๋Š” ๋ฐฉ์‹ - ์ธ๊ฐ€ ์ฝ”๋“œ ๊ตํ™˜ ๋ณดํ˜ธ
  • Token Revocation: ํ•„์š”ํ•  ๋•Œ ์ด์ „์— ๋ฐœ๊ธ‰๋œ ํ† ํฐ ์ฆ‰์‹œ ๋ฌดํšจํ™” ๊ฐ€๋Šฅ
  • ํƒ€์ž„์Šคํƒฌํ”„/Nonce: ์ผํšŒ์šฉ ๊ฐ’ ์‚ฌ์šฉ - ๊ณผ๊ฑฐ ๊ฐ’ ์žฌ์‚ฌ์šฉ ๊ณต๊ฒฉ ๋ฌดํšจํ™”

OAuth์™€ OAuth2 ๋น„๊ต

alt text


OAuth2 ๊ตฌํ˜„

1. Google Cloud ๊ฐ€์ž…

https://cloud.google.com/apis?hl=ko

2. ์ƒˆ ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ

alt text

3. ์„œ๋น„์Šค ๋™์˜ ๋ฐ ์‹œ์ž‘

alt text

4. ํ”„๋กœ์ ํŠธ ๊ตฌ์„ฑ

  • ์•ฑ ์ •๋ณด > ์•ฑ ์ด๋ฆ„: OAuth2 Test, ์‚ฌ์šฉ์ž ์ง€์› ์ด๋ฉ”์ผ: ๊ฐœ์ธ ๋ฉ”์ผ ์ฃผ์†Œ
  • ๋Œ€์ƒ > ์™ธ๋ถ€ ์„ ํƒ
  • ์—ฐ๋ฝ์ฒ˜ ์ •๋ณด: ๊ฐœ์ธ ๋ฉ”์ผ ์ฃผ์†Œ
  • โ€˜๋งŒ๋“ค๊ธฐโ€™ ๋ฒ„ํŠผ ์„ ํƒ

5. ํด๋ผ์ด์–ธํŠธ ๋งŒ๋“ค๊ธฐ

alt text

6. ๋ฐ์ดํ„ฐ ์•ก์„ธ์Šค ์„ค์ •

alt text

7. ๋Œ€์ƒ ์„ค์ •

  • ๋Œ€์ƒ > ํ…Œ์ŠคํŠธ ์‚ฌ์šฉ์ž > + ADD USERS์— ๋ณธ์ธ ๋ฉ”์ผ ์ฃผ์†Œ ์ž…๋ ฅ

8. ์„ค์ • ํ™•์ธ ๋ฐ ํ…Œ์ŠคํŠธ

alt text

  • ์•„๋ž˜ URL์— ํด๋ผ์ด์–ธํŠธ ID๋ฅผ ๋„ฃ์–ด ๊ตฌ๊ธ€ ๋กœ๊ทธ์ธ ์ฐฝ์ด ๋œจ๋Š”์ง€ ํ™•์ธ
    https://accounts.google.com/o/oauth2/auth?client_id=ํด๋ผ์ด์–ธํŠธID&redirect_uri=http://localhost:8000/login/oauth2/code/google&response_type=code&scope=https://www.googleapis.com/auth/userinfo.email+https://www.googleapis.com/auth/userinfo.profile

9. Authorization Code ๋ฐœ๊ธ‰

  • Google OAuth API ๋“ฑ๋ก ํ•„์š”
  • ์‚ฌ์šฉ์ž๊ฐ€ ๊ตฌ๊ธ€ ๋กœ๊ทธ์ธ์„ ๋งˆ์น˜๊ณ  ๋‚˜๋ฉด redirect_uri์— Authorization Code๋ฅผ ์‘๋‹ตํ•ด ์คŒ

10. LAB ํ™˜๊ฒฝ์— ์†Œ์Šค ์ถ”๊ฐ€ํ•ด์„œ OAuth2 ์—ฐ๋™ ํ…Œ์ŠคํŠธ

alt text

LAB ์†Œ์Šค์ฝ”๋“œ application.properties ์„ค์ • ์ถ”๊ฐ€

alt text

alt text

alt text

  • ์ด์ œ LAB ์ฝ”๋“œ๋ฅผ ์‹คํ–‰์‹œํ‚ค๊ณ  ์•ž์„œ ์‹œ๋„ํ•ด๋ดค๋˜ URL์„ ์ž…๋ ฅํ•˜์—ฌ ๊ตฌ๊ธ€ ๋กœ๊ทธ์ธ ์ฐฝ์ด ๋‚˜ํƒ€๋‚˜๋ฉฐ, ๊ณ„์ •์„ ์„ ํƒํ•˜๊ณ  ์ง„ํ–‰ํ•˜๋ฉด STS ์ฝ˜์†”์— ๋ฉ”์‹œ์ง€๊ฐ€ ์ œ๋Œ€๋กœ ์ถœ๋ ฅ๋˜๋ฉด ์„ฑ๊ณต

alt text

Access Token ๋ฐœ๊ธ‰

alt text

๊ธฐ์กด ์†Œ์…œ๋กœ๊ทธ์ธ ๋ฉ”์„œ๋“œ๋„ ์ˆ˜์ •ํ•˜๊ณ , getAccessToken ๋ฉ”์„œ๋“œ๋„ ์ถ”๊ฐ€

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//Authorization Code๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Access Token ์š”์ฒญ
//restTemplate.exchange()๋ฅผ ์ด์šฉํ•ด Google OAuth ์„œ๋ฒ„์™€ ํ†ต์‹ 

private String getAccessToken(String authorizationCode, String registrationId) {
    String clientId = env.getProperty("oauth2." + registrationId + ".client-id");
    String clientSecret = env.getProperty("oauth2." + registrationId + ".client-secret");
    String redirectUri = env.getProperty("oauth2." + registrationId + ".redirect-uri");

    MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
    params.add("code", authorizationCode);
    params.add("client_id", clientId);
    params.add("client_secret", clientSecret);
    params.add("redirect_uri", redirectUri);
    params.add("grant_type", "authorization_code");

    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

    HttpEntity entity = new HttpEntity(params, headers);
    ResponseEntity<String> response = restTemplate.exchange(tokenUri, HttpMethod.POST, entity, String.class);

    return objectMapper.readTree(response.getBody()).get("access_token").asText();
}
  • Authorization code์™€ ํ•จ๊ป˜ HTTP ์š”์ฒญ์œผ๋กœ ๋ณด๋‚ด์„œ ์•ก์„ธ์Šค ํ† ํฐ์„ ๋ฐ›์•„์˜ค๋Š” ๊ฒƒ์„ ํ™•์ธ

Resource Server์—์„œ ์œ ์ €์ •๋ณด ๋ฐ›๊ธฐ

alt text

1
2
3
4
5
6
7
8
9
10
11
12
//Access Token์„ Authorization: Bearer ํ—ค๋”์— ํฌํ•จํ•˜์—ฌ Google API ํ˜ธ์ถœ.
//์œ ์ € ID, ์ด๋ฉ”์ผ, ์ด๋ฆ„ ๋“ฑ์˜ ์ •๋ณด๋ฅผ ๋ฐ˜ํ™˜.

private JsonNode getUserResource(String accessToken, String registrationId) {
    String resourceUri = env.getProperty("oauth2." + registrationId + ".resource-uri");

    HttpHeaders headers = new HttpHeaders();
    headers.set("Authorization", "Bearer " + accessToken);

    HttpEntity entity = new HttpEntity(headers);
    return restTemplate.exchange(resourceUri, HttpMethod.GET, entity, JsonNode.class).getBody();
}
  • ๊ฒŸ ์œ ์ € ๋ฆฌ์†Œ์Šค๋ผ๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ์ถ”๊ฐ€
  • ๋ฉ”์„œ๋“œ ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด, HTTP ํ—ค๋”์— ๋ฒ ์–ด๋Ÿฌ๋ผ๋Š” ํ‚ค์›Œ๋“œ๋ฅผ ๋„ฃ๊ณ , ์•ก์„ธ์Šค ํ† ํฐ์„ ๋„ฃ์Œ
  • ๊ทธ ์‘๋‹ต ๊ฐ’์€ JSON ํฌ๋งท์œผ๋กœ ์ˆ˜์‹ ๋˜๋ฏ€๋กœ, ์•„์ด๋””, ์ด๋ฉ”์ผ, ๋‹‰๋„ค์ž„ ๋“ฑ์„ ์ ์ ˆํžˆ ์ถ”์ถœํ•˜์—ฌ ์ฝ˜์†”์— ์ถœ๋ ฅํ•จ

์œ ์ € ์ •๋ณด ํ† ๋Œ€๋กœ ๊ณ„์ • ์—ฐ๋™

alt text

1
2
3
4
5
6
7
8
9
10
11
// ์ปจํŠธ๋กค๋Ÿฌ
MemberModel member = checkUserId(email);
if (member == null) {
    throw new RuntimeException("User not found in local DB: " + email);
}

// ์„œ๋น„์Šค
HttpSession session = request.getSession(true);
session.setAttribute("userId", member.getUserId());
session.setAttribute("userName", member.getUserName());
response.setHeader("Set-Cookie", "JSESSIONID=" + session.getId() + "; Path=/; HttpOnly; Secure");

๋กœ๊ทธ์ธ ์„ฑ๊ณต

alt text


OAuth2 ๋ณด์•ˆ ์œ„ํ˜‘ ๋ฐ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•

OAuth2 ๊ตฌํ˜„ ์‹œ ๋ฐœ์ƒ ๊ฐ€๋Šฅํ•œ ์ทจ์•ฝ์ 

  • Redirect URI ๊ฒ€์ฆ ๋ฏธํก - ์ค‘๊ฐ„์— ๊ณต๊ฒฉ์ž๊ฐ€ ๋ผ์–ด๋“ฆ
  • State ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฏธ์‚ฌ์šฉ
    • State ํŒŒ๋ผ๋ฏธํ„ฐ: CSRF ๋ฐฉ์–ด์— ์‚ฌ์šฉํ•˜๋Š” ๋žœ๋ค ํ† ํฐ
  • PKCE ๋ฏธ์ ์šฉ
    • PKCE(Proof Key for Code Exchange): ๋ชจ๋ฐ”์ผ ๋ฐ ๊ณต์šฉ ํด๋ผ์ด์–ธํŠธ์—์„œ Authorization ์ฝ”๋“œ ํƒˆ์ทจ๋ฅผ ๋ง‰๊ธฐ ์œ„ํ•œ ๋ณด์•ˆ ๊ธฐ๋ฒ•

OAuth2 ์ฃผ์š” ์ทจ์•ฝ์  ์‚ฌ๋ก€

  • Authorization Code ํƒˆ์ทจ
    • ์ค‘๊ฐ„์ž ๊ณต๊ฒฉ(MITM)์ด๋‚˜ ์˜คํ”ˆ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ์ทจ์•ฝ์ ์„ ์ด์šฉํ•ด, ์ธ์ฆ ์ฝ”๋“œ๊ฐ€ ํƒˆ์ทจ๋˜์–ด ๋ถ€์ ์ ˆํ•œ ํ† ํฐ ๋ฐœ๊ธ‰ ์œ„ํ—˜
  • Access Token ์œ ์ถœ
    • HTTPS ๋ฏธ์ ์šฉ, ๋ถˆ์•ˆ์ „ํ•œ ํ† ํฐ ์ €์žฅ(์˜ˆ: ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€, ๋ธŒ๋ผ์šฐ์ € ์บ์‹œ ๋“ฑ)์œผ๋กœ ํ† ํฐ ๋…ธ์ถœ ๊ฐ€๋Šฅ
  • ํ† ํฐ ์žฌ์‚ฌ์šฉ ๋ฐ ๋ฆฌํ”Œ๋ ˆ์ด ๊ณต๊ฒฉ
    • ๋งŒ๋ฃŒ๋˜์ง€ ์•Š์€ ํ† ํฐ ๋˜๋Š” ์ค‘๋ณต ์š”์ฒญ ์ฒ˜๋ฆฌ ๋ฏธํก์œผ๋กœ ์ธํ•œ ๋ฆฌํ”Œ๋ ˆ์ด ๊ณต๊ฒฉ, ๋ถ€์ ์ ˆํ•œ ์ ‘๊ทผ ๊ถŒํ•œ ํ–‰์‚ฌ
  • ํด๋ผ์ด์–ธํŠธ ์‹œํฌ๋ฆฟ ๊ด€๋ฆฌ ์ทจ์•ฝ์ 
    • ํด๋ผ์ด์–ธํŠธ ์‹œํฌ๋ฆฟ(Client Secret)์ด ๊ณต๊ฐœ ํด๋ผ์ด์–ธํŠธ์— ๋…ธ์ถœ๋  ๊ฒฝ์šฐ, ์•…์˜์  ์‚ฌ์šฉ์ž๊ฐ€ ํ† ํฐ ๋ฐœ๊ธ‰ ์‹œ๋„ ๊ฐ€๋Šฅ

Access Token ์œ ์ถœ ๋ฐฉ์ง€ ์ „๋žต

  • ์•ˆ์ „ํ•œ ์ „์†ก ๋ฐ ์ €์žฅ
    • HTTPS/TLS ์ ์šฉ
    • ๋ณด์•ˆ ์ฟ ํ‚ค ์‚ฌ์šฉ
  • ํ† ํฐ ๊ด€๋ฆฌ ์ •์ฑ… ๊ฐ•ํ™”
    • ์งง์€ ์œ ํšจ๊ธฐ๊ฐ„
    • Refresh Token ๋„์ž…
    • ํ† ํฐ ์ทจ์†Œ ๋ฐ ์žฌ๋ฐœ๊ธ‰
  • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ณด์•ˆ ๊ฐ•ํ™”
    • XSS ๋ฐฉ์–ด: ์ž…๋ ฅ๊ฐ’ ๊ฒ€์ฆ, ์ธ์ฝ”๋”ฉ ๋ฐ CSP(Content Security Policy) ์ ์šฉ
    • PKCE ์‚ฌ์šฉ: ๊ณต๊ฐœ ํด๋ผ์ด์–ธํŠธ์˜ ๊ฒฝ์šฐ, PKCE ๋„์ž…์œผ๋กœ Authorization Code ํƒˆ์ทจ ๋ฐฉ์ง€
This post is licensed under CC BY 4.0 by the author.