diff --git a/keyword/chapter09/keyword.md b/keyword/chapter09/keyword.md new file mode 100644 index 0000000..38a067b --- /dev/null +++ b/keyword/chapter09/keyword.md @@ -0,0 +1,238 @@ +# Q1. 세션(Session)과 토큰(Token)의 차이는? + +## 정의 + +세션과 토큰은 **인증(Authentication)** 단계를 거친 후, 권한 확인 목적인 **인가(Authorization)** 단계에서 사용되는 방식의 종류이다. + +## 왜 쓰는가 + +HTTP는 **Stateless(무상태) 프로토콜**이므로 서버는 각 요청을 독립적으로 판단한다. 따라서 이전 요청을 기억하지 않는 특징이 있다. + +> 그렇다면 매 요청마다 "나는 인증된 사용자가 맞다"를 어떻게 증명할까? + +이를 해결하기 위해 로그인 이후 클라이언트↔서버가 주고받을 **증표**가 필요한데, 이 증표의 방식이 세션과 토큰으로 나뉜다. + +--- + +## 세션 (Session) + +### 정의 + +서버가 사용자의 인증 상태를 **서버 측에 저장**하고, 그 정보를 가리키는 식별자(**Session ID**)만 클라이언트에 발급하는 방식이다. 클라이언트는 이후 요청마다 Session ID만 서버에 전달하면 된다. + +- 클라이언트는 '열쇠'만 들고 있는 셈이다. +- 서버가 상태를 저장하므로 **Stateful**한 방식이다. + +### 동작 흐름 + +1. 로그인 성공 → 서버가 세션 데이터 생성 & 저장소에 보관 +2. Session ID 발급 → 클라이언트 쿠키에 전달 +3. 이후 요청마다 클라이언트는 쿠키에 담긴 Session ID 전송 +4. 서버가 저장소에서 조회해 인증된 사용자인지 검증 + +### 특징 + +- 서버가 상태를 직접 관리하므로 **강제 무효화가 쉽다.** (강제 로그아웃, 동시 접속 제한 등) +- **저장소 부담**이 있다. (세션 데이터가 많아짐) +- **서버 확장에 불리**하다. + +--- + +## 토큰 (Token) + +### 정의 + +인증에 필요한 정보를 **토큰 자체에 담아 서명**한 뒤 클라이언트에 발급하고, 서버는 저장 없이 **서명 검증만으로** 사용자를 식별하는 방식이다. + +- 클라이언트가 정보를 들고 있다. +- 서버가 상태를 갖지 않으므로 **Stateless**한 방식이다. + +### 동작 흐름 + +1. 로그인 성공 → 서버가 서명된 토큰 생성 +2. 토큰을 클라이언트에 전달 (서버는 저장 X) +3. 이후 요청마다 토큰 함께 전송 (`Authorization: Bearer `) +4. 서버는 서명만 검증 (저장소 조회 X) + +### JWT 구조 + +`Header.Payload.Signature` + +- **Header** : 토큰 타입 + 서명 알고리즘 +- **Payload** : 사용자 정보 (Base64 인코딩) + - Payload는 누구나 디코딩 가능하므로, 민감한 정보를 넣으면 안 된다. +- **Signature** : Header + Payload를 비밀키로 서명 → 위변조 검증용 + +--- + +## 장단점 비교 + +> **토큰 방식이 세션보다 우월하거나 더 좋은 방식이 아니다!** +> 확장성과 통제권 사이의 트레이드오프일 뿐이다. + +### 세션 장점 + +- **강제 무효화가 쉽다.** 저장소에서 정보를 지우면 즉시 로그아웃이 가능하고 동시 접속 제한도 수월하다. +- 클라이언트가 정보를 들고 있지 않아 **탈취 리스크가 토큰보다 낮다.** +- 권한 변경·세션 관리를 **실시간으로 반영**할 수 있다. + +### 세션 단점 + +- **서버 확장에 불리하다.** (세션 공유 문제) → Redis 등 별도 저장소가 필요하다. +- **저장소 부담**이 있다. 사용자가 많아질수록 서버가 저장할 데이터가 많아진다. +- **CSRF 노출 위험**이 있다. (쿠키 기반이므로) + +### 토큰 장점 + +- **서버 확장에 유리하다.** 서버가 상태를 저장하지 않으므로, 어느 서버로 가든 토큰만 검증되면 된다. + - 분산 환경 또는 MSA에 적합하다. +- **저장소 조회가 없다.** 서버는 서명 검증만 하므로 부하 분산에 유리하고, 서버 저장 부담이 없다. +- **클라이언트 환경에 유연하다.** + - `Authorization` 헤더로 토큰을 전송해 쿠키에 의존하지 않으므로, 다양한 클라이언트에 대응하기 쉽다. + +### 토큰 단점 + +- **강제 무효화가 어렵다.** 발급된 토큰은 만료 전까지 유효하므로 탈취당해도 즉시 차단이 어렵다. → 별도 보완 설계 필요 +- **페이로드 노출** → Payload는 Base64 인코딩이므로 누구나 디코딩이 가능하다. 민감한 정보를 담으면 안 된다. +- **토큰 크기가 크다.** 데이터를 담고 있어 Session ID보다 크고, 네트워크 부담이 상대적으로 크다. +--- +# Q2. 액세스 토큰(Access Token)과 리프레시 토큰(Refresh Token)이란? + +## 왜 토큰을 두 종류로 나누는가 + +토큰을 두 종류로 나누는 이유는 **'강제 무효화가 어려움'**이라는 토큰의 단점 때문이다. + +- 토큰의 유효기간을 **길게** 잡으면 → 탈취당했을 때 위험성이 커진다. +- 토큰의 유효기간을 **짧게** 잡으면 → 비교적 안전하지만, 사용하기 불편하다. (자주 인증해야 함) + +따라서 **자주 쓰면서 수명이 짧은 액세스 토큰** + **자주 안 쓰면서 수명이 긴 리프레시 토큰**으로 나뉜다. + +--- + +## 액세스 토큰 (Access Token) + +### 정의 + +API 요청 시 실제 **인가(Authorization)**에 사용되는 수명이 짧은 토큰이다. + +> 세션 vs 토큰을 비교할 때의 '토큰' = 액세스 토큰이라고 생각하면 개념 이해가 빠르다. (100% 일치하진 않음) + +- 매 요청마다 `Authorization: Bearer ` 형태로 실려, "나는 인증된 사용자이고, 권한이 있다"를 증명하는 데 사용된다. +- 매 API 요청에서 서버가 서명을 검증하는, 그 토큰이 액세스 토큰이다. + +### 특징 + +- **수명이 짧다.** (보통 몇 분~몇십 분) → 탈취되더라도 악용 시간이 짧다. +- **사용 빈도가 높다.** → 모든 API 요청에 사용되기 때문이다. +- **클라이언트가 보관**하고, 서버는 따로 저장하지 않는다. + +### 액세스 토큰의 수명을 짧게 두는 이유 + +토큰의 단점으로 '강제 무효화 어려움'을 언급했는데, 탈취됐을 때를 대비해 **토큰 사용 가능 시간을 처음부터 짧게 설정**하여 피해 리스크를 줄이기 위한 목적이다. + +--- + +## 리프레시 토큰 (Refresh Token) + +### 정의 + +액세스 토큰이 만료됐을 때, **새 액세스 토큰을 재발급받기 위해** 사용하는 수명이 긴 토큰이다. + +- API 요청에 직접 쓰이지 **않는다.** 오직 '액세스 토큰 재발급' 목적으로만 사용된다. + - 액세스 토큰이 만료되면, 클라이언트는 리프레시 토큰을 인증 서버에 보내 새 액세스 토큰을 발급받는다. → 재로그인 없이 인증 상태가 자동 연장된다. + +### 특징 + +- **수명이 길다.** (보통 n일~n주) +- **사용 빈도가 낮다.** → 액세스 토큰이 만료되는 시점에만 사용되기 때문이다. +- **서버가 저장하는 경우가 많다.** (항상 100%는 아님) + +### 리프레시 토큰을 서버에 저장하는 이유 + +리프레시 토큰은 수명이 길어 탈취되면 위험이 크다. 따라서 서버가 직접 관리하며 필요할 때 **무효화**할 수 있게 한다. + +> 토큰 방식의 약점인 '강제 무효화 불가'를 리프레시 토큰 단계에서 통제권을 되찾으며 극복하는 구조이다. + +--- + +## 동작 흐름 + +1. 로그인 성공 → 서버가 **액세스 토큰 + 리프레시 토큰** 함께 발급 +2. 매 API 요청 → **액세스 토큰으로만** 인가 +3. 액세스 토큰 만료됨 → 클라이언트가 리프레시 토큰을 서버에 전달 +4. 서버가 리프레시 토큰 검증 후 유효하면, 새 액세스 토큰 발급 +5. 리프레시 토큰마저 만료됨 → 재로그인 필요 +--- +# Q3. OAuth 1.0과 OAuth 2.0의 차이는? + +## OAuth 정의 + +사용자의 **비밀번호를 직접 넘기지 않고**, 제3자 애플리케이션에게 **특정 권한만 위임**하도록 하는 **인가(Authorization) 위임 프로토콜**이다. +즉, 로그인 기술이 아니다. + +즉, 사용자의 생년월일이 필요할 때 아이디+비밀번호를 통째로 넘기는 것이 아니라, **'생년월일 읽기 권한만 담긴 토큰'**을 발급하여 생년월일 데이터에 대한 권한만 허용하도록 하는 것이다. + +> ⚠️ OAuth는 본래 **인가(Authorization)** 프로토콜이다. "누구인지 확인(인증)"이 주목적이 아니다. (흔히 쓰는 "구글로 로그인"은 OAuth 위에 얹은 **OpenID Connect**라는 별도 규격이다.) + +--- + +## OAuth 1.0 + +### 정의 + +초기 위임 표준이다. 토큰을 주고받되, **모든 요청을 클라이언트가 직접 서명(Signature)**해서 무결성을 보장하는 방식이다. + +### 특징 + +- **요청마다 서명을 생성한다.** 클라이언트는 요청 내용 + 비밀키를 조합해 해시 서명을 만들어 함께 전달하고, 서버도 같은 방식으로 검증한다. +- **HTTPS가 필수가 아니다.** 서명 자체로 위변조를 막으므로, 암호화되지 않은 통신에서도 무결성이 보장된다. + - OAuth 1.0이 사용될 당시에는 HTTPS가 보편적이지 않아 이 설계가 의미 있었다. +- **상태 유지가 복잡하다.** 일회용 값(nonce)이나 timestamp 등을 관리해야 해 구현 난이도가 높다. + +### 장점 + +1. **HTTPS(전송 보안)에 의존하지 않고도** 요청 무결성을 보장한다. +2. 서명 기반이라 **요청 위변조·재전송 공격에 강하다.** + +### 단점 + +1. **서명 로직이 복잡하다.** 클라이언트마다 서명을 정확히 구현해야 해 개발 부담이 크다. +2. **확장성이 떨어진다.** 모든 요청에 서명 연산이 필요하고, 다양한 클라이언트(모바일 앱, SPA 등)에 적용하기 번거롭다. + +--- + +## OAuth 2.0 + +### 정의 + +OAuth 1.0의 복잡성을 걷어낸 **재설계 버전**이다. 복잡한 서명을 없애고, 보안은 **HTTPS(TLS)에 위임**하며, 토큰을 그대로 전달하는 방식으로 단순화했다. + +### 특징 + +- **서명이 없어졌다.** 요청마다 서명을 만드는 대신, 발급받은 액세스 토큰을 그대로 제시한다. +- **역할을 명확히 분리한다.** + - 사용자(Resource Owner) / 클라이언트(Client) / 인가 서버(Authorization Server) / 자원 서버(Resource Server) +- **액세스 토큰 + 리프레시 토큰** 구조를 기반으로 한다. + +### 장점 + +1. **구현이 단순하다.** 서명 로직이 없어 OAuth 1.0에 비해 개발 부담이 줄었다. +2. **확장성과 유연성이 높아졌다.** Grant Type을 환경별로 골라 쓸 수 있어 웹·모바일·서버 간 통신 등 서로 다른 상황을 지원한다. + - Grant Type = OAuth 2.0에서 클라이언트가 **액세스 토큰을 받아오는 방식**을 규정한 유형 +3. **현재 업계 표준이다.** 구글·카카오·깃허브 등 대부분의 서비스에서 사용 중이다. + +### 단점 + +1. **HTTPS에 전적으로 의존한다.** TLS가 없으면 토큰이 그대로 노출된다. → 서명으로 자체 방어하던 1.0과 달리, 전송 계층 보안이 무너지면 취약하다. +2. **1.0에 비해 규격이 느슨하다.** 큰 틀의 프레임워크에 가까워, 구현체마다 보안 수준이 다를 수 있고 잘못 구현하면 취약점이 발생할 수 있다. + +--- + +## 핵심 정리 + +> **본질적 차이는 "무결성을 어디서 보장하느냐"이다.** +> +> - **1.0** : 클라이언트가 **직접 서명**해서 보장 → 안전하지만 복잡 +> - **2.0** : **HTTPS(전송 계층)**에 위임 → 단순하지만 TLS 의존 + +**2.0이 1.0을 대체한 이유는 "더 안전해서"가 아니라 "더 단순하고 확장 가능해서"이다.** (HTTPS 보편화로 서명의 필요성이 줄어든 것이 배경) \ No newline at end of file diff --git a/mission/chapter09/images/loginSuccess.png b/mission/chapter09/images/loginSuccess.png new file mode 100644 index 0000000..6bfcbc2 Binary files /dev/null and b/mission/chapter09/images/loginSuccess.png differ diff --git a/mission/chapter09/images/mypageFailure.png b/mission/chapter09/images/mypageFailure.png new file mode 100644 index 0000000..6d70ecd Binary files /dev/null and b/mission/chapter09/images/mypageFailure.png differ diff --git a/mission/chapter09/images/mypageSuccess.png b/mission/chapter09/images/mypageSuccess.png new file mode 100644 index 0000000..a15808f Binary files /dev/null and b/mission/chapter09/images/mypageSuccess.png differ diff --git a/mission/chapter09/images/token.png b/mission/chapter09/images/token.png new file mode 100644 index 0000000..eb1bf57 Binary files /dev/null and b/mission/chapter09/images/token.png differ diff --git a/mission/chapter09/mission.md b/mission/chapter09/mission.md new file mode 100644 index 0000000..1eb2155 --- /dev/null +++ b/mission/chapter09/mission.md @@ -0,0 +1,11 @@ +## 1. 로그인 성공 +![loginSuccess.png](./images/loginSuccess.png) + +## 2. 액세스 토큰 적용 +![token.png](./images/token.png) + +## 3. 마이페이지 조회 성공 +![mypageSuccess.png](./images/mypageSuccess.png) + +## 4. 마이페이지 조회 실패 (잘못된 액세스 토큰) +![mypageFailure.png](./images/mypageFailure.png)