Cookies, Session, Token, Web Storage 정리

     

     

    [ Cookie ]

    클라이언트의 브라우저에 저장되는 작은 크기의 문자열 (4KB)

     

     

     

    쿠키의 특징

    1. 도메인에 따라 제한되기에 다른 도메인에서 해당 쿠키에 접근이 불가능하다.

    2. 만료기간이 있고 이는 설정 가능하다.

         = expires와 max-age로 설정이 가능하며 두 가지 모두 설정되어 있을 때는 expires는 무시된다.

    3. 인증뿐만 아니라 여러 데이터 전달도 가능하다.

          ex. 웹페이지에 대한 언어설정 데이터를 쿠키에 담으면 서버가 이를 받아 유저가 설정한 언어로 변경해 준다.

     

     

     

    쿠키의 종류

     

    만료 기간에 따른 분류

    • 영구쿠키 : 만료기간이 있으며 만료 기간이 끝난 후엔 삭제된다.
    • 세션쿠키 : 만료기간이 없고 브라우저 종료 시 삭제된다.

    소유자에 따른 분류 ( 직간접 방문의 차이 )

    • 퍼스트파티 쿠키 : 같은 도메인에서 만든 쿠키로 서브도메인의 경우도 포함한다.
    • 서드파티 쿠키 : 다른 도메인에서 만든 쿠키

                 퍼스트파티 쿠키 : 같은 도메인 tstory.kr   서브 도메인 m.tstory.kr  

                 서브파티 쿠키 : 다른 도메인 facebook.com

                  => 서드 파트는 tstory에서 페이스북 스크립트가 존재 시 생성된다.

                        또는 다른 도메인으로 요청을 해야 하는 경우 생성된다.

                        이를 통해 사람들이 어떤 사이트에 방문했는지 알 수 있어

                        주로 광고 목적으로 사용되는데 개인정보 악용 우려로

                        크롬은 서드파티 쿠키 지원 중단 계획을 발표하기도 했다.

    쿠키 동작방식 

    브라우저에서 서버에 처음 요청을 보내면 

    서버는 브라우저에게 응답을 보내면서 쿠키를 함께 보낸다.

    이후에 브라우저에서 새로이 요청을 보내면 서버에서 준 쿠키를 요청과 함께 보낸다.

     

     

     

    쿠키가 사용되는 곳 

    1. 비 로그인 장바구니 

    2. 로그인 유지

    3. 특정 창을 다시 보지 않는 기능

     

     

     

    로그인 시 사용되는 쿠키

    HTTP 프로트콜은 stateless이기에 요청이 끝나면 서버는 요청을 보낸 유저가 누구인지 잊게 된다.

    그러렇기에 요청마다 우리를 알려야 하는데

    클라이언트가 쿠키에 유저정보를 담아 서버에 전달해 준다면 서버는 이 유저를 알 수 있게 된다.

     

     

     

    쿠키의 문제점

    1. 쿠키에 유저의 정보를 담아 사용할 수 있으나

       쿠키는 탈취당하기 쉽기에 보안상의 문제를 발생시킨다.

    2. CSRF에 취약 - 물론 SameSite의 속성값을 strict로 설정하면 된다. ) 

    3. 4KB로 저장용량이 적고

        HTTP 요청 시 자동으로 모든 쿠키 데이터가 전송되어 불필요한 트래픽 증가에 대한 문제가 발생한다.

    => 이를 막고자 쿠키를 단독으로 사용하는 것보단 Session과 함께 사용한다.

     

     


     

     

    [Session]

    세션이란 웹 사이트에 이용되는 사용자 정보를 서버에 저장하는 방법이다.

    세션을 사용 시 쿠키에는 사용자 정보가 없고 세션 ID만 존재하기에 쿠키를 탈취당해도 안전한 편이다.

    그래도 공격의 위험이 있기에 HttpOnly, Secure옵션을 주어 쿠키에 저장한다.

     

     

     

    동작방식

    로그인을 예시로 동작방식을 알아보자

     

    처음에 유저가 id와 password를 서버에 보내 인증을 요청하면

    서버는 해당 id와 password가 일치하는지 판단 후

    일치할 경우에 세션 DB에 해당유저를 생성해 저장한다.

     

    이때 인증확인의 표시로 별도의 세션 ID가 서버로 주어지는데

    서버는 이를 받아 쿠키에 넣어 유저에게 전달한다.

    유저는 세션 ID가 담긴 쿠키를 쿠키보관소에 보관한다.

    다음에 유저는 서버에게 사용자 인증이 필요한 정보에 대한 요청을 보낼 땐 인가를 위해 세션 ID를 쿠키에 담아 보낸다.

    서버는 해당 쿠키의 정보로 세션 저장소를 조회에 로그인 시 보관한 세션 정보를 사용한다.

    유효하지 못한 세션이라면 401 에러를 반환한다.

     

     

    session의 문제점

    1. 이러한 과정은 유저(브라우저)에서 요청을 받을 때마다 일어나는데

        유저가 많을수록 DB리소스가 증가하고 처리 속도에 대한 비용이 발생한다.

     

    2. HTTP의 가장 큰 특성 중 하나인 stateless 한 특성을 위배하게 된다. 

        stateless 특성은 서버에서는 클라이언트의 상태를 저장하지 않아야 하지만

         세션 저장소라는 곳에서 클라이언트의 상태를 저장하게 되므로 stateful 한 상태가 된다.

     

    3. 1번을 해결 하기위해 서버를 분산하는 방법이 있으나 오히려 서버 분산 환경에서 성능이 떨어진다.

          - 서버 과부하를 줄이기 위해 서버를 여러 대 쓰면 세션을 쓰기 복잡해진다.

             특히 이런 환경에선 내가 이전에 인증한 서버와 현재 내가 요청을 보내는 서버가 달라질 수 있다.

             이렇게 되면 세션 정보가 없는 다른 서버에 접속할 때마다 계속 로그인해줘야 한다. 

          - 물론 이를 해결하기 위해 sticky session, session clustering과 같은 방안이 나왔지만

             이를 처리하는 별도의 비용이 발생한다.

    => 사람들은 이러한 문제점때문에 token을 사용하기도 한다.

     

     

     


     

     

     

     

    [ Token - JWT ]

    JWT 토큰 방식은 웹표준으로서

    두 개체에서 JSON 객체를 사용하여 가볍고 자가수용적인(self-contained) 방식으로 정보를 안정성 있게 전달한다.

    (자가수용적이라는 의미는 JWT 안에 인증에 필요한 모든 정보를 자체적으로 지니고 있다는 의미이다)

     

     

     

    토큰의 구조

    [ header.payload.signature ] 

     => 토큰 구조에 대한 자세한 내용은 아래 포스트를 읽어보는 걸 추천한다.

     

    Session(세션)과 Token(토큰)의 차이는?

    우선 HTTP의 프로토콜 상태에 알아보자. HTTP 는 stateless 한 특성 때문에 각 통신의 상태는 저장되지 않는다. 하지만 서비스에서는 어떤 유저가 기능을 사용하는지 특정할 수 있어야하는데 이를 위

    velog.io

     

     

     

    토큰의 종류

    1. Access Token 

         역할: 사용자가 인증되었음을 나타내며, 리소스 서버에 접근할 때 사용된다.

         만료 기간: 짧은 기간 동안만 유효하며, 주로 몇 분 또는 몇 시간으로 설정된다.

         저장 : 로컬 스토리지 또는 세션 스토리지에 저장한다.

    2. Refresh Token

          역할: Access Token을 갱신하기 위해 사용되며, 새로운 Access Token을 얻을 때 사용된다.

          유효 기간: 일반적으로 Access Token보다 긴 기간 동안 유효한다. 보통은 여러 일 또는 몇 달로 설정될 수 있다.

          저장 : 쿠키에 저장하고 보안 옵션들(HTTP Only, Secure Cookies)을 활성화한다. 

                    물론 Refresh Token은 서버에도 저장되있어야 한다. 

     

     

    HTTP Only Cookies 

    =클라이언트에서 자바스크립트로 쿠키를 조회할 수 있는데 

      해당 옵션을 활성화 하면 브라우저에서 쿠키에 접근할 수 없으므로 XSS와 같은 공격으로부터 안전하다. 

     

    Secure Cookies 

    = HTTP 프로토콜은 언제든지 패킷을 중간에 가로챌 수 있다. 

       그래서 보안개념을 추가한 HTTPS 프로토콜을 사용하여 데이터를 암호화해 통신한다. 

       문제는 HTTPS 로 전송되어야 할 정보가 휴먼에러로 인해 HTTP로 전송될 때 가 있다.

       그래서 HTTPS 프로토콜이 아닌 경우에는 쿠키를 전송하지 않도록 설정하는 옵션이다.

     

     

     

    동작방식

    1. 로그인 시

    사용자는 클라이언트에서 ID/PW를 통해 로그인을 요청한다. 

    유효한 ID/PW라면, Access token & Refresh token을 발급한다. 

    클라이언트는 전달받은 토큰들은 localStorage에 저장한다. 

    클라이언트는 헤더에 Access token을 담아 서버에 요청한다. 

    서버에서는 Access token을 검증하고, 응답을 클라이언트로 보낸다. 

    Access token이 유효하지 않다면 Refersh token으로 Access token을 재발급한 뒤, access token을 리턴해준다.

     

     

     

     

    2. Access token이 만료되었을 시

     

     

     

    Refresh Token만 탈취한다면?

    공격자는 탈취한 Refresh Token 으로 계속 Access Token을 생성해서 정상적인 사용자처럼 서버에 계속 요청할 수 있다.

    이를 대비해서 서버에서 추가 검증 로직으로 방어해야 한다.

     

    [ 로직 ]

    DB에 사용자와 Access Token, Refresh Token 들을 매핑하여 저장한다.

     

    정상적인 유저의 Access Token이 만료된 경우 Access Token과 Refresh Token을 서버로 보내서 새 Access Token을 요청한다.

    → 서버에서는 DB에 저장된 Access Token, Refresh Token쌍과 클라이언트에서 보낸 토큰 쌍들을 비교한다

    → 일치하면 새 Access Token토큰을 발급해 준다.

     

    공격자가 Refresh Toekn을 탈취한 경우 공격자가 탈취한 Refresh Token으로 새 Access Token 생성 요청

    → Access Token이 없이 요청하면 공격으로 간주 → 서버에서 Access Token , Refresh Token 폐기

     

     

     

    토큰의 문제점

    1. 거의 모든 요청에 토큰이 포함되므로 트래픽 크기에 영향을 미칠 수도 있다. 

    2. 토큰에 정보가 많아져 토큰의 크기가 커지면 네트워크에 부하를 줄 수 있다. 

    3. 페이로드는 암호화된 게 아니라 BASE64로 인코딩 된 것이므로, 

        중간에 토큰을 탈취하면 페이로드의 데이터를 모두 볼 수 있다. 

         => 따라서 토큰의 페이로드에는 중요 정보를 담아선 안된다.

    4. access token을 사용하는 기간은 stateless이지만 만료되었을 경우엔 stateless가 깨진다.

         => 보안문제로 refresh token을 도입하면 결국 이를 저장할 별도의 저장소가 필요하기 때문...

     

     

     


     

     

     

    [ 웹 스토리지 ]

     클라이언트에 데이터를 저장할 수 있도록 HTML5부터 새롭게 지원하는 저장소

     

     

     

    웹 스토리지의 특징

    1. 5MB의 저장 용량으로 쿠키의 부족한 저장 용량 문제를 해결한다.

    2. 서버에 요청을 보낼 때 Headers에 웹스토리지를 전송하지 않는다.

          => 쿠키의 CSRF나 트래픽 문제를 해결한다.

    3. key와 value의 형태로 데이터를 저장한다.

    4. 직렬화를 통해 개체 저장이 가능하다.

    5. 만료 기간 설정이 불가하다.

    6. 웹 스토리지 객체는 오리진( 오리진은 도메인, 프로토콜, 포트로 정의된다. )에 묶여있기에

        프로토콜과 서브 도메인이 다르면 데이터에 접근할 수 없다.

     

     

     

    스토리지 종류

     

    만료 기간에 따른 분류

    • 로컬 스토리지

                -  브라우저에 저장되어 브라우저나 OS를 재시작하더라도 데이터는 보존된다.

                -  오리진이 같은 경우 데이터는 모든 탭과 창에 공유된다.

                -  만료기간이 없기에 직접 삭제를 해야만 데이터가 삭제된다.

                - 사용자 설정이나 글 임시 저장 시 사용된다. 

     

    • 세션 스토리지

                - 현재 떠 있는 탭 내에서만 유지되기에 탭마다 다른 세션 스토리지가 생성된다.

                - 새로고침을 해도 데이터는 유지되나 탭 종료 시 데이터는 삭제된다.

     

     

     

    스토리지 사용 시 필요한 메서드

    localStorage.setItem(key,item);  // key-value 쌍으로 데이터 보관
    localStorage.getItem(key,item);  // key에 맞는 데이터 반환
    localStorage.removeItem(key);        // key에 맞는 데이터 삭제
    localStorage.clear();            // 모든 데이터 삭제
    localStorage.length();           // 데이터의 수 반환

     

     

     

    스토리지의 문제점

    1. HTML5를 지원하지 않는 브라우저에서는 사용할 수 없다.

    2. XSS에 대해 취약하다.

    3. 동기적으로 동작하기에 브라우저가 블로킹될 수 있다.

    4. 5MB보다 큰 데이터를 다룰 수 없다.

     -> indexedDB를 고려해봐야 한다.

     

     

     


     

     

     

    [ 참고문헌 ]

    https://jongminfire.dev/cookie-session-web-storage-local-storage-session-storage

    https://fierycoding.tistory.com/69

    https://ko.javascript.info/localstorage

    https://velog.io/@ddangle/Session%EC%84%B8%EC%85%98%EA%B3%BC-Token%ED%86%A0%ED%81%B0%EC%9D%98-%EC%B0%A8%EC%9D%B4%EB%8A%94

     

     

    댓글