이번 글에서는 웹 어플리케이션의 인증 방식에 대해 알아보려고 한다.
인증 방식을 알아가기에 앞서, 인증과 인가란 무엇인지, 웹 어플리케이션 인증에 어떤 특수성이 있는지, 어떤 인증 방식이 있는지 살펴보자.
인증 / 인가
- 인증(Authentication)
- 해당 유저가 실제 유저인지 인증하는 개념
- 사용자의 신원을 검증하는 프로세스
- ex) ID, PW 로 로그인하는 행위
- 인가(Authorization)
- 인증 이후의 프로세스로, 인증된 유저가 어떠한 자원에 접근할 수 있는지 확인하는 절차
- ex) 관리자 페이지 - 관리자 권한
웹 어플리케이션 인증의 특수성
- 일반적으로 서버 - 클라이언트 구조로 되어 있다.
- Http 프로토콜을 이용하여 통신한다. → 비연결성(Connectionless), 무상태(Stateless)의 특징을 지닌다.
비연결성(Connectionless)
- 서버와 클라이언트가 연결되어 있지 않다.
- 서버와 클라이언트가 계속 연결되어 있다면, 서버의 비용이 기하급수적으로 늘어난다.
- 리소스의 절약을 위해 서버는 하나의 요청에 하나의 응답을 보내고 연결을 끊는다.
무상태(Stateless)
- 서버가 클라이언트의 이전 상태를 저장하지 않는다. 클라이언트가 직전에 무슨 요청을 보냈었는지 알지 못한다.
- 기존의 상태를 저장하는 것은 서버의 비용과 부담을 증가시키기 때문에, 기존의 상태가 없다고 가정하는 프로토콜을 구현한다.
웹 어플리케이션 인증 방식
Http의 Connectionless와 Stateless라는 특성을 생각해보면, 사용자가 로그인을 통해 인증을 거쳐도, 이후 요청에 대해서는 인증된 상태를 유지할 수 없다. 서버가 사용자가 로그인을 했다는 정보를 저장하지 않기 때문에, 최초 로그인 이후 매 요청마다 반복적으로 ID, PW를 입력하여 페이지 접근 인가를 받아야 하는 것이다.
하지만, 우리는 웹 어플리케이션을 이용할 때, 로그인을 한 번 하면 그 이후에 반복해서 로그인 하지 않아도, 회원이 접속 가능한 페이지에 접근이 가능하다.
Connectionnless, Stateless한 Http 프로토콜에서 인증 / 인가가 어떤 방식으로 이루어지는지 바로 살펴보자!
쿠키(Cookie)
- 클라이언트에 저장될 목적으로 생성한 작은 정보를 담은 파일(서버에서 사용자 브라우저로 전송한다.)
- 브라우저는 서버에서 받은 쿠키를 저장해두었다가, 동일한 서버로 재요청할 때 쿠키를 함께 전송한다.
- 사용자가 로그인을 하면, 서버는 ID, PW 정보를 쿠키에 담아 브라우저로 다시 보낸다. 이후 브라우저에서는 요청할 때마다 로그인 정보가 담긴 쿠키를 함께 서버로 보낸다. 브라우저에서 매번 요청할 때마다 서버 입장에서는 로그인 정보가 담긴 쿠키를 받게 되는 것이다.
쿠키의 장점
- 기존 로그인 정보를 사용하기 때문에 인증을 위한 추가적인 데이터 저장이 필요 없다.(쿠키는 서버가 아닌 클라이언트 웹 브라우저에 한다.)
쿠키의 단점
- 사용자의 주요 정보를 매번 요청에 담기 때문에 보안상 문제가 있다.
- 클라이언트에서 쿠키 정보를 쉽게 변경, 삭제할 수 있고, 가로채기 당할 수도 있다.
- 쿠키 사이즈가 커질수록 네트워크 부하가 심해진다.
쿠키의 구성요소
- Name(이름) : 쿠키를 구별하는 데 사용되는 키 (중복 불가)
- Value(값) : 쿠키의 값
- Domain(도메인) : 쿠키가 저장된 도메인
- Path(경로) : 쿠키가 사용되는 경로
- Expires(만료기한) : 쿠키의 만료기한
세션(Session)
- 서버에서 일정시간 동안 클라이언트 상태를 유지하기 위해 사용한다.
- 서버에서 클라이언트별 유일한 세션 ID를 부여하고, 세션 정보를 서버에 저장한다.
- 세션 ID : 사용자의 주요 정보가 아닌, 단지 사용자를 식별할 수 있는 값을 생성한다. → 보안 강화
- 서버에서 생성한 세션 ID는 클라이언트의 쿠키 값(세션 쿠키)으로 저장되고, 클라이언트에서 요청을 보낼 때 이 세션 쿠키를 함께 보낸다. 서버에서는 클라이언트별 세션 쿠키 값이 저장되어 있으니, 요청으로 온 세션 쿠키 값을 보고 어떤 클라이언트인지 식별할 수 있다.
세션의 장점
- 사용자의 로그인 정보를 주고 받지 않기 때문에 상대적으로 안전하다.
- 사용자마다 고유한 세션 ID가 발급되기 때문에, 요청이 들어올 때마다 회원DB를 찾지 않아도 된다.
세션의 단점
- 사용자를 식별할 수 있는 값인 세션 ID를 생성하고, 서버에 저장해야하는 작업이 생긴다.
- 서버 세션 저장소를 사용하므로 요청이 많아지면 서버 부하가 심해진다.
JWT(JSON Web Token)
- JWT : 인증에 필요한 정보들을 암호화시킨 토큰
- JWT 토큰(Access Token)을 HTTP 헤더에 담아 서버가 클라이언트를 식별한다.
JWT 구조
- Header
-
토큰 타입, 해쉬 알고리즘(HS256 or RSA 등)으로 구성되어 있다.
{
"alg": "HS256",
"typ": "JWT"
}
- Payload
-
claim이 포함되는 영역으로, 토큰에 담을 정보를 갖고 있다.
- claim : key-value 형식으로 이루어진 한 쌍의 정보로, 엔티티(주로 사용자)에 대한 속성을 설명한다.
-
클라이언트 고유 ID 값이나 유효 기간 등이 포함되는 영역이다.
{
"sub": "1234567890",
"username": "user1",
"admin": true
}
- Signature
-
인코딩된 Header와 Payload를 더한 뒤, secret key로 해싱해서 생성한다. 이 때, 해싱 방법은 Header에서 지정한 해쉬 알고리즘 방법으로 한다.
-
Header와 Payload는 단순히 인코딩된 값이어서 누구든 복호화가 가능하나, Signature는 서버 측에서 관리하는 secret key가 있어야 복호화가 가능하다.
-
Signature 부분으로 토큰의 위변조 여부를 확인할 수 있다.
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
JWT의 작동
-
클라이언트가 ID, PW 로그인 요청을 보낸다.
-
회원 DB에서 사용자를 확인한다.
-
로그인 성공 시, 서버는 로그인 정보를 Payload에 담고, Secret Key를 사용해서 Access Token(JWT)을 발급한다.
-
서버가 JWT를 Client에 전달한다. 이 때 전달방법은 개발자가 정한다.
ex) 응답 Header에 Authorization: BEARER <JWT>
형태로 전달
-
클라이언트는 전달받은 토큰(JWT)을 저장한다.(쿠키, local storage 등)
-
클라이언트가 서버에 요청할 때마다 토큰(JWT)을 요청 Header의 Authorization
에 포함시켜 함께 전달한다.
-
서버는 클라이언트가 전달한 토큰의 Signature를 secret Key로 복호화한 후, 위변조 여부 및 유효기간을 검증한다.
-
검증에 성공하면, JWT에서 사용자 정보를 확인하고 요청에 응답한다.
JWT 장점
- 동시 접속자가 많을 때 서버 부하를 낮춘다.
- 클라이언트, 서버가 다른 도메인을 사용할 때 사용 가능하다.
- ex) 카카오 OAuth2 로그인 시 JWT 토큰 사용
- 인증 정보를 서버에 별도로 저장할 필요가 없다. → 서버의 Stateless 특성이 유지된다.
JWT 단점
- 구현 복잡도가 증가한다.
- JWT에 담는 내용이 커질수록 네트워크 비용이 증가한다.
- 이미 생성된 JWT를 일부만 만료시킬 방법이 없다. (토큰의 유효기간을 너무 길게 잡으면 안된다.)
- Secret Key 유출 시 JWT 조작이 가능하다.
- Payload 자체는 암호화되지 않기 때문에 사용자의 중요한 정보는 담을 수 없다.
[참고자료]
https://dev.gmarket.com/45
https://samtao.tistory.com/64
https://tecoble.techcourse.co.kr/post/2021-05-22-cookie-session-jwt/