알고리즘 주간에 진입하기 전에 진행했던 미니프로젝트에서 제일 어려웠던 부분은 역시 JWT(Jason Web Token)과 API(Application Programming Interface)였다.
사전 준비 기간에는 단순히 강의롤 보고 따라하면서 웹페이지의 모양새와 배포를 구현하는데 그쳤다면, 이번 프로젝트에서 내가 제일 주의를 기울이고, 구현하려고 노력했던 부분은 jwt를 이용한 회원가입과 로로그아웃 기능이었다.(로그인 기능은 다른 팀원분이 맡아서 하셨지만, 헷갈리지 않고 제대로 구현하려면 내가 로그인 기능을 맡아서 하는게 맞았던 것 같다. 어쨌든 지난 일이지만...)
우선 JWT에 대해서 정리를 해보았다.

사용자가 ID와 PW를 입력하면 서버로 전송이 된다. 서버에서는 ID, PW를 DB에서 조회하고 회원이면 로그인처리를 한다. 하지만 여기서 문제가 발생하는데, http는 사용자가 새로운 요청을 하면 과거에 로그인한 사실을 기억하지 못하기 때문에 이 문제 해결을 위해 예전에는 로그인 할 때 DB에 누가 로그인 했는지 기록을 했다.

로그인을 하면 로그인한 사용자를 위한 토큰을 발급한다. 이 때 발급된 토큰은 계정 정보가 필요한 요청(홈페이지에서 물건을 구입하거나 내역 조회, 내가 쓴 글 보기 등등)을 할 때 이용된다. 토큰에는 요청한 사람의 정보가 담겨 있고, 서버는 DB를 조회하지 않고도 토큰을 이용해 누가 요청하는지 알 수 있다.

- 서버 기반 인증 방식의 핵심은 서버측에서 유저 정보를 저장하는 것이다.
- 세션을 사용하는 방법이 대표적. 유저가 로그인 -> 서버는 해당 유저의 세션을 만듬 -> 서버의 메모리와 데이터 베이스에 세션을 저장함.
- 사용자가 증가해 서버를 확장하면 모든 서버에게 세션의 정보를 공유해야 한다. 따라서 별도의 중앙 세션 관리 서버를 만들어야 한다.
- 문제는 사용자가 늘어날수록 세션으로 저장하는 정보가 증가하기 때문에 메모리를 많이 사용한다. 또한 쿠키는 단일 도메인 및 서브 도메인에서만 작동하기 때문에 여러 도메인에서 관리하기 번거롭다.
JWT의 구성 요소

- 구조 : [Base64(HEADER)].[Base64(PAYLOAD)].[Base64(SIGNATURE)]
- JWT는 . 을 구분자로 3가지 문자열로 구성됨.
- 전송을 위해서 Base64로 인코딩된다.
- Header와 Payload는 디코딩을 하면 평문으로 해독이 가능하기 때문에, 인증정보나 비밀번호와 같은 민감한 정보를 넣으면 안된다. 하지만 Signature는 복호화 할 수 없다.
- 헤더는 JWT 토큰을 어떻게 해석해야 하는지 알려주는 부분
- typ, alg 두 가지 정보로 구성된다.
- alg : 알고리즘 장식을 지정, 서명 및 토큰 검증에 사용함.
- typ : 토큰의 타입을 지정함.
{
"alg": "HS256",
"typ": JWT
}
Payload(내용)
- name / value 쌍으로 이루어져 있다.
- 페이로드에 있는 속성들을 Claim Set이라고 부른다.
- 페이로드는 등록된 클레임 (Registered claims), 공개 클레임(Public claims), 비공개 클레임(Private claims)로 구분된다.
Payload 종류 1: 등록된 클레임(Registered Claim Names)
- ss(issuer): 토큰 발급자
- sub(subject): 토큰 제목
- aud(audience): 토큰 대상자
- exp(expiration): 토큰 만료 시간 - NumericDate 형식으로 작성되어야 한다. ex) 1480849147370
- nbf(not before): 토큰 활성 날짜 - 이 날이 지나기 전에 토큰은 활성화되지 않음.
- iat(issued at): 토큰이 발급된 시간 - 토큰 발급 이후의 경과 시간을 알 수 있다.
- jti(JWT ID): JWT 토큰 식별자 - 중복 방지를 위해 사용하며, 일회용 토큰(Access Token) 등에 사용하면 유용
Payload 종류 2: 공개 클레임(Public Claim)
사용자 정의 클레임으로 공개용 정보를 위해 사용된다. 충돌 방지를 위해 URI 포맷을 이용해야 한다.
{
"https://tandohak.co.kr/is_authenticated": true
}
Payload 종류 3: 비공개 클레임(Private Claim)
등록된 클레임도 아니며, 공개 클래임도 아닌 서버와 클라이언트 사이에 임의로 지정한 정보를 저장하기 위해 만들어진 사용자 지정 클레임입니다.
{
"username": "tandohak"
}
비공개 클레임을 조심해서 사용하지 않으면 등록된 클래임과 공개 클래임과 다르게 충돌이 일어날 수 있기에 주의해야 한다.
Signature(서명)
- 헤더와 페이로드는 암호화 한 것이 아니라 단순히 JSON문자열을 base64로 인코딩 한 것.
- 누구나 디코딩을 한다면 헤더와 페이로드의 내용을 볼 수 있다.
- 누군가 JWT를 탈취하여 수정한 후에 서버로 보낼수 있다. 이 경우를 대비해 다른 사람이 위조 및 변조를 했는지 검증하기 위한 부분이다.
- 서명은 헤더의 인코딩 값과 정보의 인코딩 값을 합친 후 비밀키로 해쉬를 해 생성함.