본문 바로가기

Sparta

[Sparta] 07. 로그인과 JWT.md

2021-09-24

To-Do

  • 7시 기상
  • 아침식사
  • 오전운동 ()

 

  • 잠을 설쳤다. 모기를 두마리나 잡았는데, 두놈 다 피를 뱉지 않았다... 나는 분명히 물렸는데... 덕분에 너무 힘든 아침이었다. 커피를 마셔도 너무 피곤해서, 알람을 맞춰두고 한시간 자버렸다. 역시 졸릴땐 버티는거 보다 잠깐이라도 자는게 최고인거 같다.

 

Today I Learned

 

1. 로그인

 

내가 잼민이 시절, 메이플스토리를 하면 이런 공지문구가 보이곤 했다.

 

운영자는 절대 유저의 비밀번호를 묻지 않습니다.

 

나는 "아 ㅋㅋ 운영자는 컴퓨터 보면 다 알텐데 물어볼리가 없지"라고 생각했고, 이내, "잠깐, 내 비번을 다 안다고?"라는 의문이 들었다. 그래서 대충 찾아보니 역시나 세상엔 똑똑한 사람이 많다는걸 다시금 느꼈다. 정확히는 모르겠지만, 내 비밀번호는 "해쉬"되어 잘 관리되고 있었다.

(사실 이 "해쉬"에도 할말이 많지만, 오늘의 주제는 아니니 넘어가겠다.)

이제 서버 개발을하고 있는 나는 로그인이라는 작업이 얼마나 까다로운지 피부로 느끼고있다. 그리고 이 로그인 작업보다 훨씬 까다로운게 "로그인을 유지"하는 것이었다....

 

로그인은 서버에 한번 인증(Authentication)받으면 된다. 내가 입력한 ID와 PW(물론, 해쉬된)를 서버의 DB에 저장된 ID, PW 대조하여 일치한다면 인증을 해주는 것이다.

 

하지만 로그인을 유지하는 것, 즉 인가(Authorization)는 조금 다르다. 인가는 한번 인증을 득한 사용자가 이후의 인증받은 서비스의 여러 기능을 사용할 때, 서버가 해당 사용자에게 허가를 해주는 것을 말한다. 그러니까 "로그인이 유지"된 상태에서, 좋아요를 누르거나, 댓글을 달거나 하는 활동을 "인가"해주는 것이다.

2. JWT

JWT는 인증(Authentication)보다는 인가(Authorization)에 관한 기술이다. 나는 Flask로 서버를 만들었기 때문에, PyJWT로 Token을 만들었고, 이는 cookie(브라우저에서 사용하는 데이터베이스라고 생각하면 쉽다.)로 브라우저에 저장되어 사용자에게 Authorization을 부여했다.

 

쿠키란, 페이지에 관계없이, 브라우저에 임시로 저장되는 정보를 의미한다. key:value 형식으로 저장이 되며, 이러한 쿠키를 저장해 두기 때문에, 한번 로그인을 하면, 페이지를 변경한다 해서 다시 로그인을 할 필요가 없어지는 것이다. 브라우저를 닫으면 자동으로 삭제되게 하거나, 일정 시간이 지나면 삭제되게 할 수 있다.

 

JWT를 본격적으로 알아보기 전에 세션에 대해 간단히 알아보고 넘어가자.

 

1. 세션(Session)

 

인가에는 크게 두가지 방법이 있다. 첫번째는 세션(Session)방식이고 두번째는 토큰방식(Token, JWT)이다.

 

우선 세션의 정의를 알아보면 다음과 같다.

세션(session)이란 웹 사이트의 여러 페이지에 걸쳐 사용되는 사용자 정보를 저장하는 방법을 의미합니다. 사용자가 브라우저를 닫아 서버와의 연결을 끝내는 시점까지를 세션이라고 합니다.

 

세션 방식은 전통적으로 많이 사용되어온 방식으로, 사용자가 로그인에 성공하면(인증을 받으면), 서버 측에 데이터를 저장하고, 세션의 키값만을 클라이언트 측에 넘겨준다.

 

브라우저는 Session ID라는 이름의 쿠키로 저장하고 앞으로 해당 사이트에 요청을 보낼 때 마다, 키값을 서버에 보낸다. 서버는 클라이언트(브라우저)에서 보낸 세션의 키값을 서버의 그것과 대조하여 짝이 맞으면 인가(Authorization)를 해준다. 이치럼, Session ID(키값)를 사용해서 어떤 사용자가 서버에 로그인 된 되어있음이 지속되는 이 상태를 '세션'이라고한다.

 

이 세션은 몇가지 문제점이 존재하는데, 우선 서버의 메모리에 문제가 생길경우 모든 유저의 로그인이 튕길 수 있고, 서버의 메모리의 사양에 따라 속도가 느려질 수 있으며, 여러개의 서버를 운영 할 경우 분산 문제가 생겨 세션 유지가 어려워질수도 있다.

 

이러한 문제점을 해결하기 위해 등장한 개념이 토큰 방식의 "JWT"이다.

2. JWT

 

JSON 웹 토큰(JSON Web Token, JWT)은 선택적 서명 및 선택적 암호화를 사용하여 데이터를 만들기 위한 인터넷 표준으로, 페이로드는 몇몇 클레임(claim) 표명(assert)을 처리하는 JSON을 보관하고 있다.

 

위키백과의 설명이다. 뭔말인지 모르겠다.

 

쉽게 말해, JWT를 사용하는 서비스에서는 사용자가 로그인을 하면 토큰이라고 하는 입장권을 건네주게 된다. 세션방식과 같이 서버에 남기는 것 없이, 사용자에게 토큰 하나 주고 끝! (물론 다양한 방식이 있다.) 아주 간단하지 않은가?

 

이때 사용자가 받는 토큰은 다음과 같이 생겼다.

 

jwt.io

 

딱 봐도 어지러운게 뭔갈 인코딩한게 분명하다. 중간에 .이 있는 걸보니 3가지의 데이터를 이어붙인 것 같기도 하다. 이를 분석하면 다음과 같다.

 

 

예상한 바와 같이 세 부분으로 나뉘는데 각각 header, payload, verify signature로 구분된다.

 

첫번째 부분인 헤더의 경우, type(무조건 JWT)과 algorithmn정보를 담고있다. HS256 등 여러 암호화 방식 중 하나를 지정하여 생성한다.

 

두번째 부분인 페이로드는, 해당 토큰을 누가 발급했고, 언제까지 유효하며, 발급 받은 사용자의 권한은 어디까지인가 등에 대한 JSON형식의 여러 정보들을 담고있다. 이렇게 토큰에 담긴 사용자 정보 등의 데이터를 Claim이라고 부른다.

 

마지막으로, 1번 헤더와 2번 페이로드, 그리고 '서버에 감춰놓은 비밀 값' 이 셋을 암호화 알고리즘에 넣고 뚱땅뚱땅하면 3번 서명 값이 나오게 된다. 그러니까 함부로 해석 할 수 없다는 뜻 되시겠다.

 

따라서 서버는 1번과 2번값 그리고 서버의 비밀 키값을 조합하여 인코딩 한 결과를 3번 서명값과 대조해보면 해당 사용자가 인가를 받았는지 아닌지 알 수 있다.

 

아쉽게도 이러한 토큰 방식은 "사용자의 상태를 기억하지 않아" 발생하는 치명적 단점이 있다. 다시말해, 서버에서 사용자를 제어할 수 없다. 해커가 해당 토큰을 탈취하면 언제든지 서버에 접속 할 수 있게 된다.

 

추가적으로, 사용자를 제어할 수 없으니, 여러개의 브라우저에서 같은 토큰으로 서버에 접속을 시도 할 수 있게 된다.

 

이러한 단점을 보안하기 위해 수명이 짧은 access 토큰과 수명이 긴 refresh 토큰, 두개를 발급하는 방법 등이 고안되었지만 완벽한 해결책은 아니라고 한다.

 

해당 포스팅 또한 얄코님의 유튜브를 참고하여 정리하였다.