ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 토큰, 세션, 쿠키 알고가자
    인증_인가 2023. 3. 14. 15:22

    들어가기전에

     토큰, 세션, 쿠키는 모두 사용자가 웹 서비스를 이용할 때, '나'라는 것을 증명하기 위해 식별하고 인증하기 위한 기술이다. 비슷하게 생긴 이 친구들을 더이상 헷갈리지 말고 깰끔하게 정리해보자.
     먼저, 들어가기 전에 이런 이야기를 해본다. 은행 창구에서 은행원과 마주 앉아 적금 신청을 하고 있는데, 신분증을 달라고 한다. 은행원은 나의 신원을 확인한 뒤, 적금 상품에 가입도 해주고 첫 거래가 필요하다고 하여 다른 계좌에서 이체도 해준다. 알아서 착착. 그런데, 적금 상품에 가입 해주는 한 번의 인증과 다른 계좌에서 이체를 해주는 한 번의 인증, 총 2번의 인증이 필요하거늘 한 번의 인증으로 모든 것이 통과됐다. 나는 생각한다. '당연하지. 나는 처음에 신분증을 보여줬고 은행원이 나를 계속 기억하는걸.'

    우리의 웹 서비스도 당연할까? 아닐걸..

    우리는 당연한 서비스를 웹 어플리케이션에서 구현하고자 한다.

    HTTP의 특성

     HTTP의 특성에 대해서 알아볼 필요가 있다. HTTP 프로토콜은 한 번의 요청-응답 사이클이 완료되면 연결을 종료하기 때문에 지속적으로 상태를 유지할 수가 없다. 이를 무상태(stateless) 라고 표현한다. 즉, HTTP는 바로 직전의 통신 조차 기억하지 못한다.
    '아... 난감하다.. 계속해서 신원 증명을 할 수 없는데..'
    이 난감한 문제를 '세션, 쿠키'와 '토큰'을 통해 해결한다.

     

    토큰(Token): JWT 토큰

     JWT는 유저를 인증하고 식별하기 위한 토큰 기반 인증이다. JWT의 구조는 Header, Payload, Signature로 이루어져있다.

    header는 알고리즘과 토큰 타입으로, 'alg'는 정보를 암호화할 해싱 알고리즘을, 'typ'은 토큰의 타입을 지정한다.

    payload는 토큰 데이터로서 실제로 토큰에 담을 정보들을 지니고 있다. 주로 클라이언트 고유 ID, 유효 기간 등이 포함된다.

    signature는 인코딩된 header와 payload를 더한 뒤,  Secret key로 암호화한다. header 및 payload는 단순 인코딩된 값이기 때문에 해커가 복호화하고 조작할 수 있지만, signature는 서버 측에서 관리하는 Secret key가 유출되지 않는 이상 복호화 할 수 없다.

    [출처] JWT 공식 홈페이지

    서비스 구조에 대입해보기

    실제로 JWT 관련 동작이 일어나는 곳

    [출처] 원티드 프론트엔드 챌린지 3월 - 우아한 형제들 신성환님 강의 자료

    토큰 인증과정

    1. 클라이언트 로그인 요청이 들어오면 서버는 검증 후 클라이언트 고유 ID 등의 정보를 'payload' 에 담는다.

    2. 서버는 해쉬 알고리즘으로 암호화하여 JWT를 발급한다.

    3. 클라이언트는 전달받은 JWT(토큰)을 로컬스토리지 또는 쿠키 등에 저장해두고, 서버에 요청할 때마다 토큰을 헤더 Authorization에 'Bear token'을 담는다.

    4. 서버는 토큰의 Signature를 비밀키로 복호화한 다음, 위변조 여부 및 유효 기간 등을 확인한다.

    5. 유효한 토큰이라면 요청에 응한다.

     

    =>  위 그림과 같이, 유저가 진입하자마자 저장된 토큰을 확인하는 로직을 통해서 바로 유효성 검증을 한다면 인증과정 4~5번에 해당한다.

     

    토큰의 장점

    1. Signautre를 생성하므로 데이터 위변조를 막을 수 있다. (단, 서버에서 관리하는 Secret key를 탈취당하지 않는 이상..)

    2. 서버는 세션과 달리 데이터베이스나 파일 등에 저장할 필요가 없이 메모리 상에서 정의된 비밀키를 이용해 비교하는 것만으로 인증을 처리하기 때문에 추가적인 I/O 작업이 없다. => 비용 (로드 밸런서 등으로 서버 분산을 할 필요가 적음)

    3. 서버 관리와 비용이 세션 방식보다 적다. => 비용

    4. JWT는 토큰에 대한 기본 정보와 전달할 정보 및 토큰 검증 서명 등 필요한 모든 정보를 자체적으로 지니고 있다.

    5. 토큰 기반으로 다른 로그인 시스템에 접근 및 권한 공유가 가능하다. (토큰 서버 활용)

    6. 토큰 기반으로 다른 로그인 시스템에 접근 및 권한 공유가 가능하다.

    7. OAuth의 경우 Facebook, Google 등 소셜 계정을 이용해 다른 웹 서비스에서도 로그인 할 수 있다.

    토큰의 단점

    1. JWT는 세션 ID 보다 인증 정보가 더 많이 길어 토큰의 길이가 길어져, 네트워크 부하가 심해질 수 있다. => 성능

    2. payload 자체는 암호화되지 않기 때문에 유저의 중요한 정보를 담을 수 없다.

    3. 토큰을 탈취당하면 대처하기 어렵다. 토큰은 한 번 발급되면 유효 기간이 만료될 때 까지 계속 사용이 가능하다. => 보안성

    4. 특정 사용자의 접속을 강제로 만료하기 어렵다. (쿠키 / 세션 기반 인증은 서버 단에서 쉽게 삭제할 수 있지만 토큰은 그게 안됨) => 보안성

    5. 프론트 엔드에서 세션 쿠키 방식보다 관리가 어려워진다. JWT를 서버에서 받아서 로컬 스토리지 등에 저장하고 관리하는 작업을 해야되기 때문에

    토큰의 이중관리

     토큰 방식의 가장 큰 단점이라고 한다면, 바로 보안성이 취약하다는 것이다. 이는 발급받은 Access Token(JWT 토큰)을 브라우저에 저장,관리하고 있기 때문이다.

     이를 해결하기 위해서 Access Token과 Refresh Token을 함께 사용하는 이중 관리를 많이 한다.

    Access Token은 보안성의 단점을 보완하기 위해 유효기간 짧게, 메모리(로컬)에 발급한다.

    Refresh Token은 HttpOnlyCookie로 발급한다. (*JS로 접근이 불가)

    CSRF 공격으로 Refresh Token이 탈취되어 재사용 시도하더라도 Access Token이 살아 있으므로 토큰을 무효화 할 수 있다.

     따라서, Access Token과 Refresh Token이라는 두 가지의 토큰을 이중으로 관리하여 보안성을 높일 수 있다.

    OAuth

    OAuth란? 허가된 다른 서비스를 통해 기존 서비스(Google 등)의 권한을 "위임"하는 것

    전체 동작 살펴보기

    1. OAuth 인증 요청

    2. OAuth 로그인용 링크 전달

    3. 인증 요청 & 타 서비스 정보 전달

    4. 타 서비스 전용 토큰 전달

    5. 타 서비스용 토큰과 동작 요청

    6. 받은 토큰과 시크릿 키를 이용해 동작 요청

    7. 전달된 토큰과 시크릿 키 확인 후 동작 승인

    8. 동작 수행 및 응답

    권한에 따라 OAuth 원본 서버의 유저 정보를 가져와 사용하거나 권한을 위임받은 동작을 할 수 있으며 인증 자체만을 사용할 수도 있다.

     

    세션(Session)

    세션과 세션 방식 로그인

    세션: 사용자의 로그인 이후 (로그아웃 혹은 로그인 만료)까지의 기간

    세션 방식 로그인: 사용자 로그인이 유효한 시간 동안 서버에 세션 아이디를 기록해 두고 인증에 사용하는 방식.

    토큰과 다르게 클라이언트의 인증 정보를 서버 측에 저장하는 방식이다.

    서버가 세션 아이디를 기록하는 법

     서론에서 이야기 했듯이, HTTP는 무상태를 유지한다고 했다. 서버에 세션 아이디를 기록해두면, 클라이언트에서는 동일 유저의 요청에 대해서 어떻게 인증 정보가 유효한지 판단할 수 있을까? 그렇다. 토큰이라는 인증 정보가 클라이언트의 로컬 스토리지 또는 쿠키에 저장되어 요청했던 것처럼, 클라이언트에서도 인증 정보를 저장하고 유지하고 있어야 한다. 이 역할을 바로 '쿠키'가 한다.

     서버는 클라이언트의 로그인 요청을 통해서 인증 정보 유효성을 확인하고 식별하면 '세션 ID' 를 헤더의 set-cookie에 key-value 값으로 넣어 전달한다.

    [출처] 원티드 프론트엔드 챌린지 3월 - 우아한 형제들 신성환님 강의 자료

     클라이언트는 웹 브라우저 쿠키에 저장하고, 매 요청마다 헤더에 쿠키 값을 서버에 전달한다.

    // fetch의 경우 header에 credentials: 'include' 값을 전달한다.
    
    const result = await fetch(`${BASE_URL}/auth`, {
        method: 'POST',
        headers: {
          "Content-type": "application/json",
          credentials: 'include',
        },
        body: JSON.stringify({username:..., password:...})
      }
    })

    세션 기반 인증의 장점

    1. 쿠키 헤더에 세션 ID만 실어 보내면 되므로 트래픽을 적게 사용한다.

        => JWT는 사용자 인증 정보와 토큰의 발급 시각, 만료 시각, 토큰의 ID 등 세션 ID에 비해 비대하다.

    2. 인증 정보를 서버에서 관리하기 때문에 보안성 측면에서 유리하다.

        => 토큰은 클라이언트가 모든 인증정보를 가지기 때문에 한 번 탈취되면, 해당 토큰이 만료되기 전까지 피해를 입는다. 또한, payload에 담긴 인증 정보는 암호화되지 않기 때문에 유저의 중요한 정보가 들어있으면 안된다.

    3. 각 사용자 마다 고유한 세션 ID가 발급되기 때문에, 요청이 들어올 때마다 서버에서 회원 정보를 확인할 필요가 없다.

    4. 프론트 엔드에서 인증이 쉬워진다. 쿠키를 브라우저에 직접 저장하는 등의 노력이 필요없기 때문이다..

     

    세션 기반 인증의 단점

    1. 인증 정보를 세션에서 저장, 관리하기 때문에 요청이 많아져 서버의 관리 + 비용이 대폭 증가한다.

     

    쿠키 (Cookie)

    ( 드디어...) 쿠키란..?

     HTTP 쿠키는 서버가 사용자의 웹 브라우저에 전송하는 작은 데이터 조각이다. 아까, 서버에서 세션 ID를 header의 set-cookie에 담아 쿠키를 클라이언트에 요청한다는 것을 배웠다. 이 때, 서버에서 브라우저에 쿠키를 저장한다는 것 역시 배웠다. (쿠키의 역할을 더 설명할 필요가 없넹...? ㅎㅎ)

     이후 클라이언트는 요청을 보낼 때마다 매번 저장된 쿠키를 요청 헤더의 Cookie에 담아 보낸다. 서버는 쿠키에 담긴 정보를 바탕으로 해당 요청의 클라이언트를 식별할 수 있다.

    [출처] 원티드 프론트엔드 챌린지 3월 - 우아한 형제들 신성환님 강의 자료

    쿠키의 장.단점

     웹 브라우저에 인증 정보를 저장하고 있다는 사실은 항상 상당한 위험을 갖는다. 자바스크립트 언어로 조작하고, 탈취할 수 있는 웹 브라우저라는 대문이 열려있기 때문이다. 그래서 쿠키는 서버에 인증 정보를 저장하고 관리하고 있는 '세션'과 함께 많이 쓰인다. 쿠키 단점에 대해서만 언급하겠다.

     

    1. 쿠키는 매 요청마다 헤더에 실려 서버로 전송된다. 쿠키에 저장된 정보가 많다면 그만큼 큰 오버헤드가 발생할 것이다.

       => 이런 이유로 일반적으로 쿠키의 데이터는 4kb로 제한되어 있다. 또 사이트당 쿠키의 갯수도 20개로 제한되어 있다고 한다.

    2. 보안에 취약하다. 요청 시 쿠키의 값을 헤더에 그대로 보내어 유출 및 조작당할 위험이 존재하기 때문이다.

     

     

    결론

     결국엔 모든 인증 방식은 100% 안전할 수 없다. 다만 토큰? 세션? 쿠키? 미래 기술? 여러 기술들이 있겠지만 단점을 최소화하고 보완할 수 있느냐가 서비스 인증 방식을 도입하는데 가장 중요한 포인트인 것 같다. 개발자들마다, 회사마다 특정 사용방식을 더 많이 사용한다고 하는데... 쩝.. 보안으로 인해서 확실히 알 수 있는 길은 많이 없다. 다만, 개인적으로는 토큰 방식을 가장 많이 사용하지 않을까 한다.

     이유는 비용 및 관리에서 토큰 방식이 더 유리하고 조금 더 취약한 보안점은 토큰의 이중관리, AWS Cognito(정확히 잘 모름...) 등으로 보완하면 더 유리하지 않을까 싶어서.

     

     

    [참고]

     

    원티드 프리온보딩 프론트엔드 챌린지 3월 강의 내용

     

    https://velog.io/@whitebear/%EC%BF%A0%ED%82%A4-%EC%84%B8%EC%85%98-%ED%86%A0%ED%81%B0JWT-%ED%99%95%EC%8B%A4%ED%9E%88-%EC%95%8C%EA%B3%A0-%EA%B0%80%EA%B8%B0

     

    쿠키, 세션, 토큰(JWT) 몰라도 괜찮겠어?

    깔끔하게 정리했으니 몇 분만 투자해서 이번 기회에 바로 알고 가기 😀

    velog.io

    https://hudi.blog/cookie-and-session/

     

    쿠키와 세션 (ft. HTTP의 비연결성과 비상태성)

    HTTP의 비연결성과 비상태성 HTTP는 요청과 응답을 한번 주고받으면 바로 연결을 끊어버리는 특성을 가지고 있다. 그리고 다음 요청을 하기 위해 다시 연결을 맺어야한다. 이를 HTTP의 비연결성(Conn

    hudi.blog

     

Designed by Tistory.