이 글은 그랩님의 쉽게 알아보는 서버 인증 1편(세션/쿠키 , JWT) 글을 참고하여 작성했습니다.
인증이란 사용자가 서비스의 회원인지 확인하는 방식을 의미한다. 비밀번호가 인증의 대표적인 예시이다.
사용가 아이디와 패스워드로 로그인 이후에 로그인을 하고 유효한 사용자가 보낸 요청일 때만 응답해줘야하는 경우가 있다.
이 때 사용자의 요청에 로그인이 되었는지 안되었는지에 대한 정보를 알아야 하는데 어떻게 로그인 정보를 알 수 있을까?
대표적으로 2가지 방식이 있다.
각 방식에 대해서 알아보자.
사용자가 웹 브라우저를 통해 웹서버에 접속한 시점으로부터 웹 브라우저를 종료하여 연결을 끝내는 시점까지, 같은 사용자로부터 오는 일련의 요청을 하나의 상태로 보고, 그 상태를 일정하게 유지하는 기술.
즉, 방문자가 웹 서버에 접속해있는 상태를 하나의 단위로 보고 그것을 세션이라고 한다.
HTTP 쿠키 자세히보기
HTTP 쿠키는 서버가 웹 브라우저에 전송하는 작은 데이터 조각이다. 브라우저는 데이터 조각들을 저장해 놓았다가, 동일한 서버에 재요청 시 저장된 데이터를 함께 전송한다. 쿠키는 두 요청이 동일한 브라우저에서 들어왔는지 아닌지를 판단할 때 주로 사용하며, 이를 통해 사용자의 로그인 상태를 유지할 수 있다.
쉽게 말해 서버와 클라이언트 간에 통신을 할 때 상태를 전송하기 위한 기술이다.
세션ID
, 유저ID
, 만료시간
으로 구성되어있다.JWT는 Json Web Token의 약자로 인증에 필요한 정보들을 암호화시킨 토큰을 뜻한다.
사용자가 요청을 보낼때 JWT을 HTTP 헤더에 실어 서버로 보내는 방식으로 인증을 진행한다.
💡
세션/쿠키는 세션 저장소에 유저의 정보를 넣는 반면, JWT는 토큰 안에 유저의 정보들이 넣는다
클라이언트 입장에서는 HTTP 헤더에 세션ID나 토큰을 실어서 보내준다는 점에서는 동일하나, 서버 측에서는 인증을 위해 암호화를 하냐, 별도의 저장소를 이용하냐는 차이가 발생한다.
{"typ":"JWT","alg":"HS512"}
{"iss": "was", "id": 12, "exp": 1643865426, "iat": 1643779026}
HMACSHA512(base64UrlEncode(header) + "." + "base64UrlEncode(payload)", secret-key)
페이로드를 포함한 어떠한 내용이라도 수정을 한다면 JWT토큰 자체가 바뀌게 된다.
수정을 한 사람은 시크릿 키를 모르기 때문에 JWT 값이 올바르게 변경이 되지 않는다.
위변조된 JWT는 서버에서 시크릿키로 검사를 진행하면 유효한지 확인할 수 있다.
사용자가 로그인을 한다.
서버에서는 계정정보를 읽어 사용자를 확인 후, 사용자의 고유한 ID값을 부여한 후, 기타 정보와 함께 Payload에 넣는다.
JWT 토큰의 유효기간을 설정한다.
암호화할 SECRET KEY를 이용해 ACCESS TOKEN을 발급한다.
사용자는 Access Token을 받아 저장한 후, 인증이 필요한 요청마다 토큰을 헤더에 실어 보낸다.
서버에서는 해당 토큰의 Verify Signature를 SECRET KEY로 복호화한 후, 조작 여부, 유효기간을 확인한다.
검증이 완료된다면, Payload를 디코딩하여 사용자의 ID에 맞는 데이터를 가져온다.
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)로 하여 생성하면 해독하기 힘든 시크릿키를 생성할 수 있다.