TIL 60 | 쿠키, 세션, 토큰

CHAEIN·2021년 9월 6일
0

Network

목록 보기
8/8

쿠키(Cookie)

쿠키(cookie)는 http통신의 무상태성을 보완하는 도구로 클라이언트의 상태 정보를 저장해 로컬 브라우저에 일시적으로 저장한다.

http 통신은 비연결성/무상태성을 특징으로 각각의 요청과 응답은 독립적이고 하나의 요청과 응답이 전송되면 서버와 클라이언트의 연결도 종료된다. 이로 인해 매 요청을 보낼 때마다 클라이언트는 서버가 자신을 식별할 수 있도록 계속해서 인증(ex.로그인) 을 해야하는 문제가 발생한다.

이를 해결하기 위해 서버는 클라이언트의 요청에 대한 응답을 보낼 때 응답 헤더에 클라이언트의 정보를 담은 쿠키를 심어 브라우저에 저장한다. 이후 클라이언트의 요청이 있을 때 브라우저에 저장된 쿠키는 요청 헤더에 담겨 서버로 전달되고 서버는 쿠키 내용을 바탕으로 클라이언트의 상태를 식별한다.

클라이언트의 쿠키 정보를 항상, 모든 상황에서 가져와 사용할 수 있는 것은 아니다. 클라이언트 쿠키 데이터를 사용하기 위해선 서버에서 쿠키를 생성할 때 설정한 조건에 만족해야 한다. 이러한 조건들을 쿠키 옵션이라고 한다.

cookie: {
      domain: "localhost",
      path: "/",
      maxAge: 24 * 6 * 60 * 10000,
      sameSite: "none",
      httpOnly: true,
      secure: true,
    }

쿠키 옵션

1. Domain
도메인이은 www.google.com과 같이 서버에 접속할 수 있는 이름을 의미한다. 쿠키 옵션에서 도메인은 포트 및 서브 도메인 정보, 세부 경로를 포함하지 않는다. 따라서 요청해야 할 URL이 http://www.localhost.com:3000/users/login 이라 하면 여기에서 Domain은 localhost.com이다.

만약 쿠키 옵션에서 도메인 정보가 존재한다면 클라이언트에서는 쿠키의 도메인 옵션과 서버의 도메인이 일치해야만 쿠키를 전송할 수 있다.

2. Path
세부 경로는 서버가 라우팅할 때 사용하는 경로를 의미한다. 만약 요청해야 하는 URL이 http://www.localhost.com:3000/users/login 인 경우라면 여기에서 Path, 세부 경로는 /users/login이다.

명시하지 않으면 기본으로 / 으로 설정된다. Path 옵션은 설정된 path를 전부 만족하는 경우 요청하는 Path가 추가로 더 존재하더라도 쿠키를 서버에 전송할 수 있다. 즉 Path가 /users로 설정되어 있고, 요청하는 세부 경로가 /users/login 인 경우라면 쿠키 전송이 가능하다.

3. MaxAge or Expires
MaxAge는 앞으로 몇 초 동안 쿠키가 유효한지 설정하는 옵션이다. Expires 은 MaxAge와 비슷하지만 언제까지 유효한지 특정 Date를 지정한다. 이때 클라이언트의 시간을 기준으로 한다. 이후 지정된 시간, 날짜를 초과하게 되면 쿠키는 자동으로 파괴된다.

하지만 두 옵션이 모두 지정되지 않는 경우에는 브라우저의 탭을 닫을 때 쿠키가 제거된다.

4. Secure
쿠키를 전송해야 할 때 사용하는 프로토콜에 따른 쿠키 전송 여부를 결정해야한다. 만약 해당 옵션이 true로 설정된 경우, 'HTTPS' 프로토콜을 이용하여 통신하는 경우에만 쿠키를 전송할 수 있다.

5. HttpOnly
자바스크립트에서 브라우저의 쿠키에 접근 여부를 결정한다. 만약 해당 옵션이 true로 설정된 경우, 자바스크립트에서는 쿠키에 접근이 불가하다.

명시되지 않는 경우 기본으로 false가 지정된다. 만약 이 옵션이 false인 경우 자바스크립트에서 쿠키에 접근이 가능하므로 'XSS' 공격에 취약해진다.

6. SameSite
Cross-Origin 요청을 받은 경우 요청에서 사용한 메소드와 해당 옵션의 조합으로 서버의 쿠키 전송 여부를 결정하게 된다. 사용 가능한 옵션은 다음과 같습니다.

  • Lax :Cross-Origin 요청이면 'GET' 메소드에 대해서만 쿠키를 전송할 수 있다.

  • Strict : Cross-Origin이 아닌 same-site 인 경우에만 쿠키를 전송 할 수 있다. 'same-site'는 요청을 보낸 Origin과 서버의 도메인이 같은 경우를 뜻한다.

  • None: 항상 쿠키를 보내줄 수 있다. 다만 쿠키 옵션 중 Secure 옵션이 필요하다.

이러한 옵션들을 지정한 다음 서버에서 클라이언트로 쿠키를 처음 전송하게 된다면 헤더에 Set-Cookie라는 프로퍼티에 쿠키를 담아 쿠키를 전송하게 된다.

이후 클라이언트 혹은 서버에서 쿠키를 전송해야 한다면 클라이언트는 헤더에 Cookie라는 프로퍼티에 쿠키를 담아 서버에 쿠키를 전송한다.

쿠키의 장점

  • http 무상태성을 보완하고 stateful한 통신을 지원한다.
  • 서버의 저장 공간을 줄일 수 있다.

쿠키의 단점

  • 보안에 취약하다.
    : 요청/응답 시 쿠키 값이 그대로 전달되기 때문에 중간자 공격에 취약하며 자바스크립트로 직접 접근도 가능해 쿠키에 민감한 정보를 담는 것은 위험하다.

  • 작은 허용 용량
    : 사이트 당 20개, 모두 합쳐 300개가 최대. 각 쿠키는 4Byte를 넘을 수 없으며 한번에 하나의 정보만 저장가능하다.

  • 웹 브라우저마다 지원 형태가 다르고 웹 브라우저를 변경할 경우 다른 웹브라우저에서 저장한 쿠키값을 사용할 수 없다.

  • 사용자가 보안상의 문제로 거부할 경우 사용할 수 없다.

  • 네트워크 부하가 커질 수 있다.
    : 쿠키의 크기가 클 경우 네트워크 부하가 커진다.

세션(Session)

세션(session)은 네트워크 환경에서 사용자와 서버 간 통신을 위한 논리적 연결 또는 연결된 상태를 말한다. 세션 정보는 보안 처리되어 쿠키(cookie) 와 서버에 동시에 저장되므로, 세션이 쿠키만 사용하는 것에 비해 보안상 더 안전하다.

HTTP Session id를 식별자로 구별하여 데이터를 사용자의 브라우저에 쿠키형태가 아닌 접속한 서버 DB에 정보를 저장한다. 클라이언트는 HTTP Session id를 쿠키로 메모리 저장된 형태로 가지고 있다.

세션 형성 절차

  • 클라이언트에서 http request가 오면 서버는 클라이언트의 쿠키에서 session-id를 확인한다.
  • 만약 session-id가 없으면 서버는 response 헤더에 "Set-Cookie"를 통해 새로 생성한 session-id를 전달한다.
  • 클라이언트는 response로 받은 session-id를 쿠키에 저장한다.
  • 만약 session-id가 있으면 서버는 해당 세션을 DB에서 찾아 클라이언트를 식별하고 클라이언트 상태 정보에 적절한 응답을 보낸다.

세션의 장점

  • 서버에 저장하기 때문에 핸들링 하기 수월하다.
  • 요청과 응답으로 세션 ID만 이동하기 때문에 네트워크 부하가 적다.
  • 세션 ID를 암호화할 수 있어 쿠키에 비해 보안에 뛰어나다.

세션의 단점

  • 서버 메모리를 많이 차지하고 서버의 성능을 저하시킨다.
  • 로드밸런싱과 같이 여러대의 서버로 분산 처리하는 서비스의 경우 세션 id를 모든 서버에 공유하고 sync를 맞춰야하는 문제가 발생한다.
  • 위와 비슷한 맥락으로 서버의 확장 가능성이 높은 서비스의 경우 세션 사용이 어렵다.

토큰 기반 인증(token)

유저의 정보를 암호화해 쿠키에 저장하고 서버나 세션에는 따로 저장하지 않는 인증 방식으로 세션의 단점을 보완한다. 대표적인 토큰 기반 인증 방식으로 JWT가 있다.

JWT : JSON 포맷으로 사용자에 대한 속성을 저장하는 웹토큰

JWT의 종류

  • Access token
    보호된 정보들(유저의 이메일, 연락처, 사진 등)에 접근할 수 있는 권한부여에 사용하는 토큰.
  • Refresh token
    Access token이 만료되었을 때 새 Access token을 발급받기 위해 사용되는 토큰.

쿠키는 브라우저에만 저장되기 때문에 만약 쿠키 정보가 탈취당하면 서버에서 해당 쿠키를 제제할 방법이 없지만 토큰의 경우 refresh token의 효력을 Access token의 재발급을 막아 제제가 가능해진다. 또한 세션과 같이 서버에 따로 저장하는 방식이 아니기 때문에 세션이 갖는 메모리 및 서버 성능 저하 문제를 보완하는 해결책이다. 그러나 Acess token이 탈취당할 시 해당 토큰이 기간만료로 자동으로 사라지기 전까지는 다른 방식들과 동일한 보안 문제를 가지고 있다는 점에서 완전하다고 볼 수는 없다.

JWT의 구조 (Header.Payload.Signature)

JWT는 . 으로 나누어진 세 부분으로 구성되어있다.

  • Header

Header는 어떤 종류의 토큰인지(지금의 경우엔 JWT), 어떤 알고리즘으로 sign(암호화) 할지에 대한 정보를 담고있다. JSON Web Token 이라는 이름에 걸맞게 JSON형태로 구성되어있다.

{
  "alg": "HS256",
  "typ": "JWT"
}

이 JSON 객체를 base64 방식으로 인코딩하면 JWT의 첫 번째 부분이 완성된다.

  • payload
    Payload에는 사용자 정보가 담겨 있다. 어떤 정보에 접근 가능한지에 대한 권한을 담을 수도 있고, 사용자의 유저 이름 등 필요한 데이터는 이곳에 담아 암호화한다. 물론 암호화(헤더에서 정의한)가 될 정보지만, 비밀번호와 같은 민감한 정보는 되도록 담지 않는 것이 좋다.
{
  "sub": "someInformation",
  "name": "phillip",
  "iat": 151623391
}

첫번째와 마찬가지로 base64방식으로 인코딩하면 두번째 부분이 완성된다.

  • Signature

base64로 인코딩된 첫번째, 그리고 두번째 부분이 완성 되었다면, 이 구간에선 원하는 비밀 키(암호화에 추가할 salt)를 사용하여 암호화한다. 이렇게 암호한 값은 디코딩이 가능하지만 서버에서 사용하고 있는 비밀키를 보유한게 아니라면 해독해내는데 엄청난 시간과 노력이 들어간다. Signature에는 이렇게 해싱된 값이 부여된다.

토큰기반 인증 절차

1) 클라이언트가 아이디/패스워드를 입력하고 서버에 로그인 요청을 보낸다.
2) 서버는 아이디/패스워드가 DB정보와 일치하는지 확인하고 사용자 정보를 바탕으로 Access token과 Refresh token을 생성한다.
3) 서버는 응답 헤더에 Access token과 Refresh token을 실어보내고 클라이언트는 해당 토큰을 저장한다. 저장하는 위치는 local storage, cookie, react의 state 등 다양하다.
4) 이후 클라이언트는 요청마다 Access token을 실어보내고 서버는 token을 디코딩해 사용자를 식별하여 요청을 처리하고 응답한다.

토큰기반 인증 절차의 장점

  • Statelessness & Scalability (무상태성 & 확장성)
    서버는 클라이언트에 대한 정보를 저장할 필요 없이 토큰이 해독이 되는지만 판단한다. 세션과 달리 로드발란싱 서버나 서버 확장성을 고려하는 서비스에 적합하다.

  • 안전하다
    암호화 한 토큰을 사용하고, 암호화 키를 노출 할 필요가 없기 때문에 안전하다.

  • 어디서나 생성 가능하다
    토큰 생성용 서버를 만들거나, 다른 회사에서 토큰관련 작업을 맡기는 것 등 다양한 활용이 가능하다.

  • 권한 부여에 용이하다
    토큰의 payload(내용물) 안에 어떤 정보에 접근 가능한지 정할 수 있습니다
    ex) 서비스의 사진과 연락처 사용권한만 부여

0개의 댓글