토큰기반 인증방식과 세션(서버)기반 인증방식

토큰기반 인증방식과 세션(서버)기반 인증방식에 대해서 알아보자 !

학습하기 이전에 인증과 인가에 대해 모른다면 학습하고오자 !

🔗인증과 인가

세션(서버)기반 인증방식

  • 토큰 기반 인증이 없었을 때의 인증 시스템은 서버 측에서 유저들의 정보를 기억하고 있어야 했다.

세션(서버)기반 인증방식

서버기반 인증의 문제

메모리 과부하

  • 유저가 인증을 할 때, 서버는 이 기록을 서버에 저장을 해야 하는데 이를 Session이라고 한다. 대부분의 경우 메모리에 저장하는데, 유저의 수가 급격히 늘어난다면 서버의 메모리가 과부화된다.

  • 이를 피하기 위해 데이터베이스에 저장하는 방식도 있으나 유저의 수가 많으면 데이터베이스 성능에 무리를 줄 수 있다.

확장성의 문제

  • 세션을 사용하면 서버를 확장하기 어려워진다. 서버의 확장은 더 많은 트래픽을 감당하기 위하여 여러개의 프로세스를 돌리거나 여러대의 서버 컴퓨터를 추가하는 것을 의미한다.

  • 세션을 사용하면 분산된 서버의 세션을 동기화 하는 작업 등이 필요하게 된다.

CORS(Cross-Origin Resource Sharing)

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

토큰기반 인증방식

토큰기반 인증방식으로 Claim 기반 토큰과 랜덤 값 기반 토큰이 있다.

  • Claim 기반 토큰은 JWT 토큰과 같이 공개돼도 문제가 없는 유저의 정보(Claim)를 담은 토큰을 얘기한다.
  • 랜덤 값 기반 토큰은 OAuth에 의해서 발급되는 access_token과 같이 랜덤한 스트링이 들어있는 토큰을 얘기한다.

두 가지를 간단히 비교하자면, 랜덤 값 기반 토큰 같은 경우 토큰을 발급하는 서버에서 토큰이 유효한 것인지 확인하기위해 토큰을 저장해야한다. 또한 유저를 식별하는 토큰으로 사용할 경우 자원(리소스) 서버에 별도로 API 호출을 하여 발급한 토큰으로 유저의 자원을 얻어와야한다. 하지만 Claim 기반 토큰은 토큰 자체에 유저의 자원이 들어있으며 암호화된 내용인 토큰의 정보를 이용해 토큰이 유효한 토큰인지 확인할 수 있다.

아래에서는 Claim 기반 토큰에 대해서 설명하겠다. 아래의 내용을 보고 다시 이 내용을 읽는다면 더 이해가 잘될것이다.

토큰기반 인증방식 작동 원리

  • 토큰 기반 시스템은 stateless하다. 상태를 유지하지 않는다. 이 시스템에서는 더 이상 유저의 정보를 서버나 세션에 담아두지 않는다 !

  • 이 개념만으로 서버기반 인증방식의 많은 문제점이 해소된다.

    • 서버측 메모리 과부화 해소
    • 세션이 존재하지 않으니 유저들이 로그인 되어있는 지 신경 쓰지 않으면서 서버를 손쉽게 확장 가능

구현방식

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

    1. 유저가 아이디와 비밀번호로 로그인한다.

    2. 서버측에서 해당 계정정보를 검증

    3. 계정정보가 정확하다면, 서버측에서 유저에게 signed token을 발급한다.

      여기서 signed의 의미는 해당 토큰이 서버에서 정상적으로 발급된 토큰임을 증명하는 signature를 지니고 있다는 것이다.

    4. 클라이언트 측에서 전달받은 토큰을 저장해두고, 서버에 요청을 할 때마다, 해당 토큰을 함께 서버에 전달한다.

    5. 서버는 토큰을 검증하고 요청에 응답한다.

    토큰기반 인증방식

    • 클라이언트에서 토큰을 서버에 전달할 때에는 HTTP 요청 헤더에 토큰 값을 포함시켜서 전달하게된다.

토큰 방식의 특징

  • 무상태(Stateless), Scalability

    토큰은 클라이언트 사이드에서 저장하기 때문에 완전히 Stateless하다. 그렇기 때문에 서버를 확장하기에 매우 적합한 환경이 제공된다.

    만약 세션을 서버측에서 저장하고 있고 서버를 여러대 사용하여 요청을 분산하였다면 어떤 유저가 로그인시에 처음 로그인했던 그 서버에만 요청을 보내도록 설정해야한다. 하지만 토큰은 이 문제를 해결한다! 따라서 Scale을 키우는 것에 자유로워진다.

  • 보안성

    클라이언트가 사이트를 벗어나도 이미 쿠키가 사용자 정보를 가지고 있기 때문에 공격자에게 노출될 수 있다. 공격자가 임의로 다른 URL로 유도하여 비밀번호를 바꾸거나 회원 탈퇴를 할 경우 쿠키가 있기 때문에 서버는 요청을 신뢰하고 작업을 수행하게 된다.(XSS 문제) 또는 공격자가 쿠키를 탈취하여 사용자로 위장하여 요청을 보낼 수 있다. 이러한 문제를 해결하기 위해 탈퇴시 비밀번호를 한 번 더 요구하거나 토큰과 같은 credential를 포함시켜야한다. 토큰기반 인증에서는 헤더 내에 토큰이 포함되도록하여 XSS, CSRF를 방지할 수 있다.(dom api를 통해 쿠키에 저장된 토큰을 헤더에 포함시켜야하는데 이를 위해선 HttpOnly option을 해제해야한다. 이로인해 쿠키에 저장된 토큰이 탈취될 수 있고 토큰 기반 방식 또한 문제가 있다… 즉, 토큰 기반의 방식을 사용하게되면 토큰의 새로운 문제에 대응해야한다.)

    (jwt 저장하는 방법 관련 글을 한번 읽어보는 것을 추천합니다.)

    쿠키는 단일 도메인 및 서브 도메인에서만 작동하도록 설계되어 있기 때문에 여러 도메인에서만 작동하도록 하기가 어렵다. 하지만 토큰기반 인증에서는 토큰만 유효하다면 어디서든 작동할 수 있다. (CORS 문제 해결)

  • Extensibility

    Extensibility는 로그인 정보가 사용되는 분야를 확장하는 것을 의미한다. 토큰을 사용하여 다른 서비스에서도 권한을 공유할 수 있다.

    즉, OAuth2 로그인 같은 기능을 사용할 수 있게 되는 것이다.

  • 여러 플랫폼 및 도메인

    애플리케이션과 서비스의 규모가 커지면 우리는 여러 디바이스를 호환시키고 더 많은 종류의 서비스를 제공하게 되는데 토큰을 사용한다면, 그 어떤 디바이스, 도메인에서도 토큰만 유효하다면 요청이 정상적으로 처리되도록 할 수 있다.

토큰 방식의 문제

  • Stateless한 토큰의 특성 때문에 강제로 만료시킬 수 없는 문제가 있다.

    토큰이 공격자(해커)에게 탈취되었다고 가정하면, 공격자는 토큰이 만료될 때까지 서버에 요청을 할 수 있다.

    위와 같은 상황을 해결하기 위해 토큰의 주기를 너무 짧게하면 수시로 로그인을 다시 하게 되어 사용자가 불편해지고, 사용자 편의를 위해 만료 주기를 길게하면 토큰이 탈취당했을 때 피해가 커지게 된다.

    이 단점을 보완하기 위해 보통은 토큰의 타입을 리프레시 토큰과 액세스 토큰으로 나누어 사용하는 방식을 사용한다.

    이 방식은 서비스를 요청하는데 사용하는 만료주기가 짧은 액세스 토큰과 액세스 토큰을 재발급 받을 수 있는 보안이 철저하고 만료 주기가 긴 리프레시 토큰을 사용한다. 액세스 토큰은 탈취당하더라도 보안이 철저한 리프레시 토큰을 탈취하지 못하면 공격할 수 있는 시간은 얼마 되지 않기 때문이다.

  • 토큰 저장 위치 문제

    서버가 토큰을 발급해주면, 브라우저에서 사용자/서버 간에 토큰이 전달되는 방식은 크게 두 가지이다.

    1. 로그인 성공시 서버가 응답 정보에 토큰을 넣어서 전달하도록 하고 해당 값을 웹스토리지(LocalStorage or SessionStorage)에 넣은 다음 웹 요청을 할 때마다 HTTP 헤더 값에 넣어서 요청하는 방법

      이 방법은 구현하기 쉽고 하나의 도메인에 제한되어 있지 않다는 장점이 있지만, XSS 해킹 공격을 통하여 해커의 악성 스크립트에 노출이 되는 경우 매우 쉽게 토큰이 탈취될 수 있다. LocaStorage에 접근하면 바로 토큰에 접근할 수 있기 때문이다.

      XSS(Cross Site Scripting) 란,

      게시판이나 웹 메일 등에 자바 스크립트와 같은 스크립트 코드를 삽입 해 개발자가 고려하지 않은 기능이 작동하게 하는 치명적일 수 있는 공격 방법

    2. 토큰을 쿠키에 넣는 방법

      쿠키를 사용한다고해서 세션을 관리하는 것은 아니고 그저 쿠키를 정보 전송수단으로 사용하는 방법이다. 이 과정에서 서버측에서 응답을 하면서 쿠키를 설정해줄 때, httpOnly 값을 활성화 해주면 네트워크 통신 상에서 해당 쿠키가 붙게 된다. 따라서 브라우저상에서는 자바스크립트로 토큰 값에 접근하는 것이 불가능해진다.

      이 방법의 단점은 한정된 도메인에서만 사용이 된다는 점인데, 토큰이 필요해질 때 현재 쿠키에 있는 토큰을 사용하여 새 토큰을 문자열로 받아올 수 있게하는 API를 구현하여 해결 할 수 있다.

      또 다른 단점은 XSS의 위험에서 완벽히 해방되는 대신 CSRF 공격의 위험성이 생긴다는 점이다. 스크립트를 통해 사이트의 외부에서 사이트의 API를 사용하는 것처럼 모방하는 공격에 취약점이 생길 수 있다. 또는 사이트 내부에서 스크립트가 실행되어 원하지 않는 작업이 수행되게 할 수도 있다.

      예를 들어 유저도 모르는 사이 탈퇴나 덧글을 자동으로 작성, 포스트를 자동으로 작성과 같은 동작의 스크립트가 실행될 수 있다.

      이러한 CSRF는 HTTP 요청 Referer 체크, CSRF 토큰의 사용을 통하여 방지할 수 있다.

      CSRF(Cross-Site Request Forgery) 란,

      웹 애플리케이션 취약점 중 하나로 사용자가 자신의 의지와 무관하게 공격자가 의도한 행동을 해서 특정 웹페이지를 보안에 취약하게 한다거나 수정, 삭제 등의 작업을 하게 만드는 공격 방법

JWT(Json Web Token)

JWT는 인증 헤더 내에서 사용되는 토큰 포맷이다. 토큰은 Base64로 인코딩한 String으로 이루어져있다.

이 토큰은 두 개의 시스템끼리 안전한 방법으로 통신할 수 있도록 설계하는 것을 도와준다.

JWT의 장점은 계정 서버와 API서버가 분리되어 있을 때, API 서버가 계정 서버에게 토큰의 유효성 여부를 물어보지 않고도 스스로 판단할 수 있다는 것이다.

JWT과 API 서버에서 유저 정보와 서버의 키로 만든 JWT 토큰을 비교하여 유효성 여부 판단이 가능하다.

  • Access token은 단순하게 자원에 접근하는 access token만이 아니라, 권한/인증에 대한 token을 말한다.

  • Refresh token은 Access token과 똑같은 형태의 JWT이고 Access token의 탈취 문제를 해결하기 위해 발급하는 토큰이다.

    처음 로그인을 완료했을 때 Access token과 동시에 발급되는 Refresh token은 긴 유효기간을 가지면서, Access token이 만료됐을 때 새로 발급해주는 열쇠가 된다.

JWT Flow

JWT는 토큰 자체가 의미를 갖는 Claim(권한) 기반의 토큰으로 권한과 인증의 역할을 가질 수 있다.

Claim(권한)은 사용자에 대한 프로퍼티나 속성을 의미한다.

JWT는 JSON 객체에 요구사항을 작성하고, 어떠한 암호화 방식을 사용해서 문자열로 인코딩을 한 후, HTTP header에 추가함으로써 사용자 인증을 요청한다. 서버에서는 이 토큰을 확인한 후 디코딩하여 사용자를 인증하게 된다.

기본 구성은 다음과 같다.

xxxxx.yyyyy.zzzzz
  • Header(xxxxx) JWT인 토큰의 유형이나 HMAC, SHA256 또는 RSA와 같이 사용되는 해시 알고리즘이 무엇으로 사용했는지 등 정보가 담긴다. Base64Url로 인코딩되어있다.

  • Payload(yyyyy) 클라이언트에 대한 정보나, meta Data 같은 내용이 들어있고, Base64Url로 인코딩되어있다.

  • Signature(zzzzz) header에서 지정한 알고리즘과 Secret 키, 서명으로 Payload와 header를 담는다.

JWT는 내용을 해독해 볼 수 있으므로 중요한 데이터를 포함해선 안된다.

Refernece

https://st-lab.tistory.com/100

https://velog.io/@djaxornwkd12/%EC%84%B8%EC%85%98-%EA%B8%B0%EB%B0%98-%EC%9D%B8%EC%A6%9D-%EB%B0%A9%EC%8B%9D-vs-%ED%86%A0%ED%81%B0-%EA%B8%B0%EB%B0%98-%EC%9D%B8%EC%A6%9D

https://www.a-ha.io/questions/41b92d13b08fe991acc5fa3a5a2889ff

https://dooopark.tistory.com/6

https://yonghyunlee.gitlab.io/node/jwt/

claim 기반 토큰 vs random 기반 토큰

⤧  Next post HTTP 버전과 SPEC ⤧  Previous post 인증과 인가가 뭐지 ??