[TIL 65-1일 차] 유저 관리 기능
3. 기본 인증과 인코딩
3-01. 기본 인증(Basic Authentication)
1) 기본 인증
기본 인증은 HTTP 표준 인증 방식 중 하나로, RFC 7617에 정의되어 있다.
- 클라이언트: 사용자 이름과 비밀번호를 콜론(
:)으로 연결 ➡️username:password - 인코딩: 연결한 문자열을 Base64로 인코딩 ➡️
dXNlcm5hbWU6cGFzc3dvcmQ= - 서버 요청: 인코딩한 문자열을
Authorization헤더에 담아 요청 전송
GET /mypage HTTP/1.1
Host: example.com
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
- 서버 동작
Authorization헤더 확인Basic접두사 제거 후 Base64 디코딩username:password추출- 서버 저장소의 자격 증명과 비교 후 인증 성공 여부 결정
2) 기본 인증의 한계와 보안 위험성
- 인코딩 ≠ 암호화 : Base64는 단순 인코딩, 보안 기능 X
- 재전송 위험: 요청마다 자격 증명이 반복 전송되므로 탈취 위험성이 높음
- 저장소 문제: 서버는 사용자의 비밀번호를 해시 등의 방법으로 안전하게 저장해야 함
- 현대적 대체 수단 필요: 세션 기반 인증이나 토큰 기반 인증(JWT 등)이 일반적으로 사용됨
3-02. 인코딩과 Base64URL
1) 인코딩(Encoding)
데이터를 다른 표현 규칙으로 바꾸는 것
- 내용 자체는 변하지 않고, 표현 방식만 변하는 것
- A는 컴퓨터 내부에서 2진수로
01000001로 저장됨
필요성
- 소통: 서로 다른 언어나 기기에서 같은 정보를 주고받기 위해
- 전송 안정성: 어떤 통로는 한글이나 특수 문자를 제대로 못 읽음
- 저장 호환성: 텍스트 파일, 이메일, 웹 요청 등에서 문제가 생기지 않도록 도움
예시
- 문자 인코딩 : 이모지가 상대방과 똑같이 보임
- URL 인코딩 : 주소창에 공백 대신
%20이 들어가는 것 - 동영상 인코딩 : 유튜브에서 같은 영상을 240p~1080p로 선택 가능한 이유
- QR 코드 : 흑백 점들이 문자, 링크, 숫자로 변환되는 과정
- 인코딩 순서 예시: 안녕! ➡️ UTF-8 규칙 적용 ➡️
11101111....➡️ 다른 기기에서 디코딩 ➡️ 안녕!
2) Base64 인코딩
다른 인코딩이 필요한 이유
- 이메일, HTTP 헤더 같은 통로는 특수 문자나 바이너리(사진, 음악) 파일을 직접 담기 어려움
- 그래서 모든 데이터를 알파벳 + 숫자만으로 바꿔서 안전하게 보내는 방식이 필요함
- 이것이 Base64
- 텍스트 전송만 가능한 채널에 안전한 포장지 역할을 함
- 다만, 데이터가 4/3배로 늘어나므로 대용량 데이터에는 적합하지 않음
원리
- 3 Byte(24 bit) ➡️ 6 bit씩 자름 ➡️ 4개의 문자로 바꿈
- 총 64개의 안전한 문자(
A-Z a-z 0-9 + /)만 사용 - 나머지가 부족하면
=기호로 채움
3) Base64URL 인코딩
- URL에서는
+,/,=같은 문자가 문제를 발생시킬 수 있음. - 그래서 안전하게 “
+➡️_”로, “/➡️-”로, “=제거”로 바꾼 게 Base64URL
3-03. 기본 인증 보안 고려사항
1) HTTPS의 필요성
- HTTP의 전송 방식 : 평문(암호화 없음)
- Basic Auth를 사용하면
Authorization헤더가 그대로 노출
- Basic Auth를 사용하면
- HTTPS의 전송 방식 : TLS/SSL로 암호화
- 전송 구간을 암호화하여 중간에서 패킷을 보더라도 내용을 알 수 없음
2) HTTPS 내부 동작
- 브라우저가 서버에 HTTPS 통신을 하겠다는 신호를 보냄
- 지원 가능한 암호화 방식 목록을 함께 보냄
- 서버는 사용할 암호화 방식을 고르고, 자신이 신뢰할 수 있는 서버임을 나타내는 디지털 인증서(공개키 포함)를 보냄
- 브라우저는 서버의 공개키로 임시 대칭키(세션키)를 암호화해서 전달
- 서버는 개인키로 이를 복호화하여 같은 대칭키를 얻음
- 이후 모든 HTTP 요청/응답은 이 대칭키로 암호화되어 전송됨
- 예시
- HTTP : 우편엽서에 주소, 내용, 비밀번호까지 다 작성해서 보내는 것
- HTTPS : 봉투에 넣어 봉인 후 보내는 것
3) 자격 증명 노출 위험성
- Base64는 단순 인코딩일 뿐 암호화는 아님
- 그래서
Authorization헤더를 훔치면 빠르게username:password를 알 수 있다.
4) 현대 웹 애플리케이션에서 활용 여부
안 쓰이는 이유
- 매 요청마다 ID/PW를 보내는 구조라 매우 위험
- 세션/토큰 기반 인증이 더 안전하고 효율적
사용되는 곳
- 내부 시스템, 테스트용 API, 간단한 인증에만 제한적 사용
4. Authorization 헤더와 토큰 기반 인증
4-01. Authorization 헤더
HTTP 요청에서 인증 정보를 서버로 전달하기 위해 사용하는 표준 헤더
- 용도: 서버가 클라이언트의 신원을 확인하고 보호된 리소스로의 접근 권한을 부여하는데 사용
- 예시:
Authorization헤더를 사용해 Basic 인증 자격 증명을 보낸 요청GET /protected-resource HTTP/1.1 Host: example.com Authorization: Basic dXNlcjpwYXNz
1) 구조와 기본 형식
- 인증 방식
- 어떤 인증 방법을 사용하는지 식별
- 예시
Basic,Bearer,Digest
- 자격 증명 또는 토큰
- 인증 데이터 (암호화, 인코딩된 값 등)
- 예시
dXNlcjpwYXNz,eyJhbGciOi...
- 최종 형태
Authorization: <인증방식> <인증정보>- Basic 인증
- 예시:
Authorization: Basic dXNlcjpwYXNz - RFC 7617에서 정의한 인증 방식인
Basic을 사용 username:password를 Base64로 인코딩하여 전송- 단순하지만 보안에 취약 ➡️ 반드시 HTTPS와 함께 사용해야 함
- 예시:
- Bearer 토큰 인증
- 예시:
Authorization: Bearer eyJhbGciOi... - RFC 6750에서 정의된 방식으로, 보통 액세스 토큰(JWT 등)을 전달합니다.
- “이 토큰 가진 자(bearer)는 접근 권한이 있다”는 의미
- API 서버를 설계할 때 일반적으로 많이 사용함 (+ HTTPS)
- 예시:
- Digest 인증
- 예시:
Authorization: Digest username="Mufasa", [realm="testrealm@host.com](mailto:realm=%22testrealm@host.com)", ... nonce와 해시 알고리즘을 이용해 암호를 직접 전송하지 않고 검증- 과거에는 많이 사용했으나, 현재는 거의 Bearer/JWT 방식으로 대체됨
- 예시:
2) 세션 기반 인증과의 차이점
| 구분 | 세션 기반 인증 | Authorization 헤더 기반 인증 |
|---|---|---|
| 인증 정보 저장 위치 | 서버 (세션 저장소) | 클라이언트 (토큰 등) |
| 전송 방식 | 쿠키(Cookie: SESSION=...) |
헤더(Authorization: ...) |
| 상태 관리 | 서버가 상태(state)를 유지 | 서버는 무상태(stateless)로 동작 가능 |
| 확장성 | 서버 확장 시 세션 동기화 필요 | 토큰만 검증하면 되어 확장성 높음 |
3) Authorization 헤더 기반 인증 workflow
## 4-02. 토큰 기반 인증 토큰은 특정 리소스에 대한 접근 권한을 부여함
### 1) 토큰 기반 인증의 특징 - 토큰에 포함된 인증 정보는 서버가 별도로 저장하지 않음 - 생성된 토큰을 **HTTP Authorization** 헤더에 담아 전송 - 토큰 안에 사용자 정보가 포함되므로 **세션에 비해 네트워크 트래픽이 많을 수 있다.** - 토큰이 매 요청마다 함께 전송되기 때문 - 서버는 토큰 자체를 관리하지 않으므로 **보안성 측면에서 신중한 설계**가 필요 - 인증 상태를 서버에 저장하지 않기 때문에 **확장성(Scalability)**면에서 매우 유리함 - **토큰 유출 시 위험** - 평문 그대로 전달되므로 반드시 TLS(HTTPS)로 전송해야 함 - 토큰은 만료되기 전까지 기본적으로 무효화 불가능 - 단, Redis 같은 인메모리 DB에 블랙리스트 형태로 저장하고 짧은 만료 시간을 부여하여 보완 가능
### 2) 세션 기반 인증과 토큰 기반 인증 비교 | 구분 | 세션 기반 인증 | 토큰 기반 인증 | | --------- | --------------------------------- | ------------------------------------- | | 상태 관리 | 서버에 세션 저장소 필요 | 서버 상태 저장 불필요, 토큰만 검증 | | 확장성 | 세션 공유 필요 (예: Redis) | 서버 확장에 유리 | | 저장 위치 | 브라우저 쿠키 | 로컬 스토리지, 세션 스토리지, 쿠키 등 | | 보안 위험 | 세션 탈취 | 토큰 유출 | | 무효화 | 세션 만료 시 서버에서 무효화 가능 | 만료 전까지 기본적으로 무효화 불가 |
### 3) 토큰 기반 인증 workflow
## 4-03. JWT(JSON Web Token) JWT는 **데이터를 안전하고 간결하게 전송하기 위해 고안된 인터넷 표준 인증 방식** - 애플리케이션 보안에서 JWT는 **출입 카드**와 비슷한 개념으로, 특정 권한을 가진 사용자가 시스템을 이용할 수 있게 해줌 - JWT 공식 사이트: https://www.jwt.io/ **토큰 기반 인증(Token-based Authentication)**에서 가장 범용적으로 사용됨 - JWT는 서버 확장성이 중요한 **마이크로서비스 아키텍처**에서 유용
### 1) JWT 구조 세 부분으로 나뉘며, 각각 `.`으로 구분됨 #### **Header (헤더)** - 어떤 알고리즘으로 서명했는지, 어떤 타입의 토큰인지 정의 ```json { "alg": "HS256", "typ": "JWT" } ``` - `alg` : 사용할 서명 알고리즘 (예: `HMAC SHA256`) - `typ` : 토큰 타입 (`JWT`) - **Base64URL로 인코딩**하면 JWT의 첫 번째 부분이 됨 #### Payload (페이로드) - 사용자 정보와 클레임(Claim) 데이터가 담김 ```json { "sub": "user123", "name": "Alice", "iat": 1516239022 } ``` - 사용자의 고유한 정보와 권한, 토큰 발급 시간(`iat`) 등이 포함됨 - **민감한 정보를 포함 금지** - **Base64URL로 인코딩**하면 JWT의 두 번째 부분이 됨 #### Signature (서명) - 헤더와 페이로드가 변조되지 않았음을 검증 ``` HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret ) ``` - 서버의 비밀키(Secret Key)로 생성 - 클라이언트가 보낸 토큰이 변조되지 않았다는 것을 검증함
### 2) JWT workflow
### 3) JWT 사용 예시 앱 A가 Gmail과 연동되어 이메일을 읽어와야 하는 경우 (1) 사용자가 Gmail 인증서버에 로그인 (2) 인증에 성공하면 서버는 **JWT 발급** (3) 앱 A는 JWT를 Authorization 헤더에 넣어 Gmail API 요청 (4) Gmail 서버는 JWT의 서명을 검증 후 이메일 데이터를 반환 ➡️ 사용자는 Gmail 비밀번호를 앱 A에 제공하지 않아도 안전하게 데이터 연동 가능
### 4) JWT 실무 팁 잘못 사용하면 보안에 취약할 수 있음 #### 민감한 정보 포함 금지 - JWT는 Base64URL로 인코딩되어 있을 뿐 암호화되어 있지 않음 #### 토큰 만료 시간 설정 - 만료 시간(`exp`)을 반드시 설정 - 만료 시간이 없는 토큰은 탈취될 경우 영구적으로 악용될 수 있음 #### HTTPS 사용 - JWT는 네트워크를 통해 전달되므로, 반드시 HTTPS를 통해 암호화된 채널에서만 전송 #### 저장 위치 주의 - 로컬 스토리지(`localStorage`) 대신 **HTTPOnly 쿠키** 또는 보안이 강화된 세션 스토리지 사용을 권장 - 로컬 스토리지는 XSS 공격에 취약 #### 토큰 무효화 전략 - 기본적으로 JWT는 발급 후 만료 전까지 무효화할 수 없음 - 이를 보완하기 위해 서버 측에서 블랙리스트를 관리하거나 Redis 같은 인메모리 DB 활용
## 4-04. Refresh 토큰의 이해 보안성과 편의성을 동시에 만족하기 위해서 **Access 토큰과 Refresh 토큰을 분리**하는 방식을 사용
### 1) Access 토큰과 Refresh 토큰의 역할 | 구분 | Access 토큰 | Refresh 토큰 | | ----------- | ------------------------------- | ------------------------------------------- | | 목적 | 리소스 서버 접근 권한 부여 | 새로운 Access 토큰 발급 요청 | | 유효 기간 | 짧음 (분 단위 \~ 수십 분) | 김 (일 단위 \~ 수주) | | 보관 위치 | 클라이언트(브라우저/앱) | 클라이언트 안전 영역(예: Secure Storage) | | 보안 리스크 | 탈취 시 제한된 시간만 사용 가능 | 탈취 시 장기간 사용 가능 → 강화된 보안 필요 | - **Access 토큰** : 실제 API 요청에 사용 - **Refresh 토큰** : Access 토큰 재발급 용도
### 2) 토큰을 나누는 이유 #### 보안성 강화 - Access 토큰은 짧은 만료 시간으로 발급 ➡️ 탈취되더라도 금방 무력화됨 - Refresh 토큰은 더 오래 유지되지만, 오직 **재발급 요청**에만 사용됨 #### 사용자 경험 개선 - 사용자가 매번 로그인할 필요 없음 - Access 토큰이 만료되면 Refresh 토큰을 이용해 자동으로 새 Access 토큰을 발급
### 3) 토큰 갱신 workflow
### 4) 토큰 만료 및 무효화 처리 #### Access 토큰 만료 - 기본적으로 수 분 ~ 수십 분 ➡️ 탈취 시, 피해를 최소화하기 위함 #### Refresh 토큰 만료 - 보통 일 단위 또는 주 단위 - 장기간 보관되므로 **DB 저장 후 화이트리스트/블랙리스트 방식**으로 관리하는 경우가 많음 #### 무효화 전략 - 강제 로그아웃: 서버 DB에서 Refresh 토큰을 제거 - 토큰 로테이션: Refresh 토큰 사용 시마다 새 Refresh 토큰 발급, 이전 것 무효화
### 5) Access 토큰과 Refresh 토큰 실무 팁 - **모바일 앱**은 Refresh 토큰을 Secure Storage(Keychain, Keystore 등)에 저장 - **브라우저 환경**에서는 Refresh 토큰을 쿠키(HttpOnly + Secure + SameSite)로 관리 ---
Leave a comment