[IT] 쿠키, 세션, 토큰

노유성·2023년 7월 26일
0
post-thumbnail

들어가며

Spring을 통해서 API 서버를 만들면서 인증과 인가, 보안에 대해서 생각하지 않을 수가 없었고 듣는 강좌에서 OAuth 2.0 프레임워크를 이용해서 보안을 인증과 인가를 하려고 하는데 인증과 인가에 대해 기본적인 개념이 없어서 작성되었다.

쿠키

HTTP 통신은 요청과 응답이 종료되면은 상태가 연결되지 않으므로(stateless) 다음에 클라이언트가 요청을 할 때 서버에서 클라이언트를 식별하기 위해서 쿠키, 세션, 토큰과 같은 방식이 도입되었다.


쿠키는 위 그림과 같이 클라이언트가 서버에 ID, PW에 대한 정보를 넘기면은 서버에서 이에 대해 클라이언트가 DB에 존재하는 지에 대한 여부를 검사하고 인증이 완료가 되면 인증 정보를 쿠키에 담아서 클라이언트에게 보낸다. 그러면 클라이언트는 다음 요청부터는 요청 헤더에 쿠키를 담아서 보내고 서버에서는 이를 보고 인증된 사용자인지 아닌지를 구별할 수 있다.

하지만 쿠키는 브라우저에 저장되며 공개가 되는 정보이기 때문에 보안에 있어서 매우 취약하므로 인증 후 상태를 유지하기 위한 전략으로는 적절하지 않다. 또한 인증 정보 및 중요한 개인 정보가 Client에서 다뤄지므로 탈취가 될 경우에는 문제가 심각해진다.

세션


세션을 한 단어로 표현하자면 공연장 티켓이다. 사용자가 서버에게 인증 요청을 한 이후에 인증을 서버 쪽에서는 인증 티켓을 만들고 반으로 나눠서 하나는 사용자에게 하나는 서버에서 갖는다.

사용자의 반쪽짜리 티켓은 쿠키에 저장이 되며 다음 요청부터 헤더에 담겨서 보내게 된다. 그러면 서버에서는 클라이언트가 보낸 티켓과 자신이 갖고 있는 티켓을 대조하여 사용자를 식별할 수 있다.

세션은 자체 DB에 세션 정보를 저장하기 때문에 사용자에 대해 통제권을 가질 수 있다는 장점이 있다. 만약에 특정 사용자를 강제로 로그아웃하게 하고 싶다면 DB에서 해당 사용자의 세션 정보를 삭제하면된다. 또한 사용자의 민감한 정보를 서버에서 다루기 때문에 해커가 이를 탈취하기가 어렵다.

하지만 세션의 치명적인 단점은 모든 사용자의 반쪽짜리 티켓을 서버에서 들고 있어야 한다는 점이다. 이를 보완하기 위해 redis처럼 가벼운 DB를 이용해서 세션 정보를 관리한다는 해결책도 있지만 결국엔 반쪽짜리 티켓을 들고 있는다는 리스크 자체는 변하지 않는다.

토큰


세션과 헷갈리기 쉬운 토큰은 클라이언트가 로그인 요청을 하면은 무언가를 생성해서 클라이언트에게 전달한다는 점까지는 동일하지만 서버에서 어떤 정보를 갖고 있지 않다는 점에서 차이가 있다. 그러면 서버에서는 어떻게 아무 정보도 없으면서 사용자를 식별할 수 있을까? 바로 서버 쪽에서 데이터를 검증한다는 점이다. 암호화된 토큰을 발급하고 이를 사용자가 요청 헤더에 담아서 서버에 보내면은 서버에서는 토큰을 복호화해서 사용자를 알아볼 수 있다. 이로 인해 DB를 조회하지도, 반쪽 티켓을 갖지도 않은 채로 사용자를 알아볼 수 있는 것이다.

하지만 이런 토큰도 데이터의 길이가 길어서 인증 요청이 많아지면 네트워크 부하가 심하게 걸린다는 단점이 있으며 Payload가 암호화되지 않으므로 중요한 정보를 담을 수 없으며, 탈취되면 대처가 어렵다는 단점이 있다. 마지막 단점을 극복하기 위해서 토큰 사용 기간을 제한하는 식으로 극복을 한다.

JWT(Json Web Token)

JWT는 json으로 만들어진 토큰을 의미한다. json데이터를 base64 로 인코딩하고 직렬화 한것으로, 토큰 내부에 위조 방지를 위해 서버의 개인키로 서명한 전자 서명도 들어있다. 따라서 사용자가 JWT를 전송하면 서버는 서명을 검증게 된다.

JWT 구조

payload

누가 누구에게 토큰 발급했는지, 토큰의 유효기간, 서버가 사용자에게 이 토큰으로 공개하고자 하는 내용(닉네임, 레벨, 관리자 여부) 등의 정보를 담을 수 있으며 이렇게 담긴 데이터를 Claim 이라고 부른다. 이렇게 데이터를 담으면은 인증 후에 서버에서 사용자에게 요청이 들어올 때마다 필요한 정보를 DB에서 찾아봐야 하는 수고를 덜 수 있다. 예를 들어, 인증된 A 사용자의 이름, 나이, 성별, 닉네임은 토큰에 담아도 되는 개인정보이고 자주 사용되는 정보이기에 매번 DB에서 조회하면은 리소스가 많이 소요될 것이다.

header에는 2가지 값이 들어간다. type, alg,

type은 JWT로 고정이다.

alg은 알고리즘의 약자로 서명을 만들기 위한 알고리즘이 적용된다. 여러 암호화 방식중 하나를 선택할 수 있으며 이렇게 하여 header의 정보, payload의 정보, 서버의 암호값 3가지를 alg에 정의된 알고리즘에 넣어서 돌리면 서명값이 나오는 거다.

이렇게 해서 payload와 header값 중 조금이라도 바뀌면은 서명값을 만들 수 없도록하여 정보를 강제할 수 있다.

한계점

JWT의 한계점은 토큰의 한계점과 유사하게 사용자의 권한을 강제할 수 없다는 점이 있으며 토큰을 탈취 당하면 서버에서는 이를 막을 수 없다는 단점이 있다. 이를 해결하기 위해서 서버에서는 수명이 매우 짧은 access 토큰과 수명이 긴 refresh 토큰을 발급해서 access 토큰을 이용해 인가를 받고 혹시 탈취당해도 짧은 수명으로 인해 접근을 최대한 제한한다. 요약하자면, refresh 토큰만 탈취당하지 않으면 어느정도 보안을 유지할 수 있다는 뜻이다.

profile
풀스택개발자가되고싶습니다:)

0개의 댓글