티스토리 뷰

🍪 Cookie

무상태성을 가진 HTTP에서 사용자의 상태를 브라우저에 저장할 수 있다.


쿠키를 정의하자면...

서버가 웹 브라우저에 정보를 저장하고 불러올 수 있는 수단
더보기

➰ 쇼핑몰 사이트를 여러 군데 돌아다니는 상황에서

마음에 드는 옷 여러개를 장바구니에 담아두었다.

여러 사이트를 돌아다니는데도 장바구니에 담아두었던 상품은 그대로 유지가 된다.

그런데 HTTP요청은 무상태성한데 다른 페이지로 이동해도 기존 장바구니는 유지가 된다.

❓ HTTP는 무상태성(stateless)인데 어떻게 정보가 유지될까?

➡︎ 쿠키 덕분!

 

🍪 Cookie란?

어떤 웹 사이트에 들어갔을 때, 서버가 일방적으로 클라이언트에 전달하는 작은 데이터
  • 해당 도메인에 대해 쿠키가 존재하면, 웹 브라우저는 도메인에게 http요청 시 쿠키를 함께 전달한다.

➡︎ 쿠키를 이용하는 것은 클라이언트에서 서버로 쿠키를 다시 전송하는 것도 포함된다.

  • 삭제하지 않으면 사라지지 않는 특성을 가진다.
    • 로그인 상태 유지, 사용자 선호, 테마 등
    • 로그인을 위한 인증 정보를 쿠키에 저장하기도 함

➡︎ 장시간 보존해야 하는 정보 저장에 적합하다.

 

📍 쿠키는 브라우저 설정 창에 노출이 되어 있는데 인증 정보를 저장하면 위험하지 않을까?

→ 암호화가 되어있어 쉽게 알아보기는 힘들다. 하지만 자바스크립트로 접근이 가능하기 때문에 위험하다.

 


🍪 Cookie 전달 방법

  1. 서버가 응답 헤더의 SetCookie프로퍼티
    • 쿠키의 이름, 값
    • 경로
    등의 옵션을 저장 후 클라이언트에게 보낸다.
  2. 클라이언트는 SetCookie에 저장된 정보를 확인한다.
  3. 클라이언트는 매 요청시 마다 쿠키의 이름과 값을 헤더에 Cookie라는 프로퍼티에 담아 서버에 보낸다.
  4. 서버가 쿠키를 저장하면 이후로는 해당 웹 사이트를 이용할 때 자동으로 쿠키가 함께 전송된다.
  5. 서버는 자동으로 전송되는 쿠키에 저장된 정보를 인식하여 자동 로그인, 장바구니 유지 등의 정보를 유지하게 된다.

🍪 Cookie 옵션

서버가 클라이언트에 특정한 데이터를 저장할 수 있다.

하지만 데이터를 저장한 이후 아무때나 데이터를 가져올 수 있는 것은 아니다.

데이터를 저장한 이후 특정 조건들이 만족되어야 다시 가져올 수 있다.

  • 조건들은 http헤더를 사용하여 쿠키 옵션으로 표현한다.
// 쿠키 옵션
'Set-Cookie':[
            'cookie=yummy', 
            'Secure=Secure; Secure',
            'HttpOnly=HttpOnly; HttpOnly',
            'Path=Path; Path=/cookie',
            'Doamin=Domain; Domain=codestates.com'
        ]

 

1. Domain

서버와 요청의 도메인이 일치하는 경우 쿠키 전송

쿠키옵션에서 도메인은 포트 및 서브 도메인 정보, 세부 경로를 포함하지 않는다.

  • 서브 도메인 : www같은 도메인 앞에 추가로 작성되는 부분

따라서 요청해야 할 URL이 http://www.localhost.com:3000/users/login 이라면 도메인은 localhost.com 이 된다.

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

 

2. Path

세부 경로로써 서버가 라우팅할 때 사용하는 경로를 의미

서버와 요청의 세부 경로가 일치하는 경우 쿠키 전송한다.

따로 명시하지 않으면 기본적으로 /로 설정됨

설정된 경로를 포함하는 하위 경로로 요청을 하더라도 쿠키를 서버에 전송할 수 있다.

  • Path가 /users로 설정되어 있고, 요청하는 세부 경로가 /users/codestates 인 경우라면 쿠키 전송이 가능
  • /posts/codestates로 전송되는 요청은 Path 옵션(/users )을 만족하지 못하기 때문에 서버로 쿠키를 전송할 수 없음

 

3. MaxAge or Expires

쿠키의 유효기간 설정

📍 MaxAge

쿠키가 유효한 시간을 초 단위로 설정하는 옵션

 

📍 Expires

언제까지 쿠키가 유효한지 지정

옵션의 값은 클라이언트의 시간을 기준으로 한다.

지정된 시간, 날짜를 초과하게 되면 쿠키는 자동으로 파괴됨

 

쿠키는 위 옵션의 여부에 따라 세션 쿠키영속성 쿠키로 나눠진다.

  • 세션 쿠키(Session Cookie)
    • MaxAge 또는 Expires 옵션이 없는 쿠키 
    • 브라우저가 실행 중일 때 사용할 수 있는 임시 쿠키로 브라우저를 종료하면 해당 쿠키는 삭제된다.

 

  • 영속성 쿠키(Persistent Cookie)
    • 브라우저의 종료 여부와 상관 없이 MaxAge 또는 Expires에 지정된 유효시간 만큼 사용 가능한 쿠키

🎈 PC방에서 로그아웃을 안하고 나온 경우,

서버에서 쿠키에 MaxAge 혹은 Expire옵션을 통해 유효 기간을 지정했다면 일정 시간 후 자동으로 쿠키가 소멸되기 때문에 브라우저에서 확인이 불가능 하다. → 탈취 방지

 

 

4. HttpOnly

스크립트의 쿠키 접근 가능 여부 결정

쿠키는 경우에 따라 자바스크립트(<script>태그)로 접근이 가능하다.  XSS 공격에 취약

  • 옵션을 명시하지 않는 경우에는 기본적으로 false로 지정됨

→ document.cookie를 이용해 자바스크립트로 쿠키에 접근할 수 있어 탈취될 위험이 있음

 

해당 옵션이 true로 설정된 경우, 자바스크립트로 쿠키에 접근이 불가하다.

➡︎ HttpOnly로 자바스크립트의 접근을 막을 수는 있지만, 민감한 정보나 개인 정보는 쿠키에 담지 않는 것이 좋다.

 

 

5. Secure

HTTPS 프로토콜에서만 쿠키 전송 여부 결정

Secure옵션이 true로 설정된 경우 HTTPS를 이용한 경우에만 쿠키를 전송할 수 있다.

  • 옵션이 없다면 프로토콜에 상관 없이 모두 쿠키를 전송

단, 도메인이 localhost인 경우에는 HTTPS가 아니어도 쿠키 전송이 가능하다.

→ 개발 단계에서 localhost를 사용하는 경우가 많기 때문

 

 

6. SameSite

CORS 요청의 경우 옵션 및 메소드에 따라 쿠키 전송 여부 결정

요청에 사용한 메소드와 해당 옵션의 조합 기준으로 서버의 쿠키 전송 여부를 결정한다.

  • Lax
    • CORS 요청이라면 GET 메소드에 대해서만 쿠키를 전송할 수 있다.
  • Strict
    • 가장 엄격한 옵션으로, CORS가 아닌 same-site인 경우에만 쿠키를 전송할 수 있다.
  • None
    • CORS에 대해 가장 관대한 옵션으로 항상 쿠키를 보내줄 수 있다.
    • 다만 쿠키 옵션 중 Secure옵션이 필요하다.

이때 same-site는 요청을 보낸 Origin과 서버의 도메인, 프로토콜, 포트가 같은 경우를 말한다. → 하나라도 다르면 CORS로 구분


🍪 Cookie를 이용한 상태 유지

쿠키에 민감한 정보를 담는 것은 위험하다.

쿠키의 특성을 이용하여 Stateless한 인터넷 연결을 Stateful하게 유지할 수 있다.

하지만 기본적으로 쿠키는 오랜 시간 동안 유지될 수 있고, HttpOnly옵션을 사용하지 않았다면 자바스크립트를 이용해 접근이 가능하다.

이런 인증 정보를 이용해 공격자가 유저인 척 서버에 요청을 보낸다면 서버는 의심없이 인증된 유저의 요청으로 취급하게 된다.

이 때 개인정보와 같은 민감한 정보를 공격자가 탈취한다면 2차 피해가 일어날 수 있다.

 


🔗 Session

사용자의 정보를 서버에 저장하고 쿠키를 이용하여 이를 검증한다.

서버와 클라이언트간의 연결이 활성화된 상태를 의미하며

데이터를 서버에 저장하고 쿠키에는 암호화된 ID만 부여한다.

 

🔗 세션기반 인증 (Session-based Authentication)

🧑‍💻 로그인

사용자는 웹 사이트에서 아이디 및 비밀번호를 이용해 로그인을 시도한다.

정확한 아이디와 비밀번호를 입력했다면, 서버는 인증(Authentication)에 성공했다고 판단한다.

더보기

➰ 인증이 된 후 다음번에 인증을 필요로 하는 작업( 장바구니에 물품 추가 등)을 요청하는 경우 또 로그인 과정을 거쳐야 할까?

Nope!

서버가 “해당 유저는 인증에 성공했음”을 알고 있다면, 유저가 매번 로그인할 필요가 없다.

📌 인증에 따라 리소스의 접근 권한이 달라진다.

  • 서버 : 사용자가 인증에 성공했음을 알고 있어야함 → 세션
더보기

📍 세션

사용자가 인증에 성공한 상태

서버는 일종의 저장소에 세션을 저장한다.

주로 in-memory, 또는 세션 스토어 (redis 등과 같은 트랜잭션이 빠른 DB)에 저장한다.
세션이 만들어지면, 각 세션을 구분할 수 있는 세션 아이디도 만들어진다.

( 보통 클라이언트에 세션 성공을 증명할 수단으로써 세션 아이디를 전달 )

 

  • 클라이언트 : 인증 성공을 증명할 수단을 갖고 있어야 함 → 쿠키
더보기

📍 쿠키

웹 사이트에서 로그인을 유지하기 위한 수단으로 쿠키를 사용

쿠키에는 서버에서 발급한 세션 아이디를 저장한다.

쿠키를 통해 유효한 세션 아이디가 서버에 전달되고 세션 스토어에 해당 세션이 존재한다면 서버는 해당 요청에 접근이 가능하다고 판단한다.

쿠키에 세션 아이디 정보가 없는 경우, 서버는 해당 요청이 인증되지 않았음을 알려준다.

 

🧑‍💻 로그아웃

세션 아이디가 담긴 쿠키는 클라이언트에 저장되어 있으며, 서버는 세션을 저장하고 있다.

서버는 세션 아이디로만 인증 여부를 판단한다.

더보기

⚠️ 주의 ⚠️

쿠키는 세션 아이디, 즉 인증 성공에 대한 증명을 갖고 있으므로, 탈취될 경우 서버는 해당 요청이 인증된 사용자의 요청이라고 판단한다.

→ 공공 PC에서 로그아웃 해야함

로그아웃을 하기 위해서는

  • 서버 : 세션 정보를 삭제해야 함
  • 클라이언트 : 쿠키를 갱신하거나 삭제해야 함
    • res.cookie로 쿠키의 값을 무효한 값으로 갱신
    • res.clearCookie로 쿠키를 삭제

🔗 Session 전달 방법

세션으로 유저를 저장하는 쇼핑몰에서 장바구니에 물건을 담으려는 경우

  1. 로그인 후에 장바구니에 상품을 넣도록 요청을 보냄
  2. 서버는 DB에 로그인 정보를 저장한 후 session_id를 반환받음
  3. 쿠키에 session_id를 담아 클라이언트에게 보냄
    • 🚨 쿠키는 보안이 취약하기 때문에 암호화된 session_id로 저장
  4. 다른 상품을 장바구니에 넣도록 요청을 보냄
    • session_id가 부여된 상태이므로 session_id로 서버에 요청을 보냄(신분증 같은 역할)
  5. 서버는 session_id를 확인하고 DB에 장바구니를 업데이트
  6. session_id가 유효하면 장바구니를 업데이트
  7. 클라이언트에게 장바구니가 업데이트 되었다는 응답을 보냄

🍪 Cookie 와 🔗 Session 비교

  설명 접속 상태 저장 경로 장점 단점
Cookie 쿠키는 그저 http의 stateless한 것을 보완해 주는 도구 클라이언트 서버의 부담을 덜어줌 쿠키 그 자체는 인증이 아님
Session 접속 상태를 서버가 가짐 (stateful) 접속 상태와 권한 부여를 위해 세션 아이디를 쿠키로 전송 서버 신뢰할 수 있는 유저인지 서버에서 추가로 확인 가능 하나의 서버에서만 접속 상태를 가지므로 분산에 불리

🔗 Session 단점

  • 사용자가 많아질 경우 저장하고 있어야 할 메모리가 커져 가용 메모리 크기가 줄어듬 → 서버의 성능이 안좋아짐
  • 기존의 쿠키를 완전히 대체한게 아니기 때문에 XSS 공격으로 인한 탈취 가능성이 있음

🔗 express-session

Node.js에 있는 세션을 대신 관리해주는 모듈

express-session은 세션을 위한 미들웨어로, express 서버에서 쉽게 세션을 위한 공간을 다룰 수 있도록 만들어준다.

const express = require('express');
const session = require('express-session');

const app = express();

app.use(
	// 세션의 옵션을 지정
  session({
		// secret옵션의 비밀키를 이용해 암호화 -> 세션id 생성
    secret: '@codestates',
    resave: false,
    saveUninitialized: true,
    cookie: {
      domain: 'localhost',
      path: '/',
      maxAge: 24 * 6 * 60 * 10000,
      sameSite: 'none',
      httpOnly: false,
      secure: true,
    },
  })
);
  • 쿠키로 전송된 세션i d는 이에 종속되는 고유한 세션 객체를 가지며 서버에 저장됨
    • 세션 객체는 유저 별로 독립적으로 생성된 객체이므로 각각 다른 데이터를 저장할 수 있음
    ➡︎ 클라이언트에 유저의 개인 정보를 담지 않고도 서버가 클라이언트의 세션i d를 이용해 유저의 인증여부를 판단할 수 있다.
  • 세션 객체는 req.session 으로 접근할 수 있다.
    • 이를 통해 세션에 임의의 데이터를 저장하거나 불러올 수 있음
    • 세션 객체에 값을 담거나 불러오는 법, 세션 파괴하는 법

GitHub - expressjs/session: Simple session middleware for Express

728x90

'코딩 > 코드스테이츠' 카테고리의 다른 글

[인증 / 보안] - OAuth  (0) 2023.03.09
[인증 / 보안] - Token  (0) 2023.03.08
[네트워크] - TCP/IP  (0) 2023.03.06
[사용자 친화 웹] - 접근성  (0) 2023.03.02
[사용자 친화 웹] - 웹 표준  (0) 2023.02.28