지난 포스팅에서는 로그인 인증 - 세션과 쿠키 인증 방식에 대해서 알아봤다. 이번엔 토큰 인증 방식에 대해서 알아보려고 한다.
그렇다면, 토큰을 이용한 인증 방식은 뭘까?
토큰 인증 방식은 인증받은 사용자들에게 토큰을 발급하고, 서버에 요청을 할 때 헤더에 토큰을 함께 보내도록 하여 유효성 검사를 한다. 세션 방식과 달리 상태를 유지하지 않으므로 stateless 한 구조를 갖는다.
이러한 토큰 인증 방식에서 대표적으로 사용되는 JWT
를 이용한 토큰 인증 방식에 대해서 알아보고자 한다.
JWT(Jason Web Token)이 뭘까?
JWT
는 정보를 JSON 객체 형태로 사용자에 대한 속성 정보(Claim)를 저장하는 암호화된 문자열(token
)이다. JWT는
토큰 자체를 정보로 사용하는 Self-contained
방식으로 정보를 안전하게 전달한다
JWT 구조
JWT
는 아래와 같이 Header, Payload, Signature의 3 부분으로 이루어지며 JSON 형태인 각 부분은 Base64 url로 인코딩 되어 표현된다. 각각의 부분을 이어 주기 위해 .
구분자를 사용하여 구분한다. Base64 url으로 반환된 값은 암호화된 문자열이 아니고, 같은 문자열에 대해서 항상 같은 인코딩 문자열을 반환한다.
1. Header(헤더)
Header는 typ
와 alg
두 가지 정보로 구성된다. alg는
Header를 암호화하는 것이 아니고 Signature를 해싱하기 위한 알고리즘을 지정하는 것이고, typ는
토큰의 타입을 지정한다.
- typ : 토큰의 타입을 지정 ex) JWT
- alg : 알고리즘 방식을 지정, 서명(Signature) 및 토큰 검증에 사용 ex) HS256(SHA256) 또는 RSA
{
"alg": "RS256",
"typ": "JWT"
}
2. Payload(페이로드)
Payload에는 토큰을 통해 전달할 내용인 클레임(Claim) 정보를 포함하고 있다. Payload에 담는 정보의 한 조각을 클레임이라고 부르고, 이는 name/value의 한 쌍(JSON 형식)으로 이루어져 있다.
토큰에는 여러 개의 클레임들을 넣을 수 있고, 클레임의 정보는 등록된(registered) 클레임, 공개(public) 클레임, 비공개(private) 클레임으로 세 종류가 있다.
2-1 등록된 클레임(Registered Claim)
등록된 클레임은 토큰 정보를 표현하기 위해 이미 정해진 종류의 데이터들이다. "sub"는 주로 사용자 이메일을 사용한다.
{
"iss": 토큰 발급자(issuer)
"sub": 토큰 제목(subject)
"aud": 토큰 대상자(audience)
"exp": 토큰 만료 시간(expiration)
// NumericDate 형식(Unix Time) ex) 1631598299000
"nbf": 토큰 활성 날짜(not before)
// 이 날이 지나기 전의 토큰은 활성화되지 않음
"iat": 토큰 발급 시간(issued at)
// 토큰 발급 이후 경과 시간을 알 수 있음
"jti": JWT 토큰 식별자(JWT ID)
// 중복 방지 및 일회성 토큰(Access Token)에 사용
}
2-2 공개 클레임(Public Claim)
공개 클레임은 사용자 정의 클레임으로, 공개용 정보를 위해서 사용된다. 충돌 방지를 위해서 URI 포맷을 이용한다. 예시는 아래와 같다
{
"https://aosjehdgus.tistory.com/124":true
}
2-3 비공개 클레임(Private Claim)
비공개 클레임은 사용자 정의 클레임으로, 서버와 클라이언트 사이에 임의로 지정한 정보를 저장한다. 예시는 아래와 같다.
{
"token_type": access
}
3. Signature(서명)
서명은 토큰을 인코딩하거나 유효성을 검증할 때 사용하는 고유한 암호화 코드이다. Signature는 Header와 Payload의 값을 각각 Base64 url로 인코딩하고, 인코딩한 값을 비밀 키를 이용해 Header에서 정의한 알고리즘으로 해싱을 하고, 이 값을 다시 Base64 url로 인코딩하여 생성한다.
인증 순서에 대해서 알아보자
- 사용자가 로그인을 한다.
- 서버에서 계정 정보(Claim)를 읽어 사용자를 확인 후, 사용자의 고유한 ID값을 부여한 후, 기타 정보와 함께 Payload에 넣는다.
- JWT 토큰의 유효 기간을 설정한다.
- 암호화할 Secret Key를 이용해 Access Token을 발급한다.
- 사용자는 Access Token을 받아 저장한 후, 인증이 필요한 요청마다 토큰을 헤더에 실어서 보낸다.
- 서버에서는 해당 토큰의 Signature를 Secret Key로 복호화한 후, 조작 여부, 유효 기간을 확인한다.
- 검증이 완료된다면, Payload를 디코딩하여 사용자의 ID에 맞는 데이터를 가져온다.
장점
JWT
를 발급한 후 검증만 하면 되기 때문에 추가 저장소가 필요기 때문에 stateless 한 서버를 만들 수 있다. 따라서 서버를 확장하거나 유지, 보수하는데 유리하다.- 확장성이 뛰어나다. 토큰 기반으로 하는 다른 인증 시스템에 접근이 가능하다. 예를 들어, 소셜 로그인을 들 수 있다.
- 트래픽에 대한 부담이 적다.
단점
- 이미 발급된
JWT
는 돌이킬 수 없다. 따라서 악의적인 사용자는 유효기간 전까지 해당 토큰을 이용하여 해킹할 수 있다.
→ 기존의 Access Token의 유효기간을 짧게 하고 Refresh Token이라는 새로운 토큰을 발급한다.
- Payload 정보가 제한적이다. Payload는 따로 암호화되지 않기 때문에 디코딩하면 누구나 정보를 확인할 수 있다. 따라서 유저의 중요한 정보들을 Payload에 넣을 수 없다.
참고
'Tech' 카테고리의 다른 글
[Tech] AWS EC2 Instance ping test 해보기 (0) | 2022.01.18 |
---|---|
[Tech] 웹 접근성 (0) | 2022.01.11 |
[Tech] 로그인 인증 - 세션과 쿠키 (0) | 2021.09.14 |
[Tech] Javascript 웹 스크래퍼 : Puppeteer 사용해보기 (0) | 2021.08.20 |
[Tech] Visual Studio Code에서 prettier 적용하기 (0) | 2021.04.14 |