로그인 인증 - 세션과 쿠키, JWT

younoah·2022년 2월 2일
0

[nodeJS]

목록 보기
14/15

이 글은 그랩님의 쉽게 알아보는 서버 인증 1편(세션/쿠키 , JWT) 글을 참고하여 작성했습니다.

인증이란?

인증이란 사용자가 서비스의 회원인지 확인하는 방식을 의미한다. 비밀번호가 인증의 대표적인 예시이다.

사용가 아이디와 패스워드로 로그인 이후에 로그인을 하고 유효한 사용자가 보낸 요청일 때만 응답해줘야하는 경우가 있다.

이 때 사용자의 요청에 로그인이 되었는지 안되었는지에 대한 정보를 알아야 하는데 어떻게 로그인 정보를 알 수 있을까?

대표적으로 2가지 방식이 있다.

  • 세션과 쿠키
  • JWT

각 방식에 대해서 알아보자.


세션과 쿠키

세션이란?

사용자가 웹 브라우저를 통해 웹서버에 접속한 시점으로부터 웹 브라우저를 종료하여 연결을 끝내는 시점까지, 같은 사용자로부터 오는 일련의 요청을 하나의 상태로 보고, 그 상태를 일정하게 유지하는 기술.

즉, 방문자가 웹 서버에 접속해있는 상태를 하나의 단위로 보고 그것을 세션이라고 한다.


쿠키란?

이전에 HTTP 헤더 - 쿠키 작성글

HTTP 쿠키 자세히보기
HTTP 쿠키는 서버가 웹 브라우저에 전송하는 작은 데이터 조각이다. 브라우저는 데이터 조각들을 저장해 놓았다가, 동일한 서버에 재요청 시 저장된 데이터를 함께 전송한다. 쿠키는 두 요청이 동일한 브라우저에서 들어왔는지 아닌지를 판단할 때 주로 사용하며, 이를 통해 사용자의 로그인 상태를 유지할 수 있다.

쉽게 말해 서버와 클라이언트 간에 통신을 할 때 상태를 전송하기 위한 기술이다.


세션/쿠키 인증 과정

  1. 사용자가 로그인 정보를 입력하고 서버에게 요청을 보낸다.
  2. 서버는 회원DB에서 사용자 정보를 확인한다.
  3. 해당 회원정보의 세션을 생성하고 세션저장소(DB)에 저장을 한다.
    • 세션은 세션ID, 유저ID , 만료시간 으로 구성되어있다.
  4. 세션의 세션ID를 반아온다.
  5. response의 쿠키에 세션ID를 담아서 클라이언트에게 응답을 보낸다.
  6. 클라이언트는 인증이 필요한 요청일 때 마다 쿠키를 헤더에 담아서 보낸다.
  7. 이후 서버에서 쿠키에 담긴 세션정보를 검증하여 유저에게 응답을 한다.

장점

  • 고유의 세션 ID를 발급 받기 때문에 일일이 회원 정보를 확인할 필요가 없어 서버 자원에 접근하기 용이하다.

단점

  • HTTP 요청을 해커가 가로 챘다면 그 안의 Cookie도 탈취가 가능하다.
  • 서버에 세션을 저장해야하는 추가적인 저장공간이 필요해진다.

JWT 방식

JWT란?

JWT는 Json Web Token의 약자로 인증에 필요한 정보들을 암호화시킨 토큰을 뜻한다.

사용자가 요청을 보낼때 JWT을 HTTP 헤더에 실어 서버로 보내는 방식으로 인증을 진행한다.

💡

세션/쿠키는 세션 저장소에 유저의 정보를 넣는 반면, JWT는 토큰 안에 유저의 정보들이 넣는다

클라이언트 입장에서는 HTTP 헤더에 세션ID나 토큰을 실어서 보내준다는 점에서는 동일하나, 서버 측에서는 인증을 위해 암호화를 하냐, 별도의 저장소를 이용하냐는 차이가 발생한다.


JWT 구조

  • 헤더
    • JWT 토큰을 어떻게 해석해야 하는지를 명시하는 부분, Payload와 Signature를 어떻게 해석할지를 알 수 있다.
    • 사용하는 암호화 알고리즘과 타입을 명시한다.
    • i.e {"typ":"JWT","alg":"HS512"}
    • base64로 인코딩해서 헤더를 생성한다.
  • 페이로드
    • 주고받고 싶은 데이터를 담는다.
    • i.e {"iss": "was", "id": 12, "exp": 1643865426, "iat": 1643779026}
    • base64 인코딩해서 페이로드를 생성한다.
  • 시그니쳐
    • 헤더와 페이로드는 암호화를 한 것이 아니라 단순히 JSON문자열을 base64로 인코딩한 것뿐이다.
    • 그래서 누구나 이 값을 다시 디코딩하면 JSON에 어떤 내용이 들어있는지 확인할 수 있다.
    • 토큰을 사용하는 경우 이 토큰을 다른 사람이 위변조할 수 없어야 하므로, 헤더와 페이로드의 위변조 여부를 검증하기 위한 부분이 Signature 부분이다.
    • 헤더와 페이로드를 인코딩한 값을 마침표로(.) 이어주고 시크릿키와 함께 헤더에서 alg로 지정한 알고리즘 HS512 즉, HMACSHA512으로 인코딩하여 생성한다.
    • HMACSHA512(base64UrlEncode(header) + "." + "base64UrlEncode(payload)", secret-key)
    • 공격자가 서명을 위변조할 수 없도록 비밀키를 사용한다.

페이로드를 포함한 어떠한 내용이라도 수정을 한다면 JWT토큰 자체가 바뀌게 된다.

수정을 한 사람은 시크릿 키를 모르기 때문에 JWT 값이 올바르게 변경이 되지 않는다.

위변조된 JWT는 서버에서 시크릿키로 검사를 진행하면 유효한지 확인할 수 있다.


JWT 인증과정

  1. 사용자가 로그인을 한다.

  2. 서버에서는 계정정보를 읽어 사용자를 확인 후, 사용자의 고유한 ID값을 부여한 후, 기타 정보와 함께 Payload에 넣는다.

  3. JWT 토큰의 유효기간을 설정한다.

  4. 암호화할 SECRET KEY를 이용해 ACCESS TOKEN을 발급한다.

  5. 사용자는 Access Token을 받아 저장한 후, 인증이 필요한 요청마다 토큰을 헤더에 실어 보낸다.

  6. 서버에서는 해당 토큰의 Verify Signature를 SECRET KEY로 복호화한 후, 조작 여부, 유효기간을 확인한다.

  7. 검증이 완료된다면, Payload를 디코딩하여 사용자의 ID에 맞는 데이터를 가져온다.


장점

  • 서버에서 상태가 존재하지 않는 장점이 있다.

단점

  • 서버와 끊임 없이 jwt 헤더를 통해 통신을 하는데 만약 영원히 만료되지 않는 jwt라면 해커가 jwt를 가져다가 활용할 수 있는 위험성이 있다. 따라서 jwt를 잘 관리해줘야 한다.

JWT 사용해보기

jsonwebtoken 라이브러리를 설치해주자.

$ npm i jsonwebtoken

JWT 생성 및 유효성 검사 예시 코드

import jwt from 'jsonwebtoken';

// 시크릿키
const secretKey = '12r#%@2v$7#uSg$DjmzdgXlxqo2zqP5h';

// 페이로드
const payload = {
  id: '12',
  isAdmin: true,
};

// jwt 토큰 생성
// 3번째 인자는 옵션: expriesIn은 만료기간을 초단위로 명시
const token = jwt.sign(payload, secretKey, { expriesIn: 60 * 60 * 5 });

// jwt 토큰 유효성 검사
jwt.verify(token, secretKey, (error, decoded) => {
  console.log(error, decoded);
});

// 위변조가 없는 JWT라면 올바르게 decoded에 담겨온다.
// 위변조가 된 JWT라면 error가 발생한다.

안전한 시크릿 키 생성 팁

시크릿키를 지정할 때 임의 문자열을 작성해도 무방하다. 하지만 좀 더 안전한 jwt를 발급하려면 시크릿키도 복잡해야 한다.

https://www.lastpass.com/features/password-generator

위 사이트에서 length를 32(32byte = 256bit)로 하여 생성하면 해독하기 힘든 시크릿키를 생성할 수 있다.

profile
console.log(noah(🍕 , 🍺)); // true

0개의 댓글