Authentication - 인증 및 로그인

박재현·2022년 2월 21일
0
post-custom-banner

💡 로그인 기능 구현을 위한 인증방식은 크게 세션 / JWT 방식이 있다.



📌 로그인 기능 구현 ( 세션 / JWT )

📣 회원가입 및 로그인 구현 순서

1. Client -> Server

  • 회원 가입 요청: POST request (Id, 닉네임, Password 등)

2. Server

  • 데이터베이스에 사용자 정보 저장

3. Client -> Server

  • 로그인 요청: POST request

4. Server

  • 검증 성공 및 실패 (Session / JWT 방식)

5. Server -> Client

  • 로그인 성공 및 실패

해당 유저가 로그인 시 실제 등록된 유저인지 인증하게 되고, 인증이 되었다면 해당 세션Id(쿠키) 및 JWT 정보를 헤더에 담아 전달하게 된다.

6. Client -> Server

  • 세션Id(쿠키) 및 헤더에 JWT 토큰을 담아 요청 전송

이후 요청에서 브라우저에 저장된 쿠키 및 Header(JWT) 정보를 넣어서 서버에 원하는 API 요청

7. Server -> Client

  • 해당 요청에 대한 정보 전송(응답)

🔐 JWT (JSON Web Token)

  • JSON 형태의 데이터를 안전하게 교환하여 사용
  • 인터넷 표준으로서 자리잡은 규격입
  • 여러가지 암호화 알고리즘을 사용
  • header.payload.signature 의 형식으로 3가지의 데이터를 포함 (개미처럼 머리, 가슴, 배)
    때문에 JWT 형식으로 변환 된 데이터는 항상 2개의 . 이 포함된 데이터
  • JWT는 암호 키를 몰라도 Decode가 가능
    변조만 불가능 할 뿐, 누구나 복호화하여 해당 정보를 보는것은 가능

📣 인증 순서

1. Client -> Server

  • 로그인 요청: POST request

5. Server

  • JWT 생성(Create JWT Web Token)

6. Server -> Client

  • 클라이언트에게 JWT 전송

7. Client -> Server

  • 이후 모든 요청에 Header에 Authorization: Bearer JWT 정보를 포함해서 보냄

8. Server

  • 유효성 판단을 위해 전달받은 JWT의 payload를 비밀키를 통해 검증 및 만료 여부 파악

9. Server -> Client

  • 유효하다면 요청을 처리하여 Client에게 전송

📣 형태

https://jwt.io/ 에서 간단히 확인가능

  • header(머리)는 Algorithm과 signature(배)에서 어떤 암호화를 사용하여 생성된 데이터인지 표현
	{
      "alg": "HS256"
      "type" "JWT"
    }
  • payload(가슴)는 개발자가 원하는 데이터를 저장 (인코딩)
	{
      "loggedInAs": "admin"
      "iat" 123353111
    }
  • signature(배)는 이 토큰이 변조되지 않은 정상적인 토큰인지 확인
	{
      "loggedInAs": "admin"
      "iat" 123353111
    }

📣 사용 방법

// npm i jsonwebtoken
const jwt = require('jsonwebtoken');

// 토큰 생성, payload: { test: true } 시크릿 키: 'my-secret-key' expiresIn: 만료기한
const token = jwt.sign(
  { test: true },
  'my-secret-key',
  { expiresIn: 5 });
console.log(token);
// eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0ZXN0Ijp0cnVlLCJpYXQiOjE2NDAxNzI3NTN9._Nu27p4dDeGdvjncA_mBFZFEYNxWVeuGdkK2DJzdG1Y

// 복호화
const decoded = jwt.decode(token)
console.log(decoded)
// { test: true, iat: 1640173279 }

// 정상적인 토큰인지 검증
const verify = jwt.verify(token,"my-secret-key")
console.log(verify)
// { test: true, iat: 1640173279 }
// 만약 시크릿키가 정상적이지 않다면 error 발생

// 머리(HEADER).가슴(PAYLOAD).배(VERIFY SIGNATURE) 로 생성이되며
// jwt.io에서 해당 token을 입력해 보면 
// 가슴(payload)에 해당 데이터인 {"test": true} 을 담고 있다.
// 누구나 해당 사이트에서 Encoded(복호화)를 통해 데이터를 확인할 수는 있지만
// 변조가 불가능하며
// 배(VERIFY SIGNATURE)에 시크릿키(여기서는 "my-secret-key"를 입력해야
// 해당 데이터가 정상적인 토큰인지 signature verified 할 수 있다.

📣 특징

  • JWT는 암호 키를 몰라도 Decode가 가능
    변조만 불가능 할 뿐, 누구나 복호화하여 보는것은 가능
  • 때문에 민감한 정보(개인정보, 비밀번호 등)는 담지 않도록 해야함
  • 특정 언어에서만 사용 가능한것은 아님
    단지 개념으로서 존재하고, 이 개념을 코드로 구현하여 공개된 코드를 우리가 사용하는게 일반적
  • 서버 클라이언트 간 중요한 정보가 담긴 JWT를 주고 받기 때문에 만료기한을 설정하지 않을 수록 탈취 위험이 있을 수 있음

📣 쿠키, 세션과 다른점

데이터를 교환하고 관리하는 방식인 쿠키/세션과 달리, JWT는 단순히 데이터를 표현하는 형식

  • JWT로 만든 데이터를 브라우저로 보내도 쿠키처럼 자동으로 저장되지는 않지만, 변조가 거의 불가능하고 서버에 데이터를 저장하지 않기 때문에 서버를 stateless(무상태) 로 관리할 수 있기 때문에 최근 많이 쓰이는 기술중 하나
  • stateless(무상태)와 stateful(상태 보존)의 차이를 간단히 설명하자면,
    Node.js 서버가 언제든 죽었다 살아나도 똑같은 동작을 하면 Stateless
    반대로 서버가 죽었다 살아났을때 조금이라도 동작이 다른 경우 Stateful
  • 서버가 스스로 어떤 기억을 갖고 다른 결정을 하냐 마냐의 차이
  • 로그인 정보를 서버에 저장하게 되면 무조건 Stateful(상태 보존)

🔐 Session

  • 사용자의 민감한 상태 정보는 쿠키를 기반으로 서버에 저장하는 방식
  • 사용자를 식별 할 수 있는 SessionID를 생성하여 SessionID에 해당하는 상태 정보를 저장

📣 인증 순서

  1. Client -> Server
    로그인 요청

  2. Server <-> Database
    Verify(검증 성공 or 실패)

  3. Server
    세션 생성(Create Session)

  • UserId, sessionId, expiration ...
  1. Server
    세션에 해당 데이터 저장 ( 데이터베이스 or 파일 시스템 or 메모리 )

  2. Server -> Client
    { Cookie: sessionId } 정보를 넣어 클라이언트에 보내줌
    ( HTTP Only 옵션: 해당 쿠키는 브라우저에 의해서만 읽을 수 있게 됨 )

  3. Client -> Server
    이후 브라우저에서 요청을 보낼 때 전달받은 { Cookie: sessionId } 함께 보내줌

  4. Server
    존재하는 sessionId or 만료기한을 파악하여 유효하다면 사용자가 누구인지 파악 및 요청 처리

  5. Server -> Client
    관련된 데이터를 클라이언트 에 보내줌


📣 장점

  • session에 데이터베이스에 모든 정보 저장하기 때문에 신뢰할 수 있음
  • 별도의 처리 과정 없이 쿠키를 통해 정보를 주고 받으므로 Simple하게 구현
  • HTTP Only 옵션을 사용하면 브라우저만 데이터를 읽을 수 있어 보안성 UP
  • Cookie에 sessionId를 통해서만 데이터를 주고 받기 때문에 사용자 정보 노출 우려가 없음

📣 단점

  • 서버에 해당 정보가 stateful 저장되어 사용자가 많아질 수록 네트워크 요청 횟수에 따라 성능 저하

🔎 시시각각 변하는 사용자에 대해 세션에 정보를 보관하고 있기 때문에 서버를 확장해 여러 서버에서 동작을 하거나 마이크로 서비스를 하는 경우 한 다양한 서버들이 세션 정보를 확인하기위해 네트워크 요청을 해야함
즉, 클라이언트 요청을 처리하기 위해 내부적으로 여러가지 네트워크 요청을 해야해서 시간이 오래걸리고 분산형 시스템으로 서비스를 잘 디자인 했음에도 세션으로 인해 성능이 좋지 안은 경우가 발생


💡 세션을 통한 구현방식은 passport 라는 라이브러리를 활용한 방법이 있다. 기존에 passport를 통해 기본 및 카카오 로그인을 구현한 내용을 다시 한 번 정리해보고 포스팅 해볼 수 있도록 하겠다.

post-custom-banner

0개의 댓글