본문 바로가기
TIL/기타

TIL : 서버 인증 방법 (세션 / 쿠키, JWT)

by yeon_zoo 2021. 8. 14.

HTTP 요청

현재 모바일이나 웹 서비스에서 가장 많이 쓰이는 통신 방식은 HTTP 통신이다. HTTP 통신은 응답 후 연결을 끊게 되며 과거에 대한 정보를 전혀 담지 않는다. 즉 지금 보낼 HTTP 요청은 지난 번에 내 정보를 담아 보냈던 HTTP 요청과 전혀 관계가 없다는 말이다. 따라서 각각의 HTTP 요청에는 주체가 누구인지에 대한 정보가 필수적이다. 

 

서버에 요청을 보내는 작업은 HTTP 메세지를 보내는 것이다. HTTP 메세지의 구조는 다음과 같다. 일반적으로 헤더와 바디 두 가지로 구성되며 공백은 헤더와 바디를 구분짓는 역할을 한다. 여기서 헤더에는 요청에 대한 정보들이 들어간다 바디에는 서버로 보내야 할 데이터가 들어가게 된다. 보통은 HTTP 메세지의 헤더에 인증 수단을 넣어 요청을 보낸다. HTTP 기본 인증 방법은 다음과 같다.

 

1. 계정정보를 요청 -> 헤더에 넣는 방식 (HTTP base 방식)

이 방식은 가장 보안이 낮은 방식으로 계정 정보를 요청에 담아 보내는 방식이다. 이는 보안에 상당히 취약하다. 데이터를 요청할 때마다 사용자의 개인 정보를 계속해서 보내는 방식이면서도 HTTP 요청 방식은 따로 암호화되지 않기 때문이다. (HTTPS 방식은 암호화가 되지만, HTTP는 문자 그대로 보여준다.) 해커가 HTTP 요청을 가로채면 사용자의 계정정보를 알 수 있다. 실제 서비스에서는 쓰이지 않는다. 인증을 테스트하기 위해서 빠르게 개발 단계에서 사용해볼 수는 있다. 

 

2. Session / Cookie 방식

위에서 확인한 계정 정보를 헤더에 넣는 방식이 보안에 매우 취약하기 때문에 나온 인증 방식이다. 순서는 다음과 같다.

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

 2) 서버에서는 계정정보를 읽어 사용자를 확인한 후, 사용자의 고유한 ID 값을 부여하여 세션 저장소에 저장하고 이와 연결되는 세션 ID를 발행합니다.

 3) 사용자는 서버에서 해당 세션 ID를 받아 쿠키에 저장 한 후, 인증이 필요한 요청마다 쿠키를 헤더에 실어 보낸다. 

 4) 인증이 완료되고 서버는 사용자에 맞는 데이터를 보내준다. 

세션 쿠키 방식의 인증은 세션 저장소를 필요로 한다. 세션 저장소는 로그인을 했을 때 사용자의 정보를 저장하고 열쇠가 되는 세션 ID 값을 만든다. 그리고 HTTP 헤더에 실어 사용자에게 돌려 보낸다. 그러면 사용자는 쿠키로 보관하고 있다가 인증이 필요한 요청에 쿠키(세션 ID)를 넣어 보낸다. 웹 서버에서는 세션 저장소에서 쿠키(세션 ID)를 받고 저장되어 있는 정보와 매칭시켜 인증을 완료한다. 

 

※ 세션은 서버에서 가지고 있는 정보이며 쿠키는 사용자에게 발급된 세션을 열기 위한 열쇠(session ID)를 의미한다. 쿠키만으로 인증을 사용한다는 말은 서버의 자원은 사용하지 않는다는 것이며 이는 클라이언트가 인증 정보를 책임지게 된다. 그렇게 되면 위의 첫 번째 방식처럼 HTTP 요청이 Intercept 되면 다 털리게 된다. 따라서 쿠키만 사용하는 것은 장바구니 담기나 자동 로그인 설정 같은 경우에 유용하게 쓰인다.

 

결과적으로 인증의 책임을 클라이언트가 아닌 서버에 두려고 세션을 이용하는 것이다. 서버 해킹이 개인 사용자 해킹 보다 훨씬 어려우니까) 사용자는 쿠키를 이용하고 서버에서는 쿠키를 받아 세션의 정보를 접근하는 방식으로 인증한다. 

 

장점

이 방법은 세션 저장소에 담긴 유저 정보를 얻기 위한 열쇠라고 볼 수 있는 쿠키를 매개로 인증한다. 따라서 쿠키가 담긴 HTTP 요청이 도중에 노출되더라도 쿠키 자체는 유의미한 값이 없고 중요 정보는 서버 세션에 있다. 따라서 계정 정보를 직접 담아 인증을 거치는 것보단 안전하다. 또한 사용자마다 고유의 ID 값을 발급받게 되어서 서버가 쿠키 값을 받았을 때 회원 정보를 일일이 확인하지 않고도 어떤 회원인지 확인이 가능하다. 이렇게 되면 서버의 자원에 접근하기가 용이하다. 

단점

하지만 사용자의 HTTP 요청을 해커가 가로채면 그 안에 들어있는 쿠키도 훔칠 수 있다. 그리고 훔친 쿠키를 이용해서 HTTP 요청을 보내면 서버의 세션 저장소에서는 사용자를 오해해 정보를 잘못 뿌려주게 된다. (세션 하이재킹 공격이라고 함)

-> 이 때 HTTPS 를 사용해 요청 자체를 탈취해도 안의 정보를 읽기 어렵게 하거나 세션에 유효시간을 넣어줘서 방지할 수도 있다. 

또, 서버에서 세션 저장소를 사용하기 때문에 추가적인 저장공간을 필요로 한다는 점에서 부하가 높아질 수 있다. 서버가 한 대일 때는 한 세션 저장소만 이용하면 되지만, 여러 대일 경우에 같은 세션 데이터를 여러 서버에 저장해야 한다는 점에서 비효율적이다. 

 

3. 토큰 기반 인증 방식 (JWT)

JWT는 Json Web Token의 약자로 인증에 필요한 정보들을 암호화시킨 토큰을 뜻한다. 위의 세션/쿠키 방식과 유사하게 사용자는 Access Token(JWT 토큰)을 HTTP 헤더에 실어 서버로 보낸다. 

 

토큰을 만들기 위해서는 크게 3가지, Header, Payload, Verify Signature 가 필요하다. 

  • Header : 위 3가지 정보를 암호화할 방식, 타입 등이 들어간다.
  • Payload : 서버에서 보낼 데이터가 들어간다. 일반적으로 유저의 고유 ID 값, 유효기간이 들어간다. 
  • Verify Signature : Base64 방식으로 인코딩한 Header, payload 그리고 SECRET KEY를 더한 후 서명 된다. 

최종적인 결과로 Encoded Header + Encoded Payload + Verify Signature 이 보내지게 되는데, Header과 Payload는 인코딩 될 뿐 따로 암호화되지는 않는다. 따라서 누구나 이 부분은 디코딩하여 확인할 수 있다. 하지만 verify signature는 secret key를 알지 못하면 복호화할 수 없다. 그렇기 때문에 해커가 토큰을 조작하여 사용자의 정보를 확인하려고 해도 Verify Signature은 사용자의 Payload를 기반으로 암호화되어 있다. 반면 해커의 Payload는 해커의 정보가 들어가 있기 때문에 서버에서는 이를 유효하지 않은 토큰으로 간주하게 된다. 

 

이러한 이해를 바탕으로 JW가 인증에 사용되는 순서를 알아보면 다음과 같다.

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

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

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

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

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

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

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

사용자의 입장에서 보면 HTTP 헤더에 세션 ID나 토큰을 실어서 보내준다는 점에서는 동일하지만 세션/쿠키는 세션 저장소에 유저의 정보를 넣고, JWT는 토큰 안에 유저의 정보들을 넣는다. 따라서 서버 측에서는 인증을 위해 암호화를 하냐, 별도의 저장소를 이용하냐는 차이가 발생한다. 

 

장점

이는 세션/쿠키는 별도의 저장소 관리가 필요하다는 점과 비교했을 때 훨씬 간편하다. JWT는 발급한 후 검증만 하면 된다. 따라서 별도의 저장소를 사용하지 않는, 상태를 저장하지 않는 stateless한 서버를 만드는 입장에서는 상당히 유리하다. 또한, 토큰을 기반으로 하는 다른 인증 시스템(Facebook, Google 로그인 등)에 접근이 가능하기 때문에 확장성이 뛰어나다. 더불어서 선택적으로 이름이나 이메일 등을 받는 권한도 가질 수 있다. 

단점

반면 이미 발급된 JWT에 대해서는 돌이길 수 없다는 점에서 단점을 갖는다. 세션/쿠키의 경우, 쿠키가 악의적으로 이용된다면 해당하는 세션을 지워버리면 된다. 하지만 JWT는 한 번 발급되면 유효기간 완료시까지 계속 사용이 가능하다. --> 그래서 기존의 Access Token의 유효기간을 짧게 하고 Refresh Token 이라는 새로운 토큰을 발급한다. 그렇게 되면 Access Token을 탈취 당해도 상대적으로 피해를 줄일 수 있다.

Payload 정보가 제한적이라는 단점도 있다. Payload는 암호화되지 않기 때문에 디코딩하면 누구나 정보 확인이 가능하다. 따라서 중요 정보들은 payload에 담을 수 없다. (세션/쿠키는 서버의 저장소에 안전하게 저장된다)

JWT의 길이가 세션/쿠키 방식에 비해 길다. 따라서 인증이 필요한 요청이 많아질 수록 서버의 자원낭비가 발생하게 된다. 

 

참고 
https://tansfil.tistory.com/58

댓글