Skip to content

쿠키와 세션, JWT란?

Usang Lee edited this page Jun 22, 2022 · 2 revisions

쿠키와 세션 그리고 JWT

쿠키란 무엇인가?

쿠키는 서버의 요청에 의해 사용자의 웹 브라우저에(정확히는 사용자의 컴퓨터의 하드디스크에) 저장되는 작은 텍스트 파일입니다.

해당 텍스트 파일에는 서버에 필요한 클라이언트의 정보가 담겨있습니다.

쿠키를 왜 쓰나요?

쿠키에는 서버에 필요한 클라이언트의 정보가 담겨있다고 했습니다.

만약 특정 클라이언트에게만 제공되야 하는 페이지가 있다고 하겠습니다. ex) admin.html 페이지

admin.html파일은 아무에게나 제공되어서는 안 되는 중요한 페이지입니다.

이 페이지는 오로지 admin에게만 전달되어야 하며

클라이언트가 서버에게 admin.html파일을 요청한다면 서버는 해당 클라이언트가

admin이라는 아이디와 해당 아이디에 매칭되는 패스워드를 아는 클라이언트인지

확인하는 방법을 통해 admin을 식별합니다.

Q) 그냥 클라이언트의 HTTP요청에 담긴 IP를 이용해서 식별하면 안되나요?

A) 네, 특정 사용자가 항상 같은 IP주소를 사용하지는 않기에 IP주소로 특정 사용자를 식별할 수 없습니다.


보통 클라이언트는 아이디와 패스워드 정보를

웹 페이지에 직접 입력하여

http://test.com?id=admin&password=1234같은 형태로

uri의 끝에 담아서(혹은 http헤더의 body에 실어서) 서버에게 전달합니다.

그 후 서버는 전달받은 아이디와 패스워드를 DB조회를 통해 매칭시켜

해당 클라이언트가 admin인지 아닌지 판단합니다.

만약 admin이 맞다면? → admin.html을 클라이언트에게 전달합니다!


서버는 클라이언트에게 받은 데이터를 검증하여 클라이언트가 admin이란 것을 알았고

admin.html을 전달했습니다.

자, 근데 서버에는 admin2.html파일이 있습니다.

이 페이지 또한 admin에게만 보여줄 수 있는 페이지입니다.

방금 전 클라이언트는 admin인증 과정을 마쳤기에 서버에게 곧바로 admin2.html파일을 요청한다면

서버는 클라이언트에게 admin2.html파일을 전달해야 할 것이지만, 실상은 그렇지 않습니다.

클라이언트는 다시 id와 password값을 uri의 끝에 담아서(혹은 http헤더의 body에 실어서)

서버에게 전달해야만 admin2.html페이지를 응답 받을 수 있습니다.

클라이언트는 이전에 HTTP요청으로 admin.html파일을 요청할 때 id와 password값을 서버에 보낸것과는 별개로

새로운 HTTP요청에도 id와 password값을 서버에 보내주어야 합니다.

클라이언트가 서버에게 보내는 HTTP요청에 추가적으로 데이터를 덧붙여서 전달하지 않는 이상

서버에서 해당 클라이언트가 누구인지 HTTP요청만으로는 식별할 수 없기 때문입니다.

그렇습니다, 클라이언트는 서버에게 admin권한이 필요한 페이지를 요청할 때마다

매번 웹 페이지에 아이디와 비밀번호 정보를 적어서 서버에게 전달하면 됩니다.

만약 이야기가 여기서 끝난다면 웹을 이용하기 정말 불편하지 않을까요?

그러한 불편함을 없애기 위해 나온 것이 쿠키입니다.


서버는 클라이언트로부터 HTTP요청과 함께 id, password같은 정보를 받아 인증에 성공했다면

이후 클라이언트에 대한 HTTP응답에 인증 정보를 담은 쿠키를 생성하라는 명령을 함께 보냅니다.

해당 응답을 받은 클라이언트는 자신의 브라우저에(로컬 하드에) 쿠키를 생성합니다.

이후 클라이언트는 서버에 요청을 보낼때마다 HTTP헤더에 방금 생성한 쿠키 정보를 실어서 보내게 됩니다.

쿠키에 id=admin, password=1234에 대한 정보가 담겨있다면

서버측에서는 해당 요청을 보낸 클라이언트가 매번 id와 password정보를 따로 전달하지 않더라도

전달받은 쿠키에 담긴 정보를 읽어 해당 클라이언트가 admin임을 식별할 수 있을 것입니다.

세션은 무엇인가요?

쿠키는 클라이언트가 매번 인증 데이터를 직접 작성해서 보내야 된다는 번거로움을 해결해 주었지만

한 가지 문제점이 있었습니다.

예를 들어, 온라인 뱅킹을 지원하는 은행 사이트가 있는데 이 사이트는 쿠키를 이용한 인증방식을 사용하고 있다고 하겠습니다.

아까 쿠키는 사용자의 컴퓨터 하드에 저장되어 있다고 했습니다.

만약 누군가 사용자의 하드에 담긴 쿠키 정보를 훔치는 일이 발생한다면 어떨까요?

해당 유저는 쿠키 정보를 이용해 은행 사이트에 접속하여 해당 유저의 돈을 마음대로 처분하는 일이 벌어질 것입니다.


이 사태에서 사용자가 보안관리를 잘못하여 쿠키를 탈취당한 것이 문제의 원인으로 보이지만

근본적인 원인은 서버가 인증 방식을 쿠키 방식으로 선택한 것에 있습니다.

은행 계좌 정보와 같은 중요한 정보를 다루는 서버에서

언제든 제 3자에 의해 탈취될 가능성이 있는 사용자 측에 모든 정보를 저장하는 쿠키를 인증방식으로 택했다는 것이라 할 수 있습니다.


많은 사용자가 이용하는 서버일수록

접속하는 모든 사용자의 환경과 보안을 서버측에서 일일히 신경쓰고 관리할 수 없기에

서버측에서는 사용자측에 저장된 정보를 이용할 시

반드시 해당 정보가 제 3자에 의해 탈취될 수 있는 가능성도 고려해야 합니다.

그러한 점에 착안해서 나온 것이 세션(session)입니다.


세션이란 쿠키와 비슷합니다.

서버에서 필요한 클라이언트의 정보를 어딘가에 저장해 놓는다는 점은 동일하지만

일부는 사용자의 하드에, 일부는 서버에 저장된다는 점이 다릅니다.

예를 들면. id와 password 정보를 저장한다는 점은 동일하지만

id는 사용자 측에, 중요한 password정보는 서버 측에 저장한다는 차이가 있습니다.

위에서 쉬운 설명을 위해 id와 password를 예로 들었지만

실제로 서버는 session-id라는 임의의값을 생성하여 사융자측에 쿠키로 저장해놓고

서버 내부에 session-id값과 매칭되는 id와 password 값을 저장합니다.

서버는 클라이언트로부터 session-id값을 전달받으면

서버 내부에서 그에 매칭되는 id와 password값을 찾아서 사용할 수 있습니다.

서버로부터 전달받은 쿠키와 세션에는 유효기간에 대한 정보가 포함되어 있습니다.

쿠키와 세션에는 클라이언트의 인증을 대신하는 중요한 데이터가 들어있다보니

누군가 해당 정보를 탈취하더라도 이를 악용할 가능성을 낮추기 위해

해당 정보가 서버에서 인증에 사용될 유효기간을 설정해 놓은 것입니다.


쿠키는 유효기간이 지나서 사용이 불가능해지더라도 내부에 중요한 정보가 포함되어 있기에 (id와 password정보)

탈취된다면 문제가 발생하지만

세션의 경우에는 클라이언트쪽에서 데이터가 탈취당하더라도 그 속에 중요한 내용이 들어있지는 않기에 (id와 password는 서버에 있음.)

보안 측면에서 장점이 있습니다.

하지만 세션의 경우에는 저장 시 서버의 자원을 사용하고

매번 클라이언트의 session-id와 서버 내부의 정보를 매칭하는 작업이 추가로 필요하므로

사용자가 많은 웹사이트 일수록 서버에 더 많은 부담을 주게 되는 단점이 있습니다.

그래서 일반적으로 쿠키는 자동완성이나 팝업 일주일간 보지 않기 등

정보가 유출되더라도 큰 지장이 없는 정보들을 저장할 때 사용되며

유출되어서는 안되는 민감한 정보들의 저장이 필요한 경우에는 세션을 사용하게 됩니다.

JWT는 무엇인가요?

JWT (Json Web Token)은 쿠키와 세션의 장점을 모두 취한 형태의 인증방식입니다.

JWT는 클라이언트의 쿠키에 저장되며 중요한 정보를 포함하지 않습니다.

만약 id와 password정보가 있다면 id정보만 저장하는 방식입니다.

클라이언트는 서버에 id와 password값을 보내 인증을 받은 후,

서버로부터 JWT를 발급받으면 이후 JWT안에 담긴 id값만으로 서버의 인증을 통과할 수 있습니다.


이렇게 보니 주먹구구식의 보안에 취약한 인증수단이라는 생각이 들 수도 있지만

JWT를 통한 인증의 중요한 특징은 내부에 인증에 필요한 정보가 담겨있다는 것이 아니라

비록 일부의 정보만 담겨있지만 서버로부터 발급받았음을 보장할 수 있다는 것입니다.

JWT는 HEADER, PAYLOAD, SIGNATURE 세 가지의 구성요소로 이루어져 있으며

각 구성요소는 json 형태의 데이터로 이루어져 있습니다.

HEADER에는 SIGNATURE값을 생성하기 위한 암호화 알고리즘에 대한 정보가 저장되어 있습니다.

PAYLOAD에는 특정 클라이언트를 식별할 수 있으며 민감하지 않은 정보들이 저장되어 있습니다.

SIGNATURE에는 HEADER와 PAYLOAD값과 특정 secret 문자열을 더한 후 이를 암호화(해시) 한 값이 들어있습니다.

secret문자열은 서버내부에 담긴 정보로서 외부에서 알 수 없는 정보입니다.


서버는 클라이언트로부터 id와 password값을 전달받아 인증을 수행한 후

JWT토큰의 HEADER에는 암호화 알고리즘의 종류, PAYLOAD에는 클라이언트의 id,

SIGNATURE에는 HEADER와 PAYLOAD값과 자신만 알고 있는 secret 문자열을 더하여 암호화(해시)한 값을 담아

클라이언트에게 전달합니다.

이후 클라이언트가 서버에게 요청을 보낼 때 JWT도 함께 전달되는데

서버는 전달받은 JWT의 HEADER, PAYLOAD, 자신이 가진 secret 문자열을 더한 후

새로 다시 SIGNATURE를 생성합니다.

그리고 전달받은 JWT의 SIGNATURE값과 자신이 방금 생성한 SIGNAUTRE값을 비교하여

두 값이 동일하다면 JWT를 서버 자신이 발급한 값이라 판단하고

PAYLOAD의 id값을 신뢰할 수 있는 값이라 여기게 되어

password정보가 없더라도 클라이언트의 인증을 허락하는 방식입니다.


JWT는 클라이언트 측에 민감한 정보를 보관하지도 않으며

서버 측에도 모든 클라이언트들에게 공통적으로 적용할 secret문자열 말고는 따로 보관되는 정보가 없기에

보안과 서버부하 측면에서 훌륭한 인증수단이라고 할 수 있습니다.