티스토리 뷰

 
로그인과 회원가입을 구현할 때 알아야 할 중요한 개념 중 하나가 인증과 인가이다. 하지만 둘의 개념은 혼동하기 쉽기 때문에 간단한 예시와 함께 이해해 보려고 한다.
 

 

1. 인증(Authentication) vs 인가(Authorization)


인증과 인가 서비스를 제공하는 authO에 둘의 개념이 잘 나와 있다.
 

1. 인증(Authentication)

인증은 사용자의 신원을 확인하는 것이다.
 
두 가지 예시를 보자.
 
은행 창구에 가서 돈을 인출하려고 하면 직원은 신원을 확인하기 위해 신분증을 요구한다. 비행기에 탑승하기 전에도 여권을 통해 신원을 확인해야만 비행기에 탑승할 수 있다.
 
위 예시 모두 우리의 신원을 확인하기 위해 어떤 절차를 걸치며 이를 인증이라고 한다.
 
2. 인가(Authorization)
 
인가는 인증과는 조금 다른 개념이다. 
 
인가는 사용자가 어떤 리소스에 접근할 수 있는지, 또는 어떤 동작을 수행할 수 있는지를 확인하는 절차 말한다.
 
예를 들어 공연장에 입장하기 위해 티켓을 구매하는 경우, 우리는 신분증 제시나 여권 제시 등 별다른 절차 없이(인증 없이) 티켓을 구매할 수 있다. 공연 기획사가 관심있는 것은 우리가 공연장에 입장할 권한이 있는지에 대한 여부이다.

그렇다면 입장 권한은 어떻게 증명할 수 있을까?
 
바로 입장 티켓으로 증명할 수 있다. 여기서 알 수 있는 것은 티켓이 우리의 신원 정보를 포함하고 있지 않더라도, 인가 과정에서 검증이 실패하는 것은 아니다.
 
따라서 인증은 인가로 이어지지만, 인가는 인증으로 이어지지 않는다는 점도 알 수 있게 된다.
 
비행기 탑승 예시를 다시 생각해보자.
비행기 탑승권은 비행기를 타는 데 인가를 하는 역할도 하고 신원 증명(인증)의 역할도 한다. 따라서 승무원들은 탑승권으로 우리의 이름을 알 수 있다. 
 
반면, 입장 티켓은 신원의 세부사항을 담고 있지는 않다. 티켓은 단지 공연장에 입장할 권리를 나타낼 뿐, 다른 무엇도 아니다.
 

 

2. HTTP의 stateless


이제 컴퓨터 세계(?)에서의 인증과 인가를 생각해보자.
 
웹 애플리케이션에는 클라이언트서버가 존재한다. 서버에는 리소스가 존재하고 클라이언트는 서버의 리소스에 접근할 수 없다. 
 
만약 클라이언트가 서버 측의 어떤 리소스에 접근하려면 로그인과 같은 인증을 받아야 한다.  
 
그런데 로그인을 통해 리소스에 접근할 수 있다고 해도, 문제가 하나 있다. 바로 로그인 이후의 요청에서는 이전의 인증된 상태가 유지되지 않는다는 것이다. 
 
다시말해 이런 상황에서 웹 사이트를 이용하려면 인증/인가가 필요한 모든 상황에서 사용자는 반복적을 ID/PW를 입력해야하는 불상사가 생기게 된다.
 
이러한 상황이 발생하는 이유가 뭘까?
 
바로 우리가 이용하는 웹 사이트가 HTTP 위에서 동작하기 때문이다.
HTTP는 비상태성(stateless) 이라는 특성을 갖기 때문에 각 요청은 이전에 수행된 작업을 인식하지 못한다. 즉, 서버에서 클라이언트의 이전 상태를 기억하고 있지 않는다.
 
이런 한계를 극복하기 위해 여러 인증 방법이 등장하게 되었고, 그 중 세션 기반 인증토큰 기반 인증 두 가지에 대해 알아보자.
 
 
 

3. 세션 기반 인증


https://hackernoon.com/using-session-cookies-vs-jwt-for-authentication-sd2v3vci

 
세션 기반 인증은 사용자의 인증 정보가 세션 저장소에 저장되는 방식이다.
사용자가 로그인을 하면 서버는 사용자를 위한 세션을 생성하고, 세션 데이터를 서버 메모리에 저장한다.
 
사용자에게는 저장된 세션 정보의 식별자인 Session ID를 발급하는데, 발급된 Session ID는 브라우저에 쿠키 형태로 저장되지만, 실제 인증 정보는 서버에 저장되어 있다.
 
인증 절차를 마친 브라우저는 매 요청마다 HTTP Cookie 헤더에 Session ID를 함께 서버로 전송한다. 서버는 요청을 전달받고 Session ID에 해당하는 세션 데이터가 세션 저장소에 존재한다면 해당 사용자를 인증된 사용자로 판단한다.
 
 
 

4. 토큰 기반 인증


https://hackernoon.com/using-session-cookies-vs-jwt-for-authentication-sd2v3vci

 
세션 기반 인증이 인증 정보를 서버에 저장하는 방식이라면, 토큰 기반 인증은 인증 정보가 클라이언트에 저장되는 방식이다. 따라서 서버는 세션 기반 인증과 다르게 발급 검증 두 가지 역할만 할 뿐 유저의 직접적인 정보를 갖고 있지 않다.
 
이때 인증 정보가 토큰의 형태로 브라우저의 로컬 스토리지(혹은 쿠키)에 저장된다. 
 
토큰의 종류에 따라 다르겠지만, 대표적인 토큰인 JWT의 경우 디지털 서명이 존재해 토큰의 내용이 위변조 되었는지 서버측에서 확인할 수 있다.
 
클라이언트는 사용자가 가지고 있는 토큰을 HTTP 의 Authorization 헤더에 실어 보낸다.

headers:{
"Authorization": "Bearer ${JWT_TOKEN}"
}

 

이후 서버는 토큰이 위변조 되었거나, 만료 시각이 지나지 않은지 확인한 이후 토큰에 담겨있는 사용자 인증 정보를 확인한다.
 

JWT란?

앞서 언급한 JWT에 대해 간략하게 정리해보자.

JWT(Json Web Token)이란 RFC 7519 에 명세되어 있는 국제 표준으로써, 통신 양자간의 정보를 JSON 형식을 사용하여 안전하게 전송하기 위한 방법이다.

JWT는 정보가 토큰 자체에 포함된(Self-Contained) 클레임(Claim) 기반 토큰이며 일반적으로 인증(Authentication) 과 인가(Authorization)에 사용된다.

인증 절차를 거쳐 서버에서 JWT 를 발급해주면, 클라이언트는 API 등을 사용할 때에 서버에 JWT를 함께 제출하며 서버로부터 행위에 대해 인가 받을 수 있다.

 
JWT와 같이 토큰 자체에 정보가 저장되는 형태의 토큰은 세션과 달리 유저 정보가 클라이언트에게 저장되기 때문에 노출되기 매우 쉽다. 따라서 민감한 정보를 담아서는 절대 안된다.
 
또한 토큰 사이즈는 세션 ID에 비해 굉장히 비대하다. 따라서 토큰 기반 인증을 사용하기 위해서는 토큰을 사용하여 통신하면서 발생하는 오버헤드를 감안해야 한다.
 
 

 

5. 세션기반 인증 vs 토큰기반 인증


사이즈

 

https://developer.okta.com/blog/2017/08/17/why-jwts-suck-as-session-tokens

 
세션의 경우 Cookie 헤더에 세션 ID만 실어 보내면 되므로 트래픽을 적게 사용한다. 
 
하지만 JWT는 사용자 인증 정보와 토큰의 발급시각, 만료시각, 토큰의 ID등 담겨있는 정보가 세션 ID에 비해 비대하므로 세션 방식보다 훨씬 더 많은 네트워크 트래픽을 사용한다.
 
Why JWTs Suck as Session Tokens 게시물에 따르면, 단순히 JWT에 iss, sub, nbf, exp, iat, jti, typ 클레임만을 실었는데 304 바이트가 나왔다고 한다. 그에 비해 세션 ID는 단 6바이트가 나왔다. 50배가 넘는 트래픽 비효율이다. 
 

 

안전성과 보안문제

세션은 모든 인증 정보를 서버에서 관리한다. 따라서 보안 측면에서 좀 더 유리한데, 만약 세션 ID가 해커에게 탈취되더라도 서버측에서 해당 세션을 무효 처리 하면 되기 때문이다.
 
그러나 토큰은 클라이언트가 모든 인증정보를 가지고 있다. 따라서 토큰이 해커에게 한 번 탈취당하면 토큰이 만료되기 전 까지는 속수무책으로 피해를 입는다.
 
또한 JWT에 실린 Payload는 별도로 암호화 되어 있지 않기 때문에 민감한 데이터를 실어서는 안된다. 하지만 세션은 모든 데이터가 서버에 저장되어 아무나 열람할 수 없으므로 저장할 수 있는 데이터에 제한이 없다. 

 
 
 

확장성

그럼에도 최근의 웹 어플리케이션이 토큰 기반 인증을 사용하는 이유는 확장성 때문이다.
 
세션 기반 인증에서는 서버가 각 사용자의 세션 정보를 저장하고 관리한다. 이러한 방식은 단일 서버 환경에서는 잘 작동하지만, 수평 확장(Scale out) 을 할 때 다음과 같은 문제를 일으킬 수 있다.

 

  • 세션 불일치 문제: 사용자가 서버 A에 접속하여 세션을 생성했지만, 다음 요청이 서버 B로 라우팅되면 서버 B는 해당 세션 정보를 가지고 있지 않다. 따라서 세션 불일치 문제를 일으키게 된다.
  • Sticky Session: 위 문제를 해결하기 위해 Sticky Session을 사용할 수 있다. Sticky Session는 사용자의 모든 요청이 동일한 서버로 라우팅되도록 하는 방식이다. 그러나 이 방법은 서버 간 부하 분산을 저해하고, 특정 서버에 과도한 부하가 걸리게 할 수 있다.
  • Session Clustering: 세션 정보를 여러 서버 간에 공유하는 방법이다. Session Clustering는 세션 정보를 각 서버에 복제하거나, 중앙 집중식 세션 스토리지를 사용하는 방식이다. 이 방법은 구현이 복잡하고 네트워크 오버헤드가 증가할 수 있다.
  • 세션 스토리지 외부 분리: 세션 정보를 데이터베이스나 Redis와 같은 외부 스토리지에 저장하여 모든 서버가 세션 정보를 공유할 수 있도록 할 수있다. 이는 세션 불일치 문제를 해결할 수 있지만, 외부 스토리지의 성능과 가용성에 의존하게 된다.

토큰 기반 인증 방식의 경우 서버가 직접 인증 방식을 저장하지 않고, 클라이언트가 저장하는 방식을 취하기 때문에 이런 세션 불일치 문제로부터 자유롭다.
 
이런 특징으로 토큰 기반 인증 방식은 HTTP의 비상태성(Stateless)를 그대로 활용할 수 있고, 따라서 높은 확장성을 가질 수 있다.

 
 
 

서버의 부담

세션 기반 인증 방식은 서비스가 세션 데이터를 직접 저장하고 관리한다. 따라서 세션 데이터의 양이 많아지면 많아질수록 서버의 부담이 증가할 것이다.
 
하지만 토큰 기반 인증 방식은 서버가 인증 데이터를 가지고 있는 대신, 클라이언트가 인증 데이터를 직접 가지고 있다. 따라서 유저의 수가 얼마나 되던 서버의 부담이 증가하지 않는다.
 
따라서 서버의 부담 측면에서는 세션 기반 인증 방식보다는 토큰 기반 인증 방식이 조금 더 유리하다.


 
오늘은 인증과 인가, 세션 기반 인증과 토큰 기반 인증에 대해 알아보았다. 
 
해당 주제들을 공부하면서 서버 지식도 함께 알게되어 유익한 시간이었고, 특히 최근 모던 웹앱에서 JWT 방식으로 구현을 많이 하지만 단점도 존재하기 때문에, 좋은 기술을 찾기 보다는 현재 상황에 적합 기술을 사용하는 것이 중요하다는 생각이 들었다.
 
 

 
참고
https://auth0.com/intro-to-iam/authentication-vs-authorization

https://hackernoon.com/using-session-cookies-vs-jwt-for-authentication-sd2v3vci
https://hudi.blog/session-based-auth-vs-token-based-auth/
https://developer.okta.com/blog/2017/08/17/why-jwts-suck-as-session-tokens