💎목차

✔️인증의 정의

✔️세션과 토큰의 차이점

✔️API를 인증하는 여러 방법들


인증(Authentication)

인증 - 사용자의 개인정보를 사용하여 사용자가 누구인지를 판단

인가 - 사용자가 어떤 일을 할 수 있는지,어떤 권한을 갖고 있는지를 판단

사용자의 개인정보(아이디나 비밀번호)를 직접 인증에 사용하거나 인증을 위해 주고받는 방법은 정보 노출의 위험이 있어서 잘 사용하지 않는다. 대신 사용자의 개인정보를 인코딩 하거나, 해쉬 알고리즘을 통해 암호화한 뒤 이 정보를 주고받을 수는 있다. 


암호화에는 여러 가지 방법이 있다. Base64 인코딩을 거친 정보를 암호화하는 방법도 있고, 클라이언트와 서버만 아는 난수를 생성한 뒤 이를 해쉬 알고리즘에 넣어서 암호화하는 방법도 있다. 

 

그럼 암호화한 정보를 어떻게 사용할까? 클라이언트가 매번 서버에 리소스를 요청할 때마다 암호화를 통해 인증을 하는 것은 매우 번거롭고 시간도 오래 걸린다. 보통은 로그인 등으로 한 번 인증 절차를 거치면 일정 기간동안은 별도의 인증 절차 없이 리소스에 접근할 수 있도록 되어 있다. 

 

이처럼 사용자가 이미 인증 절차를 거쳤음을 증명하는 데 사용하는 것이 세션(session), 토큰(token) 등의 개념이다. 

 

세션과 토큰

토큰과 세션은 모두 사용자를 일정 기간동안 유효하게 인증하는 데 사용하는 방식인데, 인증하는 방식에 따라서 차이가 있다. 예전에는 세션을 많이 사용했다면 요즘은 세션의 단점을 보완한 토큰을 더 많이 사용하는 추세이고, 그 중에서도 json 형식으로 되어있는 JWT(json web token)를 많이 사용한다. JWT에 대해서는 뒤 부분에서 구체적으로 다뤄 보자. 

 

🌟JWT와 세션의 차이

JWT가 활성화되기 전에는 세션을 통한 인증이 활발했으나, 세션은 요청할 때 인증을 위해서 DB를 탐색해야 하는 단점이 있었다. 세션 관련 정보는 DB에 저장되었기 때문이다. 
물론 캐시(cache memory)를 이용해서 세션 정보를 브라우저에 임시로 저장할 수 있긴 하지만, 만료되거나 신규 요청이 들어오면 결국 DB를 탐색해야 했다. 
만약 세션 정보를 저장하는 DB가 분산되어 있다면 각각의 DB를 탐색해야 하는데, 이는 규모가 커질 경우 과정이 복잡해질 수도 있었다. (물론 요즘은 세션을 백엔드에서 편리하게 관리해 주는 프레임워크도 있다.)

JWT는 이런 세션의 단점을 보완한다. 

대략적인 인증 과정은 비슷하다.

클라이언트가 인증 요청을 하고, 서버가 인증을 처리하고 세션이나 JWT를 생성하면 이때 생성한 정보를 만료되기 전까지 일어나는 모든 인증에 사용하는 방식이다.

그러나 세션은 인증 정보를 DB에 저장하지만 JWT는 인증 정보를 클라이언트에 전달하고, 클라이언트가 브라우저에 JWT 토큰을 임시 메모리 형태로 저장한다. 

 

그렇다면 클라이언트가 API에 대해서 인증 요청을 할 때, 토큰을 어떻게 생성하고 인증할까? 

 

🌟API에서 토큰을 생성 및 인증하는 방법

순서

1. 사용자의 개인정보를 이용하여 사용자가 맞는지 판단하고(로그인), 사용자가 맞다면 토큰을 발급한다. 

2. 발급한 토큰은 API 접근 토큰 테이블에 등록된다. 

3. 사용자가 인증이 필요한 API를 요청할 경우, 서버는 사용자가 API 토큰이 있는지, 그리고 토큰이 유효한지(위조된 토큰인지, 유효 기간이 지났는지 등)를 확인해서 토큰이 유효하다면 사용자에게 API나 리소스를 제공한다. 

장점

API 토큰을 주고받는 중 해킹이 일어나도 사용자의 개인정보는 탈취되지 않는다. 토큰은 사용자의 정보와는 관계없는 임의의 문자열이기 때문이다. 

API 토큰 인증의 세부 방법(여러가지가 있음)

 

🌟Base 64 인코딩

클라이언트가 처음에 사용자가 맞는지를 개인정보로 인증할 때, 당연히 그 개인정보를 '직접' 보내지는 않는다. 
클라이언트는 자신의 개인정보를 Base64 인코딩을 거친 뒤, 토큰에 넣어서 서버에게 인증 요청을 보낸다. 그러면 서버가 그 정보를 바탕으로 사용자를 인증한다. 

다만 Base64는 별도의 키 값이 없기 때문에 인코딩한 문자열을 그대로 디코딩할 수 있다. 따라서 이 방법을 쓰려면 반드시 HTTPS 프로토콜을 이용해야 한다. 
안 그러면 해커가 중간에서 정보를 탈취할 수 있고, 탈취한 정보를 그대로 디코딩하면 사용자의 정보가 그대로 노출된다. 

🌟Digest Access Authentication

Base64의 단점을 보완한다. 
클라이언트가 서버에게 인증을 요청할 때, 서버는 클라이언트에게 임의의 난수 값을 준다. 
클라이언트는 이 난수 값을 해쉬 함수의 키 등으로 이용하여, 암호화한 결과를 토큰에 실어서 서버로 전송한다. 

이 경우 토큰 안에 일반 문자열(평문)으로 정보가 담겨 있지 않다. 또한 해커가 인증에 사용된 해쉬 알고리즘을 안다고 하더라도, 난수 키를 모르기 때문에 해시된 값에서 반대로 개인정보를 추출해 내기가 더 어렵다. 

 

📋인증 범위(Realm)

여러 API에 대해서 인증 범위(realm)을 다르게 설정할 수 있다. 
realm은 보호되는 영역인데, API 전체를 부분적으로 나눠서 다른 realm에 위치시킬 수 있다. 
realm을 사용하면 서버가 보호하고 있는 API를 여러 영역으로 나눌 수 있고, 각 영역(realm)마다 요구되는 정보(사용자 이름이나 비밀번호)를 다르게 지정할 수 있다. 

예를 들면 project APIA realm, homework APIB realm에 위치시킨다고 해 보자.
만약 클라이언트가 project API에 대해 인증을 요청한다면, 서버는 사용자가 A 영역(realm)에 접근을 시도했다고 보고 그에 맞는 개인정보를 받아 사용자가 맞는지 판단한다. 
반면 클라이언트가 homework API에 대해 인증을 요청한다면, 서버는 사용자가 B 영역(realm)에 접근을 시도했다고 보고 A영역과는 다른 개인정보를 받아 사용자가 맞는지 판단한다. 

만약 project API와 homework API가 모두 같은 A realm에 위치해 있었다면, 클라이언트가 project, homework API에 대해 각각 인증을 요청할 때 서버는 사용자가 모두 A 영역에 접근을 시도했다고 보고, 토큰을 발급하는 데 같은 정보를 사용했을 것이다. 

realm이 다르다는 것은 클라이언트가 각각 여러 API에 인증 요청을 보낼 때, 클라이언트는 각각 다른 정보를 사용하여 다른 유저로 인증될 수 있다는 의미이다. 

🌟화이트 리스트

API를 호출하는 클라이언트의 API가 일정할 때, 클라이언트가 고정 IP를 사용할 때 사용할 수 있다. 

서버는 특정 API URL에 대해서 들어오는 IP 주소를 화이트 리스트로 유지할 수 있다. 

 

화이트 리스트

기본 정책이 모두 차단인 상황에서 예외적으로 접근이 가능한 대상을 지정하는 방식이다. 
화이트 리스트에 등록된 IP가 아니면 모두 접근을 허용하지 않고, 화이트 리스트에 등록된 IP에 대해서만 인증 절차를 거쳐서 접근이 가능하도록 배치한다. 

 

🌟Oauth

제 3자 인증 방식 중 하나이다. 소셜로그인이 대표적인 예시이다. 
사용자 A가 웹 서비스 B의 리소스(API 등)에 접근하기 위해서, 다른 API 서비스 제공자 C(구글, 페이스북 등 소셜로그인이 가능한 서비스들)에게 인증 요청을 보낸다. 
A가 알맞은 정보로 인증하면, C는 A에게 유효기간이 있는 액세스 토큰을 지급한다. 
그러면 A는 C에게서 받은 토큰을 가지고 B의 리소스를 이용할 수 있다. 

🌟JWT(Json Web Token)

웹에서 토큰을 보낼 때 json 형식으로 주고 받는 토큰이다.

JWT는 claim 기반을 사용한다. claim(클레임)이란 유저의 속성을 의미하는데, 말 그대로 토큰 자체에 유저에 대한 정보가 포함되어 있다. 
이와 달리 Oauth는 토큰에 아무 의미가 없는 랜덤 문자열을 넣는다. 

따라서 JWT 토큰을 발급하면 토큰 내에는 사용자 정보가 포함되기 때문에(정확히는 Base64로 인코딩한 정보가 포함) 서버가 사용자의 정보를 다른 곳에서 추가로 찾거나 가져오지 않아도 된다는 장점이 있다.

반면 토큰 내에 모든 정보가 들어 있기 때문에, 토큰을 잘못 발행했어도 중간에 수정할 수 없다.

따라서 JWT 토큰에는 꼭 유효 기간을 지정해야 하고, 중간마다 리프레시 토큰으로 토큰을 재발행 해야 한다.

뿐만 아니라 토큰은 Base64 인코딩만 된 상태이기 때문에 중간에 누군가가 가로챌 경우 사용자의 정보가 노출될 수 있다.

이런 경우엔 토큰 자체를 암호화하는 JWE를 사용하기도 한다. JWT는 JWE 등으로 암호화를 하더라도, 복호화가 가능하다. 

 

☑️JWT 토큰의 구조

크게 세 가지 영역: 헤더(Header), 페이로드(Payload), 시그니처(Signature)로 나뉜다. 

 

토큰 예시: hhhhh.ppppp.sssss

 

1. Header(헤더)

토큰의 메타 정보가 담겨져 있다. 

어떤 방식으로 인코딩 되었는지, 토큰이 어떤 타입(JWT, Oauth 등)인지 등을 json 방식으로 작성한 뒤 해당 방식에 맞춰서 인코딩한다. 

2. Payload(페이로드)

사용자의 정보, 토큰의 만료 시간 등이 담겨져 있다. 

이때 사용자의 정보는 id 등 사용자를 특정할 수 있는 정보이다. (유저의 아주 중요한 정보(주민번호 등)가 담기진 않았지만, 하나의 유저를 특정할 수 있는 정보가 들어 있다.)

3. Signature(시그니처)

변조 문제를 해결하기 위한 영역이다. 

시그니처 영역을 만들기 위해서는 인코딩 된 헤더, 인코딩 된 페이로드, 그리고 secret_key(장고 프로젝트마다 사용되는 값) 값이 필요하다. 

시그니처는 이 세 값을 합친 뒤, 헤더에 지정한 알고리즘으로 해싱한다. 

그러므로 하나라도 값과 다르다면 결과값이 달라진다. 

☑️실제 인증하는 과정

기존에 만들어진 JWT 토큰은 브라우저에 캐시 형태로 저장되어 있다. 클라이언트가 서버에 특정 리소스에 대해서 인증을 요청한다고 하자. 

 

그러면 [클라이언트가 요청과 함께 보낸 토큰의 시그니처 값] == ([토큰 헤더 인코딩한 값] + [토큰 페이로드 인코딩한 값] + [장고 각 프젝마다 있는 secret_key 값])=>해시 알고리즘 적용

 

이 두 값이 같은지를 비교해서, 같다면 사용자 인증을 허가한다. 

 

 

참고한 포스트

https://dongwooklee96.github.io/post/2021/03/28/rest-api-%EB%B3%B4%EC%95%88-%EB%B0%8F-%EC%9D%B8%EC%A6%9D-%EB%B0%A9%EC%8B%9D/
https://hamait.tistory.com/416
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/WWW-Authenticate
https://www.qu3vipon.com/django-jwt

 

'server-side > server' 카테고리의 다른 글

Mac 환경설정  (0) 2024.07.15
Software Release Life Cycle  (0) 2023.07.15
OAuth 2.0 기본원리  (0) 2022.09.26
linux: cron 사용해서 자동으로 스케줄 실행하기  (0) 2022.07.09
Git: clone, single-branch, checkout  (0) 2022.06.28

+ Recent posts