본문 바로가기

컴퓨터

[Web] 웹 인증 방식 총정리: Cookie, Session, Token부터 JWT 실무 전략(RTR, Blacklist)까지

참고: https://inpa.tistory.com/entry/WEB-%F0%9F%93%9A-JWTjson-web-token-%EB%9E%80-%F0%9F%92%AF-%EC%A0%95%EB%A6%AC

 

🌐 JWT 토큰 인증 이란? (쿠키 vs 세션 vs 토큰)

Cookie / Session / Token 인증 방식 종류 보통 서버가 클라이언트 인증을 확인하는 방식은 대표적으로 쿠키, 세션, 토큰 3가지 방식이 있다. JWT를 배우기 앞서 우선 쿠키와 세션의 통신 방식을 복습해

inpa.tistory.com

https://inpa.tistory.com/entry/WEB-%F0%9F%93%9A-Access-Token-Refresh-Token-%EC%9B%90%EB%A6%AC-feat-JWT

 

🌐 Access Token & Refresh Token 원리

Access Token & Refresh Token 이번 포스팅에서는 기본 JWT 방식의 인증(보안) 강화 방식인 Access Token & Refresh Token 인증 방식에 대해 알아보겠다. 먼저 JWT(Json Web Token) 에 대해 잘 모르는 독자들은 다음 포스

inpa.tistory.com

https://hyjykelly.tistory.com/147

 

JWT 뿌시기 (세션방식과 비교/정의/구조/검증방법/장단점) (feat.Refresh 토큰)

1. 인증의 필요성 클라이언트는 서버 사이에는 다양한 요청과 응답을 발생한다. 예를 들어 쇼핑몰 사이트에서는 상품 리스트 조회나 주문 처리 등이 있을 것이다. 만약, 서버가 인증 과정 없이

hyjykelly.tistory.com

대표적인 인증 매커니즘인 쿠키와 세션, 토큰의 차이를 정리한다.

1. Cookie 인증

클라이언트의 브라우저에 설치되는 작은 기록 정보 파일이다.

 

1) 클라이언트가 서버에 요청을 보낸다.

2) 서버는 응답을 보내며, 클라이언트에 저장할 정보를 응답 헤더의 Set-Cookie에 담는다.

3) 클라이언트는 요청을 보낼 때마다, 저장된 쿠키를 요청 헤더의 Cookie에 담아 보낸다.

4) 서버는 쿠키에 담긴 정보로 클라이언트를 식별한다.

 

장점

- 구조가 단순하다.

 

단점

- 요청 시 쿠키의 값을 그대로 보내기 때문에, 유출 및 조작 당할 위험이 있어 보안에 취약하다.

- 용량 제한이 있어 많은 정보를 담을 수 없다.

- 브라우저마다 쿠키의 형태가 다르기 때문에, 브라우저간 공유가 불가능하다.

- 쿠키의 사이즈가 커질수록 네트워크에 부하가 심해진다.

 

2. Session 인증

클라이언트의 민감한 인증 정보를, 서버 측에 저장하고 관리한다.

 

세션 객체는 Key에 해당하는 Session ID와, 그 값인 Value(Map 객체)로 구성된다.

Value에는 세션 생성 시간, 마지막 접근 시간, 클라이언트가 저장한 속성 등이 Map 형태로 저장된다.

 

1) 클라이언트가 웹사이트에 로그인하면, 세션이 서버에 Session ID를 기준으로 저장된다.

2) 서버는 응답을 보내며, 응답 헤더의 Set-Cookie에 Session Id를 담는다.

3) 클라이언트는 요청을 보낼 때마다, Session Id를 요청 헤더의 Cookie에 담아 보낸다.

4) 서버는 클라이언트가 보낸 Session Id와 서버에 저장된 Session Id를 비교하여 인증을 수행한다.

 

장점

- 민감한 정보를 클라이언트가 지속적으로 보내지 않고 서버에서 관리하기에, 비교적 안전하다.

- 요청이 외부에 노출되더라도, Session Id만 노출되기에 유의미한 개인정보는 노출되지 않는다.

 

단점

- 해커가 Session Id 자체를 탈취하여, 클라이언트인 척 위장할 수 있다.

- 서버에서 세션 저장소를 사용하므로, 요청이 많아지면 이를 저장하고 조회하는 과정에서 서버에 부하가 심해진다.

- 앱의 경우, 쿠키 기반 인증은 편의성이 떨어진다.

- 클라이언트의 이전 요청(상태)을 서버가 기억해놓고, 이를 기반으로 다음 요청에 응답한다(Stateful). 따라서 사용자가 증가하면 성능 문제(기억해야 하는 상태가 많음)가 발생하고, 확장하기가 어렵다(상태는 특정 서버에만 종속되기에, 로드 밸런싱 시 해당 서버는 기억하지 못할 수 있음)

 

3. Token 인증

클라이언트가 서버에 접속하면, 서버는 해당 클라이언트에게 인증되었다는 의미로 유일한 토큰을 부여한다.

토큰을 클라이언트에 저장하고, 서버는 위조되었는지만 판별한다.

 

1) 클라이언트가 웹사이트에 로그인을 한다.

2) 서버는 유일한 토큰을 발급하여, 클라이언트에게 응답을 보낸다.

3) 클라이언트는 전달받은 토큰을 저장해 두고, 요청을 보낼 때마다 해당 토큰을 HTTP 요청 헤더에 담아 보낸다.

4) 서버는 클라이언트가 보낸 토큰을 검증하고, 요청에 응답한다.

 

장점

- 토큰을 클라이언트에 저장하고, 서버는 위조되었는지만 판별하기에 서버의 부담을 덜 수 있다(stateless).

- 앱과 서버 간 통신 및 인증에도 활용하기 좋다.

 

단점

- 토큰 자체의 길이가 길어, 인증 요청이 많아질수록 네트워크 부하가 심해질 수 있다.

- Payload 자체는 암호화되지 않기 때문에, 민감한 정보는 담을 수 없다.

- 토큰을 탈취당하면 강제 만료가 어렵다.

 

4. JWT(JSON Web Token)

JWT는 인증에 필요한 JSON 데이터를 Base64 URL-safe Encode를 통해 인코딩하여 직렬화한 것이다.

JWT 기반 인증은 JWT Access Token을 HTTP 요청 헤더에 실어 서버가 클라이언트를 식별하는 방식이다.

토큰 내부에는 위변조 방지를 위해 개인키를 통한 전자서명이 들어있어, 서버는 서명을 검증한 뒤 요청한 응답을 돌려준다.

 

JWT는 .을 구분자로 세 가지 문자열을 조합한 것이다.

Header(헤더)에는 JWT 타입과, 해시 알고리즘 종류가 담겨 있다.

Payload(내용)에는 서버에서 조회한 사용자 권한 정보와 데이터가 담겨 있다(Claims - key value 쌍).

-Registered Claims: 미리 정의된 클레임(발행자, 만료시간, 제목, 발행시간, JWT ID)

-Public Claims: 공개용 정보 전달을 위해 사용하는, 사용자 정의 클레임(이름이 겹치지 않는 URI 형식)

-Private Claims: 서버-클라이언트 간 합의하여 사용하는, public claims 이외의 사용자 정의 클레임

Signature(서명)에는 Header와 Payload를 각각 Base64URL로 인코딩하여 이를 .으로 연결한 것과, 서버가 가지고 있는 키 값을 이용해 암호화(해시 알고리즘 이용)한 결과가 담겨 있다.

-대칭키 방식: 서버가 가진 비밀키로 Header와 Payload를 서명 및 검증한다.

-비대칭키 방식: 서버가 가진 개인키로 Header와 Payload를 서명한다. 검증은 공개키로 진행한다.

 

1) 클라이언트가 웹사이트에 로그인을 한다.

2) 서버는 Header, Payload, Signature를 정의하고, 이를 Base64로 인코딩하여 JWT를 생성한 뒤 이를 응답 바디에 담는다.

3) 클라이언트는 전달받은 JWT를 저장해 두고, 요청을 보낼 때마다 해당 토큰을 Authorization Header에 Bearer 타입으로 담아 보낸다.

4) 서버는 클라이언트가 보낸 토큰이 해당 서버에서 발행한 토큰인지 검증하고, 요청에 응답한다.

- 대칭키 방식: Header와 Payload를 서버가 가진 비밀키로 서명해서, 전달받은 서명값과 동일한지 확인

- 비대칭키 방식: 서명값을 서버가 가진 공개키로 검증해서, Header.Payload와 동일한지 확인

5) 클라이언트가 서버에 요청을 했는데, JWT(Access Token)의 시간이 만료되면 클라이언트는 Refresh Token을 이용해서 서버로부터 새로운 Access Token을 발급받는다.

 

장점

- Header와 Payload를 가지고 Signature를 생성하므로, 데이터 위변조를 막을 수 있다.

- 필요한 모든 정보를 JWT가 자체적으로 지니고 있어 서버가 인증 정보를 저장할 필요가 없기에, 서버 확장성이 높다(Stateless).

- 토큰 기반으로, 다른 로그인 시스템에 접근 및 권한 공유가 가능하다.

- 모바일 어플리케이션 환경에서도 잘 작동한다.

 

단점

- 토큰 자체에 정보를 담고 있고 payload 자체는 암호화된 것이 아니므로, 중요 데이터를 넣지 않아야 한다.

- 정보가 많아질수록 토큰의 길이가 늘어나, 네트워크에 부하를 줄 수 있다.

- 토큰 자체를 탈취당하면 대처하기 어렵다.

 

5. Access Token / Refresh Token 전략

토큰 탈취의 위험성이 있기 때문에, Access Token과 Refresh Token으로 나누어 활용한다.

 

Access Token

클라이언트 정보가 담긴 토큰으로, 클라이언트에 저장했다가 서버에 API를 요청할 때 활용한다.

발급한 후 삭제가 불가능하기 때문에, 짧은 유효시간을 부여하여 탈취 문제에 대응한다.

 

Refresh Token

새로운 Access Token을 발급하기 위해 사용하는 토큰으로, 클라이언트와와 서버 데이터베이스에 저장한다.

첫 로그인 시 Access Token과 함께 발급된다

긴 유효기간을 가지며, Access Token 만료 시 새로 재발급하는 역할을 하여 유효기간이 짧아 클라이언트가 로그인을 자주 해야 하는 불편함을 줄여준다.

 

Refresh Token을 도입하게 되면, Stateless와 Stateful의 중간 상태가 된다.

토큰 탈취 대비를 위해, 서버나 DB에 Refresh Token을 저장해야 하기 때문이다.

하지만 일반 API의 경우에는 여전히 DB 조회 없이 Stateless하게 운영이 가능하고,

인증 및 토큰 재발급 부분만 Stateful하게 진행되므로

온전히 Stateless하면서 토큰 탈취 시 보안이 취약해지는 것에 비해

일부 Stateful한 부분을 도입하고 성능 부분에서 타협을 함으로써 보안성을 확보할 수 있는 방법이다.

 

1) 클라이언트가 웹사이트에 로그인한다.

2) 서버는 회원 DB에서 값을 비교하고, Access Token과 Refresh Token을 발급한다. 이때 회원 DB에도 Refresh Token을 저장한다.

3) 클라이언트는 Refresh Token을 안전하게 저장하고, 요청을 보낼 때마다 Access Token을 Authorization: Bearer <Access_Token> 헤더에 담아 보낸다.

4) 서버는 Access Token의 서명과 만료시간만 검증하여, 이에 맞는 데이터를 보낸다.

5) Access Token 만료 시, 서버는 401 Unauthorized를 보낸다.

6) 클라이언트는 Refresh Token을 서버로 보낸다.

7) 서버는 Refresh Token을 조회하여 만료시간이 지나지 않았다면 새로운 Access Token과 새 Refresh Token을 발급한다.

8) Refresh Token이 만료되었다면, 재로그인을 요구한다.

9) 로그아웃 시 클라이언트의 Access Token과 DB의 Refresh Token 모두를 삭제한다.

 

6. 보안 강화 및 실무 전략

RTR(Refresh Token Rotation)

Refresh Token을 1회 사용 시 즉시 폐기 및 재발급한다.

탈취자가 이전 Refresh Token을 재사용하려고 시도하면, 해당 사용자의 모든 세션을 강제 종료시킬 수 있다.

 

JWT의 근본적 한계와 블랙리스트

로그아웃 시, 이미 발급된 Access Token은 만료시간이 끝나기 전까지는 강제로 만료할 수 없다.

이를 위해, 로그아웃 요청 시 넘어온 Access Token의 남은 시간(TTL)만큼 Redis 등에 블랙리스트로 등록한다.

블랙리스트에 있는 토큰은 API 호출 시 401 Unauthorized로 차단하면, 탈취 시의 문제를 해결할 수 있다.

 

7. 한눈에 보는 비교 요약


항목 쿠키 (Cookie) 세션 (Session) JWT (Access/Refresh)
저장 위치 클라이언트 (브라우저) 서버 (메모리/DB) 클라이언트 + 서버(Refresh만)
상태 관리 Stateless Stateful 하이브리드 (일반 API: Stateless)
확장성 높음 낮음 (서버 간 동기화 필요) 매우 높음
보안 통제력 낮음 높음 (서버에서 세션 즉시 삭제 가능) 중간 (RTR / 블랙리스트로 보완 필요)
적합한 환경 단순 정적 웹 높은 보안이 필수인 내부 시스템 대규모 트래픽 웹/앱, MSA 아키텍처