토큰 기반 인증

Bonggus·2021년 10월 19일
0

Auth

목록 보기
1/2
post-thumbnail

(velopert님 블로그 글을 타이핑하며 읽은 것입니다)

토큰 소개

토크 기반 인증은 모던 웹 서비스에서 많이 사용되는 중이다. API를 사용하는 웹서비스를 개발한다면, 토큰을 사용하여 유저들의 인증작업을 처리하는 것이 좋은 방법이다.

Stateless Server?

Stateless Server를 이해하려면 Stateful Server에 대한 이해가 우선되어야 한다. Stateful Server는 클라이언트에게 요청을 받을 때마다 클라이언트의 상태를 계속해서 유지하고 이 정보를 서비스 제공에 이용한다. 예를들어, 유저가 로그인할 경우 세션에 로그인이 되었다고 저장해두고 서비스를 제공 할 때에 그 데이터를 사용한다. 이 세션은 서버컴퓨터의 메모리에 담을 수도 있고, DB시스템에 담을때도 있다.

Stateless Server는 반대로 상태를 유지하지 않는다. 상태정보를 저장하지 않으면 서버는 클라이언트측에서 들어오는 요청만으로 작업을 처리한다. 이렇게 상태가 없는 경우 클라이언트와 서버의 연결고리가 없기 떄문에 서버의 확장성이 높아진다.

Stateless Server 방식은 모바일 어플리케이션이 적합하다. 인증정보를 페이스북/구글같은 소셜 계정들에 전달하여 로그인을 구현할 수 있다. 토큰 기반 인증 시스템을 사용하여 어플의 보안을 높일 수 있다.

토큰을 사용하게 된 이유

서버 기반 인증

기존의 인증 시스템에서는 서버측에서 유저들의 정보를 기억학 있어야 한다. 이 세션을 유지하기 위해서 여러가지 방법이 사용된다. 메모리/디스크/DB시스템 등이다.

서버기반인증흐름

이러한 인증 방식은 아직도 많이 사용한다. 하지만 웹/모바일 웹 어플리케이션이 커지면서 서비기반 인증 시스템은 서버 확장에서 어려움을 겪고 있다.

세션

유저가 인증을 할 때, 서버는 이 기록을 서버에 저장해야 한다. 이를 세션이라고 부른다.(브라우저에 저장되는 것이 쿠키) 대부분의 경우엔 메모리에 세션을 저장한다. 하지만 로그인하는 사람의 수가 늘어나면, 서버의 램이 과부하된다. 이를 피하기 위해 세션을 데이터베이스 시스템에 저장하는 방식도 있다. 하지만 유저 수가 많을 경우 데이터베이스 성능에 문제가 생길 수 있다.

확장성

세션을 사용하면 서버 확장이 어렵다. 서버확장이란 더 많은 트레픽을 감당하기 위해 여러개의 프로세스를 돌리거나, 여러대의 컴퓨터를 추가하는 것을 의미한다. 세션을 사용하며 분산된 시스템을 설계하는 과정은 매우 복잡하다.

CORS (Cross-Origin-Resource Sahring)

세션 관리시 사용되는 쿠키는 단일 도메인 및 서브 도메인에서만 작동하도록 설계되어 있다. 따라서 쿠키를 여러 도메인에서 관리하는 것 역시 어려운 작업이다.

토큰기반 시스템 작동 원리

토큰 기반 시스템은 stateless이다. 즉, 상태유지를 하지 않는 다는 것이다. 더 이상 유저의 인증 정보를 서버나 세션에 담아두지 않는다. 이 개념 하나만으로 유저의 인증정보를 서버에 담아둠으로써 생기는 많은 문제점들이 해결된다. 세션이 존재하지 않으니 유저들이 로그인 되어있는지, 아닌지 신경쓰지 않고 서버를 확장할 수 있다.

토큰 기반 시스템의 구현 방식

  1. 유저가 아이디 비빌번호로 로그인 한다
  2. 서버측에서 해댕 계정정보를 검증한다.
  3. 계정정보가 정확하다면, 서버에서 유저에게 signed 토큰을 발급한다.
  4. 클라이언트 측에서 전달받은 토큰을 저장해두고, 서버에 요청할때마다 토큰을 함께 전달한다.(HTTP 요청의 헤더에 토큰값을 포함시켜 전달)
  5. 서버는 토큰을 검증하고, 요청에 응답한다.

토큰의 장점

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

토큰을 클라이언트 사이드에 저장했기 때문에 완전히 stateless하다(서버에 정보가 저장되지 않는다). 서버를 확장하기에 적합한 환경을 제공한다. 만약 세션을 서버측에 저장하고 있고, 서버를 여러대를 사용하여 요청을 분산했다면, 어떤 유저가 로그인 했을 땐, 그 유저는 처음 로그인 했었던 그 서버에만 요청을 보내도록 설정해야 한다(정보가 그 서버에 저장되어 있기 떄문?). 하지만 토큰을 사용할 경우 어떤 서버로 요청이 들어가던 상관이 없다.

보안성

클라이언트가 서버에 요청을 보낼 때 더이상 쿠키를 전달하지 않는다. 쿠키를 사용함으로 발생하는 취약점이 사라진다. 물론 토큰을 사용하는 환경에서도 취약점은 존재한다.

확장성 Extensibility

여기서 말하는 확장성은 로그인 정보가 사용되는 분야를 확장하는 것을 의미한다. 토큰을 사용하여 다른 서비스에서도 권한을 공유할 수 있다. 예를들어, Facebook, google 계정 등으로 로그인이 가능하게 할 수 있다. 토큰 기반 시스템에서는 토큰에 선택적인 권한만 부여하여 발급할 수 있다(예.프로필 읽기는 가능, 글쓰기는 불가능).

여러 플랫폼 및 도메인

어플리케이션과 서비스 규모가 커지면 여러 디바이스를 호환시키고 더 많은 종류의 서비스를 제공하게 된다. 토큰을 사용한다면, 그 어떤 디바이스에서도, 그 어떤 도메인에서도, 토크만 유효하다면 요청이 정상적으로 처리된다. 서버측 어플리케이션 응다부분에 다음 헤더만 포함시켜주면 된다.

Access-Control-Allow-Origin: *

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

웹표준 기반

토큰 기반 인증 시스템의 구현체인 JWT는 웹 표준에 등록되어 있다. 따라서 여러 환경에서 지원이 가능하다.


JWT(JsonWebToken)

JWT는 웹표준으로 두 개채에서 JSON 객체를 사용하여 가볍고 자가수용적(self-contained) 방식으로 정보를 안전성 있게 전달해 준다.

자가수용적이라는 것은 JWT스스로 필요한 모든 정보를 자체적으로 지니고 있다는 말이다. JWT 시스템에서 발급된 토큰은, 토큰에 대한 기본정보, 전달 할 정보 그리고 토큰이 검증되었다는 것을 증명해주는 signature를 포함하고 있다.

자가수용적이기 때문에 두 개체 사이에서(클라이언트, 서버) 쉽게 전달이 가능하다. 웹서버의 경우 HTTP헤더, URL 파라미터 등으로 전달이 가능하다.

웹표준이기에 많은 프로그래밍 언어에서 지원된다.

JWT 사용처

  1. 회원인증

JWT사용하는 가장 흔한 시나리오이다. 유저가 로그인하면 서버는 유저의 정보에 기반한 토큰을 발급하여 유저에게 전달한다. 그 후, 유저가 요청을 할 때마다 JWT를 포함하여 전달한다. 서버가 클라이언트에게 요청을 받을 때마다 해당 토큰이 유효하고, 인증되었는지 검증을 한다. 유저가 요청한 작업에 권한이 있는지 확인하여 작업을 처리한다.

서버측에서는 유저의 세션을 유지할 필요가 없다. 즉, 유저가 로그인 되었는지 아닌지 신경쓸 필요가 없다. 유저가 요청했을 때 토큰만 확인하면 된다. 세션 관리가 필요 없어서 서버 자원을 아낄 수 있다.

  1. 정보교류

JWT는 두 개체 사이에서 안정성있게 정보를 교환하기 좋은 방법이다. 그 이유는 정보가 sign이 되어있기 때문에 정보를 보낸이가 바뀌지 않았는지, 또 정보가 도중에 조작되지는 않았는지 검증이 가능하다.

JWT 구조

JWT는 3가지 문자열로 되어있다. JWT토큰을 만을때, JWT를 담당하는 라이브러리가 자동으로 인코딩 및 해싱작업을 해준다.

헤더:Header

2가지 정보를 가지고 있다.

  • typ: 토큰의 타입을 지정한다. 바로 JWT
  • alg: 해싱 알고리즘이다. 해성알고리즘은 보통 HMAC SHA256 or RSA가 사용된다. 이 알고리즘은 토큰을 검증할 때 사용되는 signature 부분에서 사용된다.

정보:Payload

토큰에 담을 정보가 들어간다. 여기에 담는 정보의 한 '조각'을 클레임(claim)이라고 부른다. 이는 name/value의 한 쌍으로 이루어져 있다. 토큰에는 여러개의 클레임 들을 넣을 수 있다.

클레임은 크게 3분류로 나뉘어져있다.

  • 등록된 클레임
  • 공개된 클레임
  • 비공개된 클레임

1. 등록된 클레임

등록된 클레임들은 서비스에서 필요한 정보들이 아닌, 토큰에 대한 정보를 담기위하여 이름이 이미 정해진 클레임들이다. 등록된 클레임의 사용은 모두 선택적이다.

  • iss: 토큰 발급자 (issuer)
  • sub: 토큰 제목 (subject)
  • aud: 토큰 대상자 (audience)
  • exp: 토큰의 만료시간 (expiraton), 시간은 NumericDate 형식으로 되어있어야 하며 (예: 1480849147370) 언제나 현재 시간보다 이후로 설정되어있어야합니다.
  • nbf: Not Before 를 의미하며, 토큰의 활성 날짜와 비슷한 개념입니다. 여기에도 NumericDate 형식으로 날짜를 지정하며, 이 날짜가 지나기 전까지는 토큰이 처리되지 않습니다.
  • iat: 토큰이 발급된 시간 (issued at), 이 값을 사용하여 토큰의 age 가 얼마나 되었는지 판단 할 수 있습니다.
  • jti: JWT의 고유 식별자로서, 주로 중복적인 처리를 방지하기 위하여 사용됩니다. 일회용 토큰에 사용하면 유용합니다.

2. 공개 클레임

공개 클레임들은 충돌이 방지된 이름을 가지고 있어야 한다. 충돌을 방지하기 위해서 클레임 이름을 URI 형식으로 짓는다.

3. 비공개 클레임

등록도, 공개도 아닌 클레임이다. 보통 클라이언트/서버 사이의 협의하에 사용되는 클레임이다. 이름이 중복되어 충돌이 될 수 있으니 사용할때에 유의해야 한다.

{
    "iss": "velopert.com",
    "exp": "1485270000000",
    "https://velopert.com/jwt_claims/is_admin": true,
    "userId": "11028373727102",
    "username": "velopert"
}

서명: Signature

서명은 헤더의 인코딩값과, 정보의 인코딩값을 합친 후 주어진 비밀키로 해싱하여 생성한다.

// 수도코드
HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

합치고 나온 결과값을 기존 결과값들(헤더, 정보)뒤에 합쳐주면 완성이다

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJ2ZWxvcGVydC5jb20iLCJleHAiOiIxNDg1MjcwMDAwMDAwIiwiaHR0cHM6Ly92ZWxvcGVydC5jb20vand0X2NsYWltcy9pc19hZG1pbiI6dHJ1ZSwidXNlcklkIjoiMTEwMjgzNzM3MjcxMDIiLCJ1c2VybmFtZSI6InZlbG9wZXJ0In0.WE5fMufM0NDSVGJ8cAolXGkyB5RmYwCto1pQwDIqo2w

Ending

실제 서비스에서는 라이브러를 사용한다. JS의 경우 jsonwebtoken이라는 패키지를 사용하면 된다.

출처

profile
프론트엔드

0개의 댓글