Skip to Content

์ธ์ฆ/๊ถŒํ•œ

CSO ์ •์‚ฐ ํฌํ„ธ์˜ ์ธ์ฆ ๊ตฌ์กฐ์™€ ๊ถŒํ•œ ๊ด€๋ฆฌ ๋ฐฉ๋ฒ•์„ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.

์ธ์ฆ ๊ตฌ์กฐ

JWT ๊ธฐ๋ฐ˜ ์ธ์ฆ

ํฌํ„ธ์€ Supabase Auth๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ์ž์ฒด JWT ์ธ์ฆ์„ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.

ํ•ญ๋ชฉ๊ฐ’
๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌjose (Edge Runtime ํ˜ธํ™˜)
์•Œ๊ณ ๋ฆฌ์ฆ˜HS256
์„œ๋ช… ํ‚คํ™˜๊ฒฝ๋ณ€์ˆ˜ JWT_SECRET
๋งŒ๋ฃŒ ์‹œ๊ฐ„24์‹œ๊ฐ„
์ฟ ํ‚ค ์ด๋ฆ„cso_session

JWT ํŽ˜์ด๋กœ๋“œ์—๋Š” UserSession ๊ฐ์ฒด๊ฐ€ ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.

{ id, business_number, company_name, email, is_admin, is_approved, is_test, must_change_password, profile_complete }

๋กœ๊ทธ์ธ ์ ˆ์ฐจ

  1. ์‚ฌ์šฉ์ž๊ฐ€ ์‚ฌ์—…์ž๋ฒˆํ˜ธ(10์ž๋ฆฌ)์™€ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•ฉ๋‹ˆ๋‹ค.
  2. ์„œ๋ฒ„์—์„œ ์‚ฌ์—…์ž๋ฒˆํ˜ธ๋ฅผ ์ •๊ทœํ™”ํ•˜๊ณ (- ์ œ๊ฑฐ), DB์—์„œ ํšŒ์›์„ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค.
  3. bcrypt๋กœ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ๊ฒ€์ฆํ•ฉ๋‹ˆ๋‹ค (Salt Rounds: 12).
  4. ์ธ์ฆ ์„ฑ๊ณต ์‹œ JWT๋ฅผ ์ƒ์„ฑํ•˜๊ณ  httpOnly ์ฟ ํ‚ค์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

๋กœ๊ทธ์ธ ์‹คํŒจ ์ฒ˜๋ฆฌ

์ƒํƒœ์‘๋‹ต ์ฝ”๋“œ๋ฉ”์‹œ์ง€
๋ฏธ๋“ฑ๋ก ์‚ฌ์—…์ž๋ฒˆํ˜ธ401๋“ฑ๋ก๋˜์ง€ ์•Š์€ ์‚ฌ์—…์ž๋ฒˆํ˜ธ์ž…๋‹ˆ๋‹ค
๋น„๋ฐ€๋ฒˆํ˜ธ ๋ถˆ์ผ์น˜401์‹คํŒจ ํšŸ์ˆ˜ ํ‘œ์‹œ (N/15ํšŒ)
๊ณ„์ • ์ž ๊ธˆ (15ํšŒ ์‹คํŒจ)423๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณ€๊ฒฝ ๋งํฌ ์ด๋ฉ”์ผ ์ž๋™ ๋ฐœ์†ก
์Šน์ธ ๋Œ€๊ธฐ403๊ด€๋ฆฌ์ž ์Šน์ธ ํ›„ ๋กœ๊ทธ์ธ ๊ฐ€๋Šฅ

๊ณ„์ • ์ž ๊ธˆ ์‹œ ๋“ฑ๋ก๋œ ์ด๋ฉ”์ผ๋กœ ๋น„๋ฐ€๋ฒˆํ˜ธ ์žฌ์„ค์ • ๋งํฌ๊ฐ€ ์ž๋™ ๋ฐœ์†ก๋ฉ๋‹ˆ๋‹ค.

๋กœ๊ทธ์ธ ํ›„ ๋ถ„๊ธฐ

๋กœ๊ทธ์ธ ์„ฑ๊ณต ํ›„ ์‚ฌ์šฉ์ž ์ƒํƒœ์— ๋”ฐ๋ผ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ๋ฉ๋‹ˆ๋‹ค.

์กฐ๊ฑด์ด๋™ ๊ฒฝ๋กœ์„ค๋ช…
must_change_password: true/change-password๊ด€๋ฆฌ์ž๊ฐ€ ๋น„๋ฐ€๋ฒˆํ˜ธ ์ดˆ๊ธฐํ™”ํ•œ ๊ฒฝ์šฐ
profile_complete: false/complete-profileํšŒ์›์ •๋ณด ๋ฏธ์™„์„ฑ
์ •์ƒ/home์‚ฌ์šฉ์ž ํ™ˆ ๋Œ€์‹œ๋ณด๋“œ

์„ธ์…˜ ๊ด€๋ฆฌ

์ฟ ํ‚ค ์„ค์ •

์˜ต์…˜๊ฐ’์„ค๋ช…
httpOnlytrueJavaScript ์ ‘๊ทผ ์ฐจ๋‹จ (XSS ๋ฐฉ์–ด)
secureํ”„๋กœ๋•์…˜๋งŒ trueHTTPS ์ „์šฉ ์ „์†ก
sameSitelaxCSRF ๊ธฐ๋ณธ ๋ฐฉ์–ด
maxAge86400์ดˆ (24์‹œ๊ฐ„)์ฟ ํ‚ค ๋งŒ๋ฃŒ
path/์ „์ฒด ๊ฒฝ๋กœ ์ ์šฉ

ํด๋ผ์ด์–ธํŠธ ์ƒํƒœ ๋™๊ธฐํ™”

์„œ๋ฒ„ ์ฟ ํ‚ค์™€ ๋ณ„๋„๋กœ localStorage(cso_auth_user ํ‚ค)์— ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ์บ์‹ฑํ•ฉ๋‹ˆ๋‹ค. AuthContext๊ฐ€ ํด๋ผ์ด์–ธํŠธ ๋งˆ์šดํŠธ ์‹œ ์„œ๋ฒ„ ์„ธ์…˜(/api/auth/session)๊ณผ ๋™๊ธฐํ™”ํ•˜์—ฌ Hydration ๋ถˆ์ผ์น˜๋ฅผ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค.

๋กœ๊ทธ์•„์›ƒ

  1. ์„œ๋ฒ„: cso_session ์ฟ ํ‚ค ์‚ญ์ œ
  2. ํด๋ผ์ด์–ธํŠธ: localStorage ํ•ญ๋ชฉ ์‚ญ์ œ + AuthContext ์ดˆ๊ธฐํ™”
  3. ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ

๊ด€๋ฆฌ์ž vs ์ผ๋ฐ˜ํšŒ์›

๊ถŒํ•œ ์ฐจ์ด

๊ธฐ๋Šฅ๊ด€๋ฆฌ์ž์ผ๋ฐ˜ํšŒ์›
์ •์‚ฐ ์กฐํšŒ ๋ฒ”์œ„์ „์ฒด ๋ฐ์ดํ„ฐ์ž๊ธฐ ์—…์ฒด(CSO ๋งค์นญ ๊ธฐ๋ฐ˜)๋งŒ
์—‘์…€ ๋‹ค์šด๋กœ๋“œ ์ œํ•œ์—†์Œ์ผ์ผ 5ํšŒ
/admin/* ์ ‘๊ทผ๊ฐ€๋Šฅ์ ‘๊ทผ ๋ถˆ๊ฐ€
ํšŒ์› ์Šน์ธ/๊ฑฐ๋ถ€๊ฐ€๋Šฅ๋ถˆ๊ฐ€
์ •์‚ฐ์„œ ์—…๋กœ๋“œ๊ฐ€๋Šฅ๋ถˆ๊ฐ€
์ด๋ฉ”์ผ ๋ฐœ์†ก๊ฐ€๋Šฅ๋ถˆ๊ฐ€
์‚ฌ์ดํŠธ ์„ค์ •๊ฐ€๋Šฅ๋ถˆ๊ฐ€

๊ถŒํ•œ ๊ฒ€์ฆ ๋ฐฉ์‹

๋ชจ๋“  ๊ด€๋ฆฌ์ž API๋Š” ์š”์ฒญ ์‹œ JWT์—์„œ is_admin ํ•„๋“œ๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. ๊ด€๋ฆฌ์ž๊ฐ€ ์•„๋‹Œ ๊ฒฝ์šฐ 403 ์‘๋‹ต์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

์ฟ ํ‚ค โ†’ JWT ๊ฒ€์ฆ โ†’ UserSession ์ถ”์ถœ โ†’ is_admin ํ™•์ธ โ†’ ์ฒ˜๋ฆฌ or 403

์ผ๋ฐ˜ํšŒ์›์˜ ์ •์‚ฐ ๋ฐ์ดํ„ฐ ์ ‘๊ทผ์€ cso_matching ํ…Œ์ด๋ธ”์„ ํ†ตํ•ด ํ•„ํ„ฐ๋ง๋ฉ๋‹ˆ๋‹ค. ํšŒ์›์˜ ์‚ฌ์—…์ž๋ฒˆํ˜ธ์™€ ๋งค์นญ๋œ CSO๊ด€๋ฆฌ์—…์ฒด์— ํ•ด๋‹นํ•˜๋Š” ์ •์‚ฐ๋งŒ ์กฐํšŒ๋ฉ๋‹ˆ๋‹ค.

ํšŒ์›๊ฐ€์ž… ์Šน์ธ/๊ฑฐ๋ถ€ ์ ˆ์ฐจ

๊ฐ€์ž… ์‹ ์ฒญ ํ๋ฆ„

  1. CSO ์—…์ฒด ๋‹ด๋‹น์ž๊ฐ€ ํšŒ์›๊ฐ€์ž… ํผ์„ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.
    • ํ•„์ˆ˜: ์‚ฌ์—…์ž๋ฒˆํ˜ธ, ์—…์ฒด๋ช…, ๋Œ€ํ‘œ์ž๋ช…, ์ฃผ์†Œ, ์—ฐ๋ฝ์ฒ˜, ์ด๋ฉ”์ผ, ๋น„๋ฐ€๋ฒˆํ˜ธ
    • ์‚ฌ์—…์ž๋ฒˆํ˜ธ ์ค‘๋ณต ๊ฒ€์‚ฌ ์ž๋™ ์ˆ˜ํ–‰
  2. ๊ฐ€์ž… ์‹ ์ฒญ์ด ์ ‘์ˆ˜๋˜๋ฉด is_approved: false ์ƒํƒœ๋กœ DB์— ์ €์žฅ๋ฉ๋‹ˆ๋‹ค.
  3. ๊ด€๋ฆฌ์ž์—๊ฒŒ ๊ฐ€์ž… ์‹ ์ฒญ ์•Œ๋ฆผ ์ด๋ฉ”์ผ์ด ๋ฐœ์†ก๋ฉ๋‹ˆ๋‹ค.

๊ด€๋ฆฌ์ž ์Šน์ธ/๊ฑฐ๋ถ€ (/admin/members)

ํšŒ์› ๊ด€๋ฆฌ ํŽ˜์ด์ง€์—์„œ ์ „์ฒด ํšŒ์›์„ ์กฐํšŒํ•˜๊ณ  ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

ํ†ต๊ณ„ ์นด๋“œ

ํŽ˜์ด์ง€ ์ƒ๋‹จ์— ํšŒ์› ํ˜„ํ™ฉ์ด ์นด๋“œ๋กœ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

  • ์ „์ฒด ํšŒ์› ์ˆ˜
  • ์Šน์ธ ๋Œ€๊ธฐ ์ˆ˜ (์ฃผํ™ฉ์ƒ‰ ๋ฑƒ์ง€)
  • ์Šน์ธ ์™„๋ฃŒ ์ˆ˜
  • ํ…Œ์ŠคํŠธ ๊ณ„์ • ์ˆ˜

ํšŒ์› ํ•„ํ„ฐ๋ง

  • ์ƒํƒœ๋ณ„: ์ „์ฒด, ์Šน์ธ๋Œ€๊ธฐ, ์Šน์ธ์™„๋ฃŒ
  • ๊ฒ€์ƒ‰: ์—…์ฒด๋ช…, ์‚ฌ์—…์ž๋ฒˆํ˜ธ, ์ด๋ฉ”์ผ๋กœ ๊ฒ€์ƒ‰
  • ์ผ๊ด„ ์ฒ˜๋ฆฌ: ์ฒดํฌ๋ฐ•์Šค๋กœ ์—ฌ๋Ÿฌ ํšŒ์› ์„ ํƒ ํ›„ ์ผ๊ด„ ์Šน์ธ

์Šน์ธ ์ฒ˜๋ฆฌ

  1. ์Šน์ธ ๋Œ€๊ธฐ ํ•„ํ„ฐ ์„ ํƒ โ†’ ๋Œ€์ƒ ํšŒ์› ํ™•์ธ
  2. ์Šน์ธ ๋ฒ„ํŠผ ํด๋ฆญ โ†’ is_approved: true๋กœ ์—…๋ฐ์ดํŠธ
  3. ํšŒ์›์—๊ฒŒ ์Šน์ธ ์™„๋ฃŒ ์ด๋ฉ”์ผ ์ž๋™ ๋ฐœ์†ก
  4. ์ผ๊ด„ ์Šน์ธ ์‹œ ์ด๋ฉ”์ผ ๊ฐ„ 200ms ๊ฐ„๊ฒฉ์œผ๋กœ ์ˆœ์ฐจ ๋ฐœ์†ก (Rate Limit ๋ฐฉ์–ด)

๊ฑฐ๋ถ€ ์ฒ˜๋ฆฌ

  1. ๊ฑฐ๋ถ€ ๋ฒ„ํŠผ ํด๋ฆญ โ†’ ๊ฑฐ๋ถ€ ์‚ฌ์œ  ์ž…๋ ฅ ๋‹ค์ด์–ผ๋กœ๊ทธ ํ‘œ์‹œ
  2. ์‚ฌ์œ  ์ž…๋ ฅ ํ›„ ํ™•์ธ โ†’ ํšŒ์›์—๊ฒŒ ๊ฑฐ๋ถ€ ์ด๋ฉ”์ผ ๋ฐœ์†ก (์‚ฌ์œ  ํฌํ•จ)
  3. ํ•ด๋‹น ํšŒ์› ๊ณ„์ • ์‚ญ์ œ

๊ธฐํƒ€ ๊ด€๋ฆฌ ๊ธฐ๋Šฅ

๊ธฐ๋Šฅ์„ค๋ช…
ํšŒ์›์ •๋ณด ์ˆ˜์ •์—…์ฒด๋ช…, ๋Œ€ํ‘œ์ž๋ช…, ์—ฐ๋ฝ์ฒ˜, ์ด๋ฉ”์ผ, ๊ด€๋ฆฌ์ž ๊ถŒํ•œ ๋ณ€๊ฒฝ
๋น„๋ฐ€๋ฒˆํ˜ธ ์ดˆ๊ธฐํ™”์ž„์‹œ ๋น„๋ฐ€๋ฒˆํ˜ธ ๋ฐœ๊ธ‰ ํ›„ must_change_password ํ”Œ๋ž˜๊ทธ ์„ค์ •
ํšŒ์› ์‚ญ์ œํ™•์ธ ๋‹ค์ด์–ผ๋กœ๊ทธ ํ›„ ์‚ญ์ œ (์—ฐ๊ด€ CSO ๋งค์นญ ์œ ์ง€)
์—‘์…€ ๋‚ด๋ณด๋‚ด๊ธฐํ˜„์žฌ ํ•„ํ„ฐ ๊ธฐ์ค€ ํšŒ์› ๋ชฉ๋ก์„ ์—‘์…€๋กœ ๋‹ค์šด๋กœ๋“œ

๋น„๋ฐ€๋ฒˆํ˜ธ ์žฌ์„ค์ •

์‚ฌ์šฉ์ž ์š”์ฒญ (๋น„๋ฐ€๋ฒˆํ˜ธ ์ฐพ๊ธฐ)

  1. ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€์—์„œ ๋น„๋ฐ€๋ฒˆํ˜ธ ์ฐพ๊ธฐ ํด๋ฆญ
  2. ์‚ฌ์—…์ž๋ฒˆํ˜ธ ์ž…๋ ฅ โ†’ ๋“ฑ๋ก๋œ ์ด๋ฉ”์ผ ์ฃผ์†Œ๋กœ ์žฌ์„ค์ • ๋งํฌ ๋ฐœ์†ก
  3. ๋งํฌ ์œ ํšจ๊ธฐ๊ฐ„: 30๋ถ„
  4. ๋งํฌ ํด๋ฆญ โ†’ ์ƒˆ ๋น„๋ฐ€๋ฒˆํ˜ธ ์ž…๋ ฅ โ†’ ๋ณ€๊ฒฝ ์™„๋ฃŒ

๊ด€๋ฆฌ์ž ์ดˆ๊ธฐํ™”

  1. /admin/members ์—์„œ ํ•ด๋‹น ํšŒ์›์˜ ๋น„๋ฐ€๋ฒˆํ˜ธ ์ดˆ๊ธฐํ™” ํด๋ฆญ
  2. ์‹œ์Šคํ…œ์ด ์ž„์‹œ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ์ด๋ฉ”์ผ๋กœ ๋ฐœ์†ก
  3. ํšŒ์›์€ ๋‹ค์Œ ๋กœ๊ทธ์ธ ์‹œ ๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณ€๊ฒฝ ํŽ˜์ด์ง€๋กœ ๊ฐ•์ œ ์ด๋™

๋น„๋ฐ€๋ฒˆํ˜ธ ์ •์ฑ…

ํ•ญ๋ชฉ์ผ๋ฐ˜ ๊ณ„์ •ํ…Œ์ŠคํŠธ ๊ณ„์ •
์ตœ์†Œ ๊ธธ์ด6์ž4์ž
์˜๋ฌธ ํฌํ•จํ•„์ˆ˜๋ถˆํ•„์š”
์ˆซ์ž ํฌํ•จํ•„์ˆ˜๋ถˆํ•„์š”
ํ•ด์‹ฑbcrypt (12 rounds)๋™์ผ