
λ°©λ νλ‘μ νΈμμλ JWT ν ν°μ μ¬μ©ν΄ μΈμ¦/μΈκ° μλΉμ€λ₯Ό ꡬννλ€. μ΄λ ν ν°μ μ ν¨μκ°μ 2μκ°μ΄λ€. λ°©μ λλ¬λ³΄λ©° 체ν¬λ¦¬μ€νΈλ₯Ό μμ±νλλ° 2μκ°μ΄λ©΄ μΆ©λΆνλ€κ³ νλ¨νκΈ° λλ¬Έμ΄λ€. κ·Έλ°λ° μλΉμ€λ₯Ό μ΄μ©ν΄λ³΄λ 2μκ°μ΄ μΆ©λΆνμ§ μμ μλ μκ² λ€λ μκ°μ΄ λ€μλ€. μ€νμ μ μ 체ν¬λ¦¬μ€νΈ μ§λ¬Έ λͺ©λ‘μ νμΈνκ³ λͺ μκ°μ΄ μ§λ λ€ λ°©μ λλ¬λ³΄λ μ¬μ©μκ° μμ μλ μλ€. λν λ°©μ λλ¬λ³Έ λ€ κ³μ½μ νκΈ° μν΄ μ²΄ν¬λ¦¬μ€νΈ μ§λ¬Έ λͺ©λ‘μ λ€μ νμΈνλ©° κ³ λ―Όνλ μ¬μ©μλ μμ κ²μ΄λ€. μλΉμ€λ₯Ό μ΄μ©νλ λμ€ λ‘κ·ΈμΈμ΄ νλ¦°λ€λ©΄ κ΅μ₯ν λΆνΈνλ€.
λ‘κ·ΈμΈ μκ°μ λ κΈΈκ² κ°μ Έκ°κΈ° μν΄ λ°©λνμ μ‘μΈμ€ ν ν°, 리νλ μ ν ν°μ λμ νκΈ°λ‘ κ²°μ νλ€. ν ν°μ μ ν¨μκ°μ λ λ리λ λ°©λ²λ μμ κ²μ΄λ€. νμ§λ§ 보μμμ μ΄μ λ‘ μ ννμ§ μμλ€. ν ν°μ νμ·¨λΉν κ²½μ° μλ²μμ ν΄μ€ μ μλ κ²μ΄ μκΈ° λλ¬Έμ΄λ€. μ ν¨μκ°μ΄ λ§λ£λλ λμ ν΄μ»€λ κ³μν΄μ μλΉμ€μ μ κ·Όν μ μλ€λ λ¬Έμ μ μ΄ μμλ€.
κΈ°μ‘΄μ μκ³ μλ 리νλ μ ν ν° κ΅¬ν νλ¦μ λ€μκ³Ό κ°λ€.
보ν΅μ λ λμ€λ₯Ό νμ©ν΄ 리νλ μ ν ν°μ μλ²μ μ μ₯νλ ꡬνλ°©μμ λ§μ΄ 보μλ€. 리νλ μ ν ν°μ΄ νμ·¨λμλμ§ νμΈν μ μκ³ , νμ·¨λ κ²½μ° μ ν¨ μκ°μ λ§λ£μν΄μΌλ‘μ¨ μΆκ°μ μΈ λ¬Έμ λ₯Ό λ°©μ§ν μ μκΈ° λλ¬Έμ΄λ€.
λ€μμ μλ리μ€λ‘ 리νλ μ ν ν°μ΄ νμ·¨λμλμ§ μ μ μλ€.
κ·Έλ°λ°, μ¬μ©μμ μ‘μΈμ€ ν ν°κ³Ό μΌμΉνλ keyκ°μ΄ μ‘΄μ¬νμ§ μλλ€. μ΄λ―Έ ν΄μ»€κ° μ‘μΈμ€ ν ν°μ κ°±μ νκΈ° λλ¬Έμ΄λ€. ν΄λΉ λ¬Έμ κ° λ°κ²¬λλ©΄ κ·Έ μ¦μ ν΄λΉ μ‘μΈμ€ ν ν°μ λ§λ£μμΌ ν΄μ»€μ μ κ·Όμ λ§μ μ μλ€.
νμ§λ§ 리νλ μ ν ν°μ λ°μ΄ν°λ² μ΄μ€μ μ μ₯νλ μκ° JWT ν ν°μ΄ μ 곡νλ stateless μ₯μ μ΄ μ¬λΌμ§λ€κ³ μκ°νλ€. stateν μνμμλ μλ² κ°μ κ°μ μΌμΉμν€λ μμ μ΄ νμνκ³ , λ§€ μμ²λ§λ€ μ μμ μΈ μ¬μ©μμΈμ§ νμΈνκΈ° μν΄ λ°μ΄ν°λ² μ΄μ€μμ κ°μ μ‘°ννλ κ³Όμ μμ μλ²μ λΆλ΄μ΄ μ¦κ°νκ² λλ€. statelessν μ₯μ μ μ·¨νκ³ μ JWT ν ν°μ μ¬μ©νλλ° λ¦¬νλ μ ν ν°μ μ¬μ©νλ©΄μ κ·Έ μ₯μ μ μκ³ μΆμ§λ μμλ€. κΈ°μ‘΄μ ν ν°μ μΏ ν€μ μ μ₯νλ κ²μ²λΌ 리νλ μ ν ν°λ μΏ ν€μ κ°μ΄ μ μ₯νλ©΄ λ¬Έμ κ° λλ?λ₯Ό κ³ λ―Όνκ² λμλ€.
κ·Έλ λ€λ©΄ μΉ ν΅μ κ³Όμ μμ μΌμ΄λ μ μλ 보μ μ΄μλ₯Ό μμλ΄μΌ νλ€. XSS(Cross-Site Scripting)μ CSRF(Cross-Site Request Forgery)μ΄ κ°μ₯ ννκ² λ°μνλ 곡격 μ νμ΄λ©΄μ κ°μ₯ μμ£Ό λ±μ₯νλ κ°λ μ΄λ€.
곡격μκ° μΉ νμ΄μ§μ μ μμ μΈ μ€ν¬λ¦½νΈλ₯Ό μ½μ νμ¬ μ¬μ©μμ μ 보λ₯Ό νμ·¨νκ±°λ μ‘°μνλ 곡격μ΄λ€. μλ₯Ό λ€μ΄, 곡격μκ° κ²μνμ μ μμ μΈ μ€ν¬λ¦½νΈλ₯Ό ν¬ν¨ν κΈμ μμ±νλ©΄, μ΄ κΈμ μ½λ μ¬μ©μμ λΈλΌμ°μ μμ ν΄λΉ μ€ν¬λ¦½νΈκ° μ€νλμ΄ κ³΅κ²©μμκ² μ λ³΄κ° μ μΆλ μ μλ€. ν ν°μ΄ μ€ν¬λ¦½νΈλ‘ μ κ·Όν μ μλ κ³³μ μ μ₯λμ΄ μλ€λ©΄ XSS 곡격μ μ·¨μ½ν΄μ§λ€.
μ¬μ©μκ° μμ μ μμ§μ 무κ΄νκ² κ³΅κ²©μκ° μλν νμλ₯Ό μΉ μ ν리μΌμ΄μ μ μμ²νκ² λ§λλ 곡격μ΄λ€. μλ₯Ό λ€μ΄, μ¬μ©μκ° μΈν°λ· λ± νΉ μλΉμ€μ λ‘κ·ΈμΈν μνμμ 곡격μκ° μ€λΉν κ²°μ μμ² λ§ν¬λ₯Ό ν΄λ¦νκ² λλ©΄, μ¬μ©μλ μμ μ μμ§μλ 무κ΄νκ² κ²°μ λ₯Ό μ§ννκ² λλ€. μ΄λ₯Ό λ°©μ§νκΈ° μν λ°©λ²μΌλ‘λ CSRF ν ν° μ¬μ©, μΏ ν€μ SameSite μμ± μ€μ , Referrer κ²μ¦ λ±μ΄ μλ€.
Cookie + HttpOnly + secure + Same Site μ΅μ μ λͺ¨λ νμ©νλ€λ©΄ μμμ λ§ν 보μ μ΄μλ₯Ό μλ°©ν μ μλ€. HttpOnly μ΅μ μ μ¬μ©νλ©΄ μ€ν¬λ¦½νΈλ₯Ό ν΅ν΄ μΏ ν€κ°μ μ½μ΄λ³Ό μ μκΈ° λλ¬Έμ XSS 곡격μ λν΄ λ°©μ΄ν μ μλ€. λν SameSite μ΅μ μ μ¬μ©νλ©΄ μΏ ν€λ₯Ό μ μ‘ν λ²μλ₯Ό μ€μ ν μ μλ€. νΉμ μμ²μ μ μΈνκ³ λ νμ¬ νμ΄μ§μ λλ©μΈκ³Ό μμ²λ°λ λλ©μΈμ΄ κ°μμΌλ§ μΏ ν€λ₯Ό μ μ‘ν΄μ€λ€. ν΄μ»€κ° λ€λ₯Έ μ¬μ΄νΈλ₯Ό ν΅ν΄ μμ²μ 보λ΄λ λλ©μΈμ΄ μΌμΉνμ§ μμ CSRF 곡격μ λν΄ λ°©μ΄ν μ μλ€.
리νλ μ ν ν°μ΄ νμ·¨λΉνλ©΄ κ³μν΄μ μ‘μΈμ€ ν ν°μ λ°κΈλ°μ μ μκΈ° λλ¬Έμ 보μ λ¬Έμ μ λν΄ κΉκ² κ³ λ―Όν΄λ΄μΌ νλ€. κ·Έλ¦¬κ³ κ΅¬ν λ°©μμ ν λ² μ νλ©΄ λ°κΎΈκΈ° μ½μ§ μκΈ° λλ¬Έμ μ λ§ λ§μ κ³ λ―Όμ νλ€.
νμ§λ§ μ무리 μκ°ν΄λ΄λ 보μ λ¬Έμ λ₯Ό κ³ λ―Όνλ€λ©΄ 리νλ μ ν ν°μ μμ νκ² μ¬μ©νκΈ° μν΄ λλ μμ΄ μ΄ λ°©λ², μ λ°©λ²μ κ°λ€ λΆμ¬μΌ νλ€. μλ₯Ό λ€μ΄ 리νλ μ ν ν°μ ν λ²λ§ μ¬μ©ν μ μλλ‘ νλ RTR(Refresh Token Rotation) κ°λ μ΄λΌλμ§ .. μ μ JWT ν ν°μ λν νμκ°μ΄ λ κ²λ μ¬μ€μ΄λ€. νΈλ¦¬μ±κ³Ό 보μμ±μ λͺ¨λ μ±κΈ°κΈ°λ μ½μ§ μμλ€.
κ·Έλμ μ€λ κ³ λ―Ό λμ λ€μμ λ°©μμ μ ννλ€.
μΏ ν€ μ΅μ μ μ λλ‘ μ€μ ν΄μ€λ€λ©΄ μ΄λ μ λ 보μ μ΄μλ₯Ό λ§μ μ μλ€κ³ μκ°νλ€. 보μμ λν μ‘°μΉκ° λ―Έν‘ν μ μ΄ μ‘°κΈ κ±Έλ¦¬μ§λ§ μ§κΈ λ¨κ³μμ λΉμ₯ νμμ±μ λλΌμ§ λͺ»νλ μμ μ μ§ννμ§ μκΈ°λ‘ νλ€.
νλ‘ νΈμμ μ‘μΈμ€ ν ν°μ΄ λ§λ£λμμμ μκ³ /reissue API μμ²μ 보λ΄κΈ° μν΄μλ, μ¦ νλ‘ νΈ μ½λ λ΄μμ λΆκΈ°μ²λ¦¬νκΈ° μν΄μλ μμΈ λ©μμ§λ₯Ό κ°μ΄ λ§μΆ°λ΄μΌ νλ€. ν ν°μ μ¬μ©νμ λ λ°μν μ μλ μλ리μ€λ₯Ό μ λμ΄ν΄λ³΄κ³ μμΈ λ©μμ§λ₯Ό μ 리νλ€.
| μμ² μ ν | 리νλ μ ν ν° | μ‘μΈμ€ ν ν° | μ²λ¦¬ κ²°κ³Ό | λ€μ μμ² |
|---|---|---|---|---|
| μΌλ° μμ² | O | X | "ν ν° μ λ³΄κ° μ‘΄μ¬νμ§ μμ΅λλ€. ν ν°μ μ¬λ°κΈν΄μ£ΌμΈμ." | /accessToken/reissue |
| μΌλ° μμ² | X | O | "λ‘κ·ΈμΈμ΄ νμν μ¬μ©μμ λλ€." | /oauth/login |
| μΌλ° μμ² | X | X | "λ‘κ·ΈμΈμ΄ νμν μ¬μ©μμ λλ€." | /oauth/login |
| /accessToken/reissue | X | X | "ν ν° μ λ³΄κ° μ‘΄μ¬νμ§ μμ΅λλ€. ν ν°μ μ¬λ°κΈν΄μ£ΌμΈμ." | /oauth/login |
| /accessToken/reissue | X | O | "λ‘κ·ΈμΈμ΄ νμν μ¬μ©μμ λλ€." | /oauth/login |
μ΄ κ³Όμ μμ μμΈ λ©μμ§λ₯Ό λμ§ λ μμΈ μ½λκ° νμνλ€λ κ²μ λκΌλ€. μμΈ λ©μμ§λ‘ νλ‘ νΈμ μν΅νλ κ²μ΄ μ½μ§ μμκ³ μμΈ μν©μ λ¬Έμμ΄λ‘ νλ¨νλ κ²μ λ°λμ§ν΄λ³΄μ΄μ§ μμλ€. λν λ°±μλ μ½λ λ‘μ§λ΄μμ μ‘μΈμ€ ν ν°κ³Ό 리νλμ ν ν°μ΄ 곡ν΅μΌλ‘ μ²λ¦¬νλ λΆλΆμ΄ μμ΄ νμ¬λ μμΈ λ©μμ§κ° λΉμ·νλ° μ΄ λΆλΆλ κ° μν©μ λ°λΌ λ μ μ ν μμΈ λ©μμ§λ‘ 리ν©ν λ§ν μμ μ΄λ€.
μλ²μμ ꡬνν reissue APIλ₯Ό νλ‘ νΈμ νμ νλ©΄μ κ³ λ―Όμ΄ μκ²Όλ€. μμΈ λ©μμ§λ₯Ό λ§μΆλ μμ μ΄ μκ°λ³΄λ€ μ½μ§ μμκ³ , "μ°¨λΌλ¦¬ μμΈ λ©μμ§λ₯Ό μ λ¬νμ§ μκ³ , μ‘μΈμ€ ν ν°μ΄ λ§λ£λλ©΄ μλ²κ° μμμ μΏ ν€λ₯Ό μ€μ ν΄μ£Όλ λ°©μμ΄ λ λμ κ² μλκΉ?"λΌλ μ΄μΌκΈ°κ° λμλ€. νμ§λ§ μ΄ λ°©μμ λν΄ μ μ§ λͺ¨λ₯Ό μ°μ°ν¨μ΄ μμλ€. μ¬λ¬ κ°μ§λ₯Ό μΆ©λΆν κ³ λ €νμ§ λͺ»ν μνμμ κ²°μ μ λ΄λ¦¬κΈ°μλ κ²½νκ³Ό κ·Όκ±°κ° λΆμ‘±νλ€κ³ λκΌλ€. κ²°κ΅ μκ° λΆμ‘±μΌλ‘ μΈν΄ μΌλ¨μ ꡬνλ Reissue APIλ₯Ό μ¬μ©νλ μͺ½μΌλ‘ κ²°λ‘ μ λ΄λ Έμ§λ§, μ΄ λ°©μμ λν΄μλ μΆκ°μ μΈ λ Όμκ° νμν κ² κ°λ€.
λ°λͺ¨λ°μ΄μ 2κ°μ§ νΌλλ°±μ λ°μ μ μμλ€. μ΄μ λν λ΅μ λ€μ μ²μ²ν κ³ λ―Όν΄λ³΄μ π