Cookie와 Session

Rosevillage·2023년 3월 7일
0

최근들어 여러 사이트들에서 쿠키관련 동의를 얻고 있기에 쿠키란 이름은 우리에게 익숙하다. 이 쿠키가 하는 역할은 간단한데, 클라이언트에 대한 몇가지 정보와, 설정을 브라우저에 저장하고 있는 것이다.

필요성

그래서 쿠키가 왜 필요한가를 생각해 본다면 다음과 같은 클라이언트-서버 통신의 특징 하나와 일상 예시 하나를 떠올릴 수 있다.

  1. 응용계층의 http는 무상태성(stateless)를 지닌다.

  2. 평소 웹 서비스를 사용할 때 우리는 로그인을 한번만 진행하고 원하는 서비스를 이용한 후 용건이 끝나면 로그아웃을 한다.

1번과 2번 사이에 왠지모를 괴리감이 든다.

무상태성은 상태를 가지지 않는다는 의미이다. 즉 클라이언트와 서버가 서로 어떤 상태인지 알지 못한다는 말이된다.

  • 클라이언트는 서버가 존재하는지, 정상적으로 작동하는지를 모르고
    서버는 클라이언트가 로그인을 했는지 안했는지 모른다.

1번의 특징을 따르면 우리는 다음과 같이 웹 서비스를 사용하고 있어야 한다.

쇼핑몰 사이트 접속-로그인=>상품 클릭=>상세 페이지 접속-로그인=>찜하기 클릭=>장바구니 접속-로그인...

이런 1번과 2번 사이의 불가능한 상황을 가능한 상황으로 만들어 주는 것 중 하나가 쿠키다.

작동방식

클라이언트-서버 통신에 대한 쿠키의 개입을 다음과 같은 단계로 설명해 볼 수 있다.

  1. 최초 로그인 시 브라우저(클라이언트)가 서버로부터 로그인한 사용자를 특정할 정보를 가지는 쿠키를 다운로드
  2. 페이지 이동 혹은 서버로 요청 시에 브라우저가 쿠키를 http 헤더에 넣어 같이 전송
  3. 서버가 동봉된 쿠키를 통해 요청을 보낸 사용자 특정

쿠키를 생성할 때 서버는 자신이 주고받을 쿠키의 조건을 설정할 수 있다.
서버는 http 헤더의 Set-Cookie 속성에 조건을 설정하고, 해당 설정을 통해 특정 조건을 만족하는 쿠키만 주고 받는다.

나름 이해를 위해서 조건을 설정한다 라는 표현을 썼지만 사실상 쿠키의 속성 설정을 의미한다.

서버가 설정할 수 있는 조건은 다음과 같다.

  • domain : naver.com과 같이 특정 도메인만 쿠키를 주고받도록 설정할 수 있다.
  • path : 라우팅할 경로인 세부 경로로 '/user'와 같이 설정하면 그의 하위 경로까지 포함해 쿠키를 받는다. 기본값은 '/'이다.
  • expires/maxAge : 두 설정 모두 쿠키의 유효기간을 명시한다. 설정하지 않으면 쿠키는 브라우저가 랜더링 될때 사라진다.
    • expires : 클라이언트의 시간을 기준으로 지정된 시간, 날짜가 지나면 쿠키를 파괴한다.
    • maxAge : 설정된 ms 를 지나면 쿠키를 파괴한다.
  • secure : 프로토콜에 따라 쿠키를 주고받을지 결정하며, true면 https를 사용하는 경우만 허용한다.
  • httpOnly : 스크립트를 통해 쿠키에 접근할수 있는지를 결졍하며, true 면 js 등의 스크립트로 접근할 수 없게 된다.(document.cookie 불가능)
  • smaeSite : 교차 사이트에 대해 쿠키를 어떻게 주고 받을지를 결정한다.
    (동일 사이트: 동일 출처와는 다른 개념으로 간단하게 말해서 naver.com정도의 수준에서 같은지 다른지를 구분한다.포트, 프로토콜, 하위 도메인을 따지지 않으며, 접미사와 접미사 바로 앞을 기준으로 한다.)
    • Lax : 교차 사이트 요청이면 읽기 전용의 안전한 메서드만 허용한다,(GET)
    • Strict : 동일 사이트 요청만을 허용한다
    • None : 교차 사이트 요청을 조건부로 허용한다.(쿠키의 secure속성이 true인 경우)

이렇게 설정한 조건들은 서버에서 클라이언트로 전송할때 http 헤더의 Set-Cookie 속성에 담겨져 전달된다.
클라이언트의 요청에서는 Cookie 속성으로 이름이 바뀐다.
set-cookie는 다음과 같이 생겼다.

'Set-Cookie' : [
  'cookie=cookie-name', 
  'Secure=Secure; Secure',
  'HttpOnly=HttpOnly; HttpOnly',
  'Path=Path; Path=/cookie',
  'Doamin=Domain; Domain=anyDomain.com'
]

위의 설정들을 보자니 쿠키는 여러 보안을 통해 상당히 안전한 것 같지만, 사실을 탈취해 이용해 먹기 쉬운 축에 속하니 민감한 정보는 쿠키에 넣어 전달하면 안된다.

express를 예로 서버에 쿠키를 생성하고 설정해 보내는 방법은 다음과 같다.

// server index
const express = require('express');
const cookieParser = require('cookie-parser'); //쿠키 생성을 위해 불러오고
const app = express();

app.use(cookieParser()); // 쿠키 생성

app.listen(3000, () => console.log('Server is starting on port:3000'));

// 요청을 담당할 미들웨어

// 쿠키를 설정한 후 
const cookieOption = {
  domain: 'anyDomain',
  path: '/', // any path
  httpOnly: true,
  sameSite: 'none',
  secure: true
}

module.exports = (req, res) => {
  // ...
  res.cookie('cookieName',userInfo, cookieOption) // 쿠키이름, 사용자 정보, 쿠키 옵션을 인자로 전달한다.
}
// 쿠키를 조건에 따라 없애야 하는 상황에는 다음과 같이 작성한다.
res.status(205).clearCookie('cookieName', cookiesOption).send('logout')

Session

평소에 쿠키와 같이 언급되는 세션은 또 무엇일까 느낌상 무슨 연관이 되어 있어 보인다.

wikipedia에 찾아보니 다음과 같이 정의한다.

네트워크 분야에서 반영구적이고 상호작용적인 정보 교환을 전제하는 둘 이상의 통신 장치나 컴퓨터와 사용자 간의 대화나 송수신 연결상태를 의미하는 보안적인 다이얼로그(dialogue) 및 시간대를 가리킨다
https://ko.wikipedia.org/wiki/세션_(컴퓨터_과학)

뭔가 이해하기 힘들지만 정리해 보자면 다음과 같다.

  • 서버와 클라이언트의 송∙수신 연결이 지속되는 시간
  • 서버와 클라이언트의 송∙수신을 위한 논리적 연결

즉, 서버와 클라이언트가 연결된 후 해제되기 전까지의 상태를 세션이라는 하나의 단위로 나타낸 것이다.
여기서 더 간단하게 얘기하면 서버와 클라이언트가 연결되면 세션이라는 말이다.

특징

앞서 쿠키는 브라우저에 정보를 저장한다고 설명했다.
그러나 세션은 서버에 정보를 저장한다. 그럼 세션은 쿠키와 반대되는 개념인가 싶으면 또 아니다.
세션은 쿠키를 통해서 클라이언트가 인증된 사용자인지 확인한다.

작동 방식

위에서 설명한 쿠키 방식과 비슷하지만 서버는 세션저장소에 세선을 저장하고, 쿠키에 암호화 된 session id를 저장한다. 사용자 정보가 저장된 장소가 브라우저에서 서버의 세션 저장소로 옮겨진 것과 같다.

  1. 클라이언트가 로그인에 성공하면 서버는 세션을 저장소에 저장(일반적으로 session store혹은 in-memory)
  2. 서버는 session id를 생성해 암호화 상태로 쿠키에 저장(JSESSIONID)
  3. 클라이언트는 쿠키를 저장하고 요청이 생길때마다 쿠키를 함께 전송
  4. 서버가 session id를 확인해 인증된 클라이언트인지 확인하고 요청을 수행

session 또한 쿠키를 사용하기에 쿠키가 가지는 취약점을 동일하게 가진다.

express를 예로 서버에 세션을 생성하는 방법은 다음과 같다.(쿠키와 크게 다르지 않다.)

const express = require('express');
const session = require('express-session'); // 세션 생성을 위해 불러온다.
const app = express();

// express-session 라이브러리를 통해 쿠키와 세션을 설정한다.
app.use(
  session({
    secret: 'secretstring',
    resave: false,
    saveUninitialized: true,
    cookie: {
      domain: 'anyDomain',
      path: '/',
      httpOnly: true,
      sameSite: 'none',
      secure: true,
    },
  })
);

app.listen(3000, () => console.log('Server is starting on port:3000'));

// 요청을 담당할 미들웨어
module.exports = (req, res) => {
  //...
    req.session.sessionId=secretId
};
// session을 삭제할 때는 다음과 같이 작성할 수 있다.
req.session.destroy()

쿠키와 세션은 XXS을 통한 session id, cookie 탈취에 취약하다

XXS(Cross-site Scripting)은 웹 애플리케이션에서 주로 나타나며, 외부에서 악성 스크립트를 삽입하는 방식(게시판에 악성 스크립트를 포함하는 게시글을 작성)으로 이루어진다.

웹 애플리케이션에서 사용자의 입력값을 제대로 검사하지 않는 경우 나타나기 때문에 웹 애플리케이션을 제작할 때는 XXS 관련 보안도 신경써야 한다.

0개의 댓글