[JWT] 토큰(Token) 기반 인증에 대한 소개


소개

토큰(Token) 기반 인증은 모던 웹서비스에서 정말 많이 사용되고 있습니다. 여러분이 API 를 사용하는 웹서비스를 개발한다면, 토큰을 사용하여 유저들의 인증작업을 처리하는것이 가장 좋은 방법입니다.

토큰 기반 인증 시스템을 선택하는데에는 여러가지 이유가 있는데요, 그 중 주요 이유들은 다음과 같습니다

Stateless 서버

Stateless 서버를 이해하려면 먼저 Stateful 서버가 무엇인지 알아야합니다. Stateful 서버는 클라이언트에게서 요청을 받을 때 마다, 클라이언트의 상태를 계속해서 유지하고, 이 정보를 서비스 제공에 이용합니다. stateful 서버의 예제로는 세션을 유지하는 웹서버가 있습니다. 예를들어 유저가 로그인을 하면, 세션에 로그인이 되었다고 저장을 해 두고, 서비스를 제공 할 때에 그 데이터를 사용하지요. 여기서 이 세션은, 서버컴퓨터의 메모리에 담을 때도 있고, 데이터베이스 시스템에 담을 때도 있습니다. Stateless 서버는 반대로, 상태를 유지 하지 않습니다. 상태정보를 저장하지 않으면, 서버는 클라이언트측에서 들어오는 요청만으로만 작업을 처리합니다. 이렇게 상태가 없는 경우 클라이언트와 서버의 연결고리가 없기 때문에 서버의 확장성 (Scalability) 이 높아집니다.

모바일 어플리케이션에 적합하다

만약에 Android / iOS 모바일 어플리케이션을 개발 한다면, 안전한 API 를 만들기 위해선 쿠키같은 인증시스템은 이상적이지 않습니다. (쿠키 컨테이너를 사용해야하죠). 토큰 기반 인증을 도입한다면, 더욱 간단하게 이 번거로움을 해결 할 수 있습니다.

인증정보를 다른 어플리케이션으로 전달

대표적인 예제로는, OAuth 가 있습니다. 페이스북/구글 같은 소셜 계정들을 이용하여 다른 웹서비스에서도 로그인 할 수 있게 할 수 있습니다.

보안

토큰 기반 인증 시스템을 사용하여 어플리케이션의 보안을 높일 수 있습니다. 단, 이 토큰 기반 인증을 사용한다고 해서 무조건 해킹의 위험에서 벗어나는건 아닙니다.

 

토큰 기반 인증 시스템을 사용하는 서비스들

토큰 기반 인증 시스템은 여러분이 알고있는 많은 서비스들에서 사용되고있습니다.

apple-touch-icon-192x192 fb-artgithub-mark googleplus-logos-02

 

왜 토큰을 사용하게 돼었을까?

토큰 기반 인증 시스템이 어떻게 작동하고, 또 이로 인하여 얻을 수 있는 이득에 대하여 알아보기전에, 이 토큰 기반 인증 시스템이 어쩌다가 나타났는지 알아봅시다. 이를 위해선, 과거의 인증시스템이 어떤 방식으로 작동했는지 살펴볼 필요가 있습니다.

서버 기반 인증

기존의 인증 시스템에서는 서버측에서 유저들의 정보를 기억하고 있어야합니다. 이 세션을 유지하기 위해서는 여러가지 방법이 사용됩니다. 메모리 / 디스크 / 데이터베이스 시스템에 이를 담곤 하죠.

서버 기반 인증 시스템의 흐름을 보자면 다음과 같습니다.

bb

 

이런 방식의 인증 시스템은 아직도 많이 사용 되고 있습니다. 하지만, 요즘 웹 / 모바일 웹 어플리케이션들이 부흥하게 되면서, 이런 방식의 인증 시스템은 문제를 보이기 시작했습니다. 예를 들자면, 서버를 확장하기가 어려웠죠.

서버 기반 인증의 문제점

세션

유저가 인증을 할 때, 서버는 이 기록을 서버에 저장을 해야합니다. 이를 세션 이라고 부릅니다. 대부분의 경우엔 메모리에 이를 저장하는데, 로그인 중인 유저의 수가 늘어난다면 어떻게될까요? 서버의 램이 과부화가 되겠지요? 이를 피하기 위해서, 세션을 데이터베이스에 시스템에 저장하는 방식도 있지만, 이 또한 유저의 수가 많으면 데이터베이스의 성능에 무리를 줄 수 있습니다.

확장성

세션을 사용하면 서버를 확장하는것이 어려워집니다. 여기서 서버의 확장이란, 단순히 서버의 사양을 업그레이드 하는것이 아니라, 더 많은 트래픽을 감당하기 위하여 여러개의 프로세스를 돌리거나, 여러대의 서버 컴퓨터를 추가 하는것을 의미합니다. 세션을 사용하면서 분산된 시스템을 설계하는건 불가능한것은 아니지만 과정이 매우 복잡해집니다.

CORS (Cross-Origin Resource Sharing)

웹 어플리케이션에서 세션을 관리 할 때 자주 사용되는 쿠키는 단일 도메인 및 서브 도메인에서만 작동하도록 설계되어있습니다. 따라서 쿠키를 여러 도메인에서 관리하는것은 좀 번거롭습니다.

토큰 기반 시스템의 작동 원리

토큰 기반 시스템은 stateless 합니다. 무상태. 즉 상태유지를 하지 않는다는 것이죠. 이 시스템에서는 더 이상 유저의 인증 정보를 서버나 세션에 담아두지 않습니다. 이 개념 하나만으로도 위에서 서술한 서버에서 유저의 인증 정보를 서버측에 담아둠으로서 발생하는 많은 문제점들이 해소됩니다.

세션이 존재하지 않으니, 유저들이 로그인 되어있는지 안되어있는지 신경도 쓰지 않으면서 서버를 손쉽게 확장 할 수 있겠죠?

토큰 기반 시스템의 구현 방식은 시스템마다 크고작은 차이가 있겠지만, 대략적으로 보면 다음과 같습니다:

  1. 유저가 아이디와 비밀번호로 로그인을 합니다
  2. 서버측에서 해당 계정정보를 검증합니다.
  3. 계정정보가 정확하다면, 서버측에서 유저에게 signed 토큰을 발급해줍니다.
    여기서 signed 의 의미는 해당 토큰이 서버에서 정상적으로 발급된 토큰임을 증명하는 signature 를 지니고 있다는 것입니다
  4. 클라이언트 측에서 전달받은 토큰을 저장해두고, 서버에 요청을 할 때 마다, 해당 토큰을 함께 서버에 전달합니다.
  5. 서버는 토큰을 검증하고, 요청에 응답합니다.

token-diagram

웹서버에서 토큰을 서버에 전달 할 때에는, HTTP 요청의 헤더에 토큰값을 포함시켜서 전달합니다.

 

토큰의 장점

무상태(stateless) 이며 확장성(scalability)이 있다

이 개념에 대해선 지금 반복적으로 이야기하고 있죠? 이는 그만큼 토큰 기반 인증 시스템의 중요한 속성입니다. 토큰은 클라이언트사이드에 저장하기때문에 완전히 stateless 하며, 서버를 확장하기에 매우 적합한 환경을 제공합니다. 만약에 세션을 서버측에 저장하고 있고, 서버를 여러대를 사용하여 요청을 분산하였다면, 어떤 유저가 로그인 했을땐, 그 유저는 처음 로그인했었던 그 서버에만 요청을 보내도록 설정을 해야합니다. 하지만, 토큰을 사용한다면, 어떤 서버로 요청이 들어가던, 이제 상관이 없죠.

보안성

클라이언트가 서버에 요청을 보낼 때, 더 이상 쿠키를 전달하지 않음으로 쿠키를 사용함으로 인해 발생하는 취약점이 사라집니다. 하지만, 토큰을 사용하는 환경에서도 취약점이 존재 할 수 있으니 언제나 취약점에 대비해야 합니다(참조).

Extensibility (확장성)

여기서의 확장성은, Scalability 와는 또 다른 개념입니다. Scalability 는 서버를 확장하는걸 의미하는 반면, Extensibility 는 로그인 정보가 사용되는 분야를 확장하는것을 의미합니다. 토큰을 사용하여 다른 서비스에서도 권한을 공유 할 수 있습니다. 예를 들어서, 스타트업 구인구직 웹서비스인 로켓펀치에서는 Facebook, LinkedIn, GitHub, Google 계정으로 로그인을 할 수 있습니다. 토큰 기반 시스템에서는, 토큰에 선택적인 권한만 부여하여 발급을 할 수 있습니다 (예를들어서 로켓펀치에서 페이스북 계정으로 로그인을 했다면, 프로필 정보를 가져오는 권한은 있어도, 포스트를 작성 할 수 있는 권한은 없죠)

여러 플랫폼 및 도메인

서버 기반 인증 시스템의 문제점을 다룰 때 CORS 에 대하여 언급 했었죠? 어플리케이션과 서비스의 규모가 커지면, 우리는 여러 디바이스를 호환 시키고, 더 많은 종류의 서비스를 제공하게 됩니다. 토큰을 사용한다면, 그 어떤 디바이스에서도, 그 어떤 도메인에서도, 토큰만 유효하다면 요청이 정상적으로 처리 됩니다. 서버측에서 어플리케이션의 응답부분에 다음 헤더만 포함시켜주면 되지요.

Access-Control-Allow-Origin: *

이런 구조라면, assets 파일들(이미지, css, js, html 파일 등)은 모두 CDN 에서 제공을 하도록 하고, 서버측에서는 오직 API만 다루도록 하도록 설계 할 수도 있지요.

웹 표준 기반

토큰 기반 인증 시스템의 구현체인 JWT는 웹 표준 RFC 7519 에 등록이 되어있습니다. 따라서 여러 환경에서 지원이 되며 (.NET, Ruby, Java, Node.js, Python, PHP …) 수많은 회사의 인프라스트럭쳐에서 사용 되고 있습니다 (구글, 마이크로소프트 …)

 

마치면서..

이번 포스트에서는 토큰 기반 인증 시스템에 대한 소개, 그리고 기존의 시스템과 어떠한 차이가 있는지에 대하여 알아보았습니다. 다음 포스트에서는, 이번에 배운 시스템의 구현체인 JWT (JSON Web Token) 에 대해서 알아보고, 그 시스템에서 사용하는 토큰의 구조를 살펴보도록 하겠습니다.

Reference

Stateless vs Stateful Servers

http://orca.st.usm.edu/~seyfarth/network_pgm/net-6-3-3.html

Cookies vs Tokens. Getting auth right with Angular.JS

https://auth0.com/blog/angularjs-authentication-with-cookies-vs-token/

확장성 있는 웹 아키텍처와 분산 시스템

http://d2.naver.com/helloworld/206816

What is token based authentication?

http://stackoverflow.com/questions/1592534/what-is-token-based-authentication

REST API의 이해와 설계 #1-개념 소개

http://bcho.tistory.com/953

The Ins and Outs of Token Based Authentication

https://scotch.io/tutorials/the-ins-and-outs-of-token-based-authentication#introduction

Token-based authentication: security considerations

http://www.kieranpotts.com/blog/token-authentication-security

  • byzz

    좋은 글 감사합니다 잘 읽었습니다 !!

  • Park Eden

    잘읽고 갑니다^^

  • 이재욱이

    감사합니다!! 정독했어요!

  • Doo hwan Kim

    감사합니다 잘 읽었습니다. 그리고 웹표준 기반 항목에 “사용 도고 있습니다” 라는 오타 발견했습니다.

  • JWT 구현하고 있었는데 좋은 글 덕분에 이해하는데 도움되었습니다. 감사합니다.

  • Kihyun Hwang

    잘 읽었습니다~ 그리고 질문이 있는데요~ 토큰 인증방식을 사용한다고해도 특정 사용자에게 발행한 토큰정보를 가지고있어야 나중에 사용자가 토큰으로 어떤 서비스를 요청했을 때 검증을 하고 서비스를 제공하는것 아닌가요? 결국 서버쪽에서 관리해야하는 정보만 바뀌는 것 아닌가요?? 제가 이제 막 사용자 인증 관련 공부를 시작해서 많이 부족합니다. 가르쳐주세요 ^-^

    • 차이점은 세션을 사용할경우 필요한 정보를 메모리 혹은 데이터베이스에 담아두고 요청이 올때마다 확인을 하는거구요,

      토큰인증의 경우 클라이언트쪽에서 자기정보를 알려주고 서버측에서 메모리나 데이터베이스 조회없이 암호학의 기술로 토큰이 정식발급된건지 체크만 하는거지요

    • Hyunseo Kang

      조금더 설명을 추가드리면요 jwt 토큰은 따로 데이터베이스나 세션정보 없이 토큰자체을 decode 하면 토큰에 들어있는 정보를 알수 있어서 토큰에 대한 정보를 따로 보관하지 않아도 됩니다. 물론 좀더 예민하고 공개하면 안되는 정보는 토큰에 담으면 안되겠죠. 그리고 나서 토큰을 verify 할 경우에 해당 토큰이 사용가능한지에 대한 여부를 알려줍니다. 그래서 jwt 가 좋은점인거 같아요. 토큰의 내용은 누구든지 알수 있지만 해당 토큰의 validity 는 서버만 알수 있어서요.

  • Heedo Jun

    authentication에 대해 공부를 하면서 google을 검색해 보았는데, 이번에도 이 블로그가 뜨네요. 정말 이 블로그는 없는 정보가 없군요!

  • 전현준

    제가 알고싶은 어떤 것을 검색해도 거의 다 이 블로그로 오게 되네요.. 정말 감사합니다!

  • 준영 박

    좋은글 감사합니다

  • Daniel

    좋은글 감사합니다^^ 한가지 궁금한 사항이 생겨서용 모바일 App에서 로그인하면 가령 10분간 유효한 토큰을 발행한다고하면요~ 10분 동안은 토큰이 유효하니까 헤더에다가 토큰정보를 넣어서 서비스를 잘 사용하면 되는데용~ 10분이 지날 무렵은 모바일에서 토큰값을 갱신을 해야할 것 같은데요. 이런경우는 보통 모바일에서 정기적으로 토큰 갱신하는 서비스를 따로 돌려야할까요?? 세션같은경우는 서비스 호출할때마다 알아서 서버 내부에서 유효시간이 연장이 되니까 세션키 그대로 쓰면 되니는데… 토큰은 10분지나면 다시 갱신하면 토큰 값이 바뀌잖아요?????

  • JangHee Lee

    정말 좋은 자료감사합니다!! Oauth2.0 을 구현하다가 jwt를 적용할려고 공부하는 중이었는데 토큰기반인증시스템를 겨우 이해했습니다.

  • 서버에서 클라이언트로 생성된 토큰 값을 넘겨줄 때 어떤 방식으로 넘겨주는지 궁금합니다.
    인터넷에 있는 대부분의 예제들에서는 그냥 res.json({ “token”: “토큰값”});
    이런 식으로 넘겨주고 있거든요.

  • henryfrz

    jwt 에 대해 공부중이라 잘 몰라서 하는 질문입니다.

    1. 서버에서 발급한 키를 클라이언트가 다음 요청에 위해서 키를 보관후 보내야 하는데 이 경우 키는 쿠키 외에 어디에 저장해야 하는지요?

    2. 해당키가 전송되는걸 도청해서 동일키를 다른 곳이서 보낸다면 서버는 역시나 같은 클라이언트로 인식할것입니다.

    3. 그냥 클라이언트가 아이디 암호 보내고 서버가 해당 아이디의 db에 저장된 암호 비교와 다를게 없어 보입니다. 공격자가 아이디 에 다른 암호를 넣어 보낸들 의미가 없으니..

    2 3 내용으로 보면 아이디암호 읽기쉽게 보내나 읽기어렵게 뭉쳐서 보내나의 차이인데 어차피 카피해 보낼 수 있다면 이는 보안에 별 도움이 안 될듯 느껴집니다.

    4. 아이디, 암호, 임시 암호, 임시암호 유효기간을 db에 저장하고 클라이언트가 상황따라 일반 텍스트로 보내고 서버가 db 조회후 처리하는 것과 비교해 어떤 장점이 있는지 궁금합니다.

    어차피 db 조회는 사용자 로그인 이후 서비스를
    위해 해야 하니 로그인을 위한 db조회 1회를 아낄 수 있다는 것은 장점에 포함시키기가 어려울듯 보입니다.

    프로젝트 중에 급히 고민하는 중이고 강좌의 jwt 내용에 대한 이해도 부족해서 제가 잘못 이해하고 있는 부분이 많습니다. 미리 사과 말씀 드리며 고견을 기다리겠습니다.

    • Jong-hyeon Lee

      1번은 저도 잘 모르겠지만, 나머지에 대해 짧은 생각을 달아봅니다.

      2번은 동의합니다. 그렇기때문에 페이스북을 이용 중 Auth(토큰) 정보를 잘 못 넘겨주게되면, 로그인 당사자가 아닌 제 3자가 당사자인척 위장해서 그 지인에게 홍보성 메시지를 날리는 등의 해킹 공격이 가능하게 됩니다.
      => 해당 상황을 당사자가 인식했을 때, 비밀번호만 변경해도 나머지 토큰들은 다 폐기됩니다. 변경 이후에는 이전 토큰 정보의 유효성이 폐기되었기 때문이죠.

      3번은 조금 다른 것 같습니다. 클라이언트가 요청마다 아이디/암호를 보내는 것과 가진 쿠키 정보를 보내는 것은 보안성 의미에서 큰 차이가 있지 않을까요?? 다른 암호를 넣어 보내는건 당연히 의미가 없을 것 같은데 어떤 상황을 비유하신 건지 잘 모르겠습니다.

      4번도 조금 .. 비교하는 상황이 무엇과 무엇의 비교인지 와닿지 않습니다. 본 포스팅에서는 세션 유지 vs 토큰인증에 대한 서버 자원 관리와 확장성을 이야기하는 것 같은데요, DB에서 조회하지 않는다는 의미는 아니구요. 그 다음 의견인 ‘로그인을 위한 db조회 1회를 아낀다’는 접근에 대해서는 의구심이 드네요.

      페이스북 앱과 서버 입장에서만 봐도 한 유저가 평균 하루에 5번만 들어간다고 쳐도 천명 기준 5,000회의 인증 과정을 소화해야되는데, 로그인 검증을 천명이 한번만 거쳐도 된다면 DB 조회 4,000회의 서버 자원을 절약할 수 있지 않을까요?? 세션 유지 비용을 제외하고서도요.

    • 김찬수 (왓슨)

      1번에 경우 저같은 경우에는 브라우저에 localStorage에 저장시키고 있습니다.

      • xpem

        로컬스토리지에 저장하는 것은 위험하다 들었습니다. 로컬스토리지의 값을 xss 로 읽어낼 수 있다는 것을 읽어본 것 같은데…

  • 스승님으로 모시겠습니다. 스승님.

  • jong

    정말 중요한 내용을 잘 가르쳐주시네요! 감사합니다.

  • Qus

    이해가 쏙쏙되네요. 감사합니다 🙂

  • Yangeok

    httpOnly를 true로 하고 쿠키를 서버에서 브라우저로 보내면 브라우저에서 쿠키에 접근을 못하는데 이건 어떻게 해결할 수가 있나요?

  • 잘 읽고 가요.

  • 이상호

    좋은 글은 쓰래드도 많군요. 처음 접하는데, 이해가 정말 잘 됩니다. 감사합니다.

  • 토큰의 보안성부분 링크가 깨진 것 같습니다. 좋은 글 감사합니다.

  • ohoroyoi

    좋은글 감사합니다!

  • 코딩윌

    좋은글 감사합니다!!

  • 김영수

    남들보다 5년이나 늦었지만 저로선 뜻밖에 수확입니다.
    많은 걸 배우고 갑니다.
    감사합니다.

  • 김정태

    많은 도움이 되었습니다. 감사합니다.