Back-end/⌛ Intro

[서버/Server] 백엔드 틀 잡기 5/5 - 인증

posted by sangmin

로그인 인증 및 유지 방법

HTTP의 큰 특징으로는 statelessconnectionless가 있다. stateless는 무상태성, 즉 상태 관리를 하지 않는다는 뜻이다. 조금 더 쉽게 설명하자면 서버가 클라이언트의 상태를 몰라 식별할 수 없다는 말이다. 따라서 로그인 상태가 유지되지 않아 매 요청마다 다시 로그인해줘야하는 번거로움이 있다.
왜 stateless한 특징을 갖는지 의문이 생길 수 있다. 그 이유가 바로 connectionless이다. 클라이언트와 서버가 성공적으로 연결을 맺어 요청에 대한 응답을 마치면 연결을 끊어버린다. 이러한 비연결성의 장점은 연결을 유지하기 위한 리소스를 줄여 더 많은 연결을 가능하게 한다. 하지만 매번 새로운 연결 과정을 거치기 때문에 오버헤드가 발생한다는 단점이 있다.

위와 같은 HTTP 특징 속에서 어떻게 하면 로그인을 유지할 수 있는지 단계별로 알아보자. 참고로 인증 관련된 것은 모두 헤더에 실어서 보낸다.

0. 기본적인 방법

  • API 요청할 때마다 아이디와 패스워드를 함께 보낸다.

서버가 아이디와 패스워드를 계속 받기 때문에 로그인 상태를 유지할 수 있으나 보안상 치명적인 문제가 있다. 그리고 모든 요청마다 아이디와 패스워드를 계속 보내야하기 때문에 번거롭다. 사실 사용하면 안되는 방법이므로 목차를 0번부터 시작했다.

1. 쿠키 / 세션

  • 쿠키 및 세션에 저장한다.

쿠키가 어떠한 것들로 구성되는지, 세션이 어떤 방식으로 동작하는지에 대해 자세히 설명하지는 않겠다. 단순하게 쿠키는 클라이언트의 저장소, 세션은 서버단의 저장소 정도로 인지하고 있으면 된다. 처음 로그인할 때 아이디와 패스워드를 받은 서버는 sessionID를 생성한다. 그리고 이 세션 ID에 사용자를 식별할 수 있는 정보를 저장해두면 된다. 응답할 때 클라이언트에게 생성한 세션 ID를 주면 클라이언트는 이것을 쿠키에 저장해두면 된다.
그 다음 API를 요청할 때부터는 쿠키에 저장해둔 세션 ID를 헤더에 같이 실어 보내면 서버가 확인할 수 있다. 이것이 0번 방법의 문제점을 완전히 해결해주지는 않는다. 1차원적으로만 해결했을 뿐 여전히 보안 상의 문제가 있으며 세션 ID를 따로 관리해줘야하기 때문에 서버 입장에서는 부하가 생길 수 밖에 없다.

2. JWT

  • JSON Web Token 을 이용한다.

위의 방법들과 똑같이 아이디와 패스워드를 함께 실어 API를 요청한다. 서버에서는 JWT를 생성하는데, 중요한 점은 이것을 따로 저장해두지 않는다는 것이다. 그러면 사용자를 어떻게 구분하는지 알아보기 위해 JWT의 구조를 간단히 살펴보겠다.

jwt

JWT는 사진처럼 Header / Payload / Signature 세 부분으로 나뉜다. 여기에 들어가면 직접 토큰을 생성할 수 있다.

  • typ : 토큰 타입
  • alg : 해싱 알고리즘 (암호화/복호화 개념이 아닌 인코딩/디코딩이다.)
# example 
{ 
  "alg": "HS256", 
  "typ": "JWT" 
}

Payload

실제 데이터가 담기는 부분으로 중요 정보는 제외한다.

# example 
{ 
  "userId": 1, 
  "name": "sangmin", 
  "age": 25 
}

Signature

Header와 Payload를 합쳐 secret key와 함께 인코딩한다. 인코딩 시 헤더에서 선언한 해싱 알고리즘을 사용한다.

# example 
HMACSHA256( 
  base64UrlEncode(header) + "." + 
  base64UrlEncode(payload), 
  SECRET_KEY 
)

다시 본론으로 돌아와 사용자를 판단하는 방법에 대해 알아보겠다. 서버에서 정상적으로 JWT를 생성해 클라이언트에게 보냈다고 가정해보자. 그 다음 요청 시 클라이언트는 발급받은 JWT를 헤더에 실어 보낼 것이다. 이 때 서버는 내 서버에서 만든 JWT가 맞는지 검증을 한다. 서버에서 갖고 있는 secret key를 이용해 디코딩하여 확인할 것이다. 검증됐다면 Payload에 있는 정보를 패킷에 실어 보내면 된다.
이로써 1번 방법이 갖고 있는 서버 부하 문제는 해결했다. 하지만 토큰이 중간에 탈취될 가능성이 있다. 이것을 막기 위해 유효기간을 설정하여 일정 기간이 지나면 토큰을 갱신하면 된다. 즉, 토큰 값이 주기적으로 변하기 때문에 해커가 작업할 수 있는 시간을 뺏는 셈이다.

그 밖에

이와 같은 방법 말고 소셜 로그인하는 경우에 사용하는 OAuth 프로토콜 등도 있다.