[WEB] Cookie & Session

Minyoung kim·2024년 11월 25일

WEB

목록 보기
1/6

1. 쿠키란?

  • 쿠키(Cookie)는 웹 서버가 클라이언트(브라우저)에 저장하는 작은 데이터 조각으로 key=value 형식의 문자열 데이터 묶음입니다.
  • 클라이언트-서버 간 상태 정보를 유지하기 위해 사용됩니다.
  • 브라우저는 서버에서 설정한 쿠키를 저장하고, 이후 동일한 서버로 요청할 때마다 쿠키를 함께 전송합니다.

즉, HTTP 프로토콜은 기본적으로 무상태성을 가지고 있기 때문에
서버와 클라이언트 간의 연결 유지를 구현하기 위해 서로를 인식할 수 있는 식별데이터가 필요했고, 그것이 쿠키 데이터 조각이라고 볼 수 있습니다.

Http?

HTTP 프로토콜의 기본 속성: Stateless

  • 서버로 가는 모든 요청은 독립적.
  • 각 요청은 이전에 보내진 요청과의 연결고리가 없다.
  • 서버는 요청에 대한 응답을 보내고 나면, 요청을 보낸 사용자를 기억하지 않는다.

HTTP 프로토콜은 Stateless해서 확장성이 좋다!
언뜻 생각해보면, 이전 요청을 기억하지 않는다는게 안좋게 느껴질 수 있다.

하지만, Stateless하다는 것은 서버가 클라이언트의 상태를 유지할 필요가 없다는 것을 뜻한다.

상태를 유지하거나 관리한다는 것은, 클라이언트의 상태를 데이터베이스에 저장하고 때에 따라 업데이트하고, 삭제하기도 해야 한다는 뜻이다.

2. 쿠키의 주요 특징

  • 저장 위치: 클라이언트(브라우저).
  • 전송 방식: HTTP 요청 헤더(Cookie)와 응답 헤더(Set-Cookie)를 통해 서버와 주고받음.
  • 수명:
    • 세션 쿠키: 브라우저를 닫으면 삭제.
    • 영구 쿠키: 만료 시간을 설정하면 브라우저를 닫아도 유지됨.
  • 보안:
    • 클라이언트에 저장되므로 조작 가능성이 있음(HTTPS, HttpOnly로 보안 강화 가능).
  • 용량 제한:
    • 하나의 쿠키 크기는 최대 4KB.
    • 도메인당 최대 20~50개(브라우저에 따라 다름).

3. 쿠키의 동작 방식

3.1 데이터 흐름

  1. 클라이언트가 서버에 요청.
  2. 서버가 응답 헤더에 Set-Cookie를 추가하여 쿠키 전달.
  3. 클라이언트는 쿠키를 저장.
  4. 이후 요청 시 브라우저가 저장된 쿠키를 HTTP 요청 헤더에 추가.
sequenceDiagram
    participant Client as 클라이언트 (브라우저)
    participant Server as 서버
    Client->>Server: HTTP 요청 (로그인)
    Server-->>Client: HTTP 응답 + Set-Cookie (sessionId=abc123)
    Client->>Server: HTTP 요청 + Cookie (sessionId=abc123)
    Server-->>Client: 사용자 상태 확인 및 응답

4. 쿠키 설정

4.1 쿠키 설정 헤더

Set-Cookie: sessionId=abc123; Max-Age=3600; Path=/; HttpOnly; Secure
  • sessionId=abc123: 쿠키 이름과 값.
  • Max-Age=3600: 쿠키의 수명(초 단위).
  • Path=/: 쿠키가 적용될 경로.
  • HttpOnly: JavaScript로 접근 불가, XSS 공격 방지.
  • Secure: HTTPS 연결에서만 전송.
  • 클라이언트가 서버에 요청할 때 쿠키를 함께 전송.
Cookie: sessionId=abc123

4.2 Spring MVC에서 쿠키 설정

쿠키 생성

@GetMapping("/set-cookie")
public ResponseEntity<String> setCookie(HttpServletResponse response) {
    Cookie cookie = new Cookie("username", "홍길동");
    cookie.setMaxAge(7 * 24 * 60 * 60); // 7일 유지
    cookie.setPath("/"); // 모든 경로에서 유효
    cookie.setHttpOnly(true); // JavaScript 접근 불가
    cookie.setSecure(true); // HTTPS에서만 전송
    response.addCookie(cookie);
    return ResponseEntity.ok("Cookie set!");
}

쿠키 읽기

@GetMapping("/get-cookie")
public ResponseEntity<String> getCookie(@CookieValue(value = "username", defaultValue = "Guest") String username) {
    return ResponseEntity.ok("Hello, " + username);
}

모든 쿠키 읽기

@GetMapping("/get-all-cookies")
public ResponseEntity<String> getAllCookies(HttpServletRequest request) {
    Cookie[] cookies = request.getCookies();
    if (cookies != null) {
        for (Cookie cookie : cookies) {
            System.out.println(cookie.getName() + " = " + cookie.getValue());
        }
    }
    return ResponseEntity.ok("Cookies printed in server logs.");
}

쿠키 삭제


쿠키는 클라이언트(브라우저)에 저장된 데이터이므로 삭제하려면 쿠키의 수명을 설정하거나, 서버에서 동일한 이름과 경로로 만료된 쿠키를 설정해야 합니다.

삭제 방법

  1. 만료 시간 설정:
    • Max-Age를 0으로 설정하면 브라우저는 즉시 쿠키를 삭제합니다.
    • Expires를 과거 시간으로 설정하면 삭제됩니다.
  2. 쿠키 경로와 도메인 일치:
    • 삭제하려는 쿠키와 동일한 경로와 도메인으로 설정해야 합니다.

4.2. Spring에서 쿠키 삭제하기

4.2.1 HttpServletResponse로 쿠키 삭제

  • 서버에서 클라이언트에게 만료된 쿠키를 보내도록 설정.
@GetMapping("/delete-cookie")
public ResponseEntity<String> deleteCookie(HttpServletResponse response) {
    Cookie cookie = new Cookie("username", null); // 값은 null로 설정
    cookie.setMaxAge(0); // 즉시 만료
    cookie.setPath("/"); // 경로 일치
    response.addCookie(cookie);
    return ResponseEntity.ok("Cookie deleted");
}

동작 원리

  • 동일한 이름, 경로, 도메인의 쿠키가 브라우저에서 만료되어 삭제됩니다.

4.2.2 HttpServletRequest로 쿠키 확인 후 삭제

  • 요청에서 특정 쿠키를 검색한 후 삭제 쿠키를 생성합니다.
@GetMapping("/delete-specific-cookie")
public ResponseEntity<String> deleteSpecificCookie(HttpServletRequest request, HttpServletResponse response) {
    Cookie[] cookies = request.getCookies();
    if (cookies != null) {
        for (Cookie cookie : cookies) {
            if ("username".equals(cookie.getName())) {
                Cookie deleteCookie = new Cookie("username", null);
                deleteCookie.setMaxAge(0); // 즉시 만료
                deleteCookie.setPath("/");
                response.addCookie(deleteCookie);
            }
        }
    }
    return ResponseEntity.ok("Specific cookie deleted");
}

쿠키 삭제 시 주의 사항

  1. 경로(Path)와 도메인(Domain):
    • 삭제하려는 쿠키와 동일한 경로와 도메인으로 설정해야 브라우저에서 삭제됩니다.
  2. 보안 속성:
    • HttpOnly, Secure 속성이 설정된 쿠키는 서버에서만 삭제 가능하며, JavaScript로 삭제할 수 없습니다.
  3. 쿠키 존재 여부 확인:
    • 삭제하려는 쿠키가 존재하지 않을 경우에도 서버가 만료된 쿠키를 전송하면 브라우저에서 처리됩니다.

  • 쿠키를 삭제하려면:
    1. Max-Age=0 또는 Expires를 과거로 설정.
    2. 동일한 이름, 경로, 도메인으로 설정.
  • 보안 쿠키 삭제:
    • HttpOnly, Secure 속성이 설정된 쿠키는 서버에서만 삭제 가능.
  • 모든 쿠키 삭제:
    • 서버는 모든 쿠키 이름을 확인 후 개별적으로 삭제해야 함.

5. 쿠키의 사용 사례

  1. 로그인 상태 유지: 세션 ID를 쿠키에 저장.
  2. 사용자 환경 설정: 테마, 언어, 글꼴 크기 등.
  3. 광고 추적: 사용자 방문 기록 저장.
  4. 장바구니: 장바구니 데이터 임시 저장.

6. 쿠키의 보안 문제와 해결

6.1 보안 문제

  1. 가로채기:
    • HTTP를 사용하면 쿠키가 평문으로 전송되어 도청 가능.
  2. 조작 가능성:
    • 클라이언트가 쿠키 값을 임의로 변경 가능.
  3. XSS 공격:
    • 악성 스크립트가 쿠키 값을 읽을 수 있음.

6.2 보안 강화 방법

  1. HTTPS 사용:
    • HTTPS를 통해 쿠키 전송 시 데이터를 암호화.
  2. HttpOnly 설정:
    • JavaScript로 쿠키 접근을 차단.
      -> 클라이언트가 쿠키 값을 변경하는 것을 막음.
  3. Secure 설정:
    • HTTPS 연결에서만 쿠키를 전송.
  4. SameSite 설정:
    • 크로스 사이트 요청 위조(CSRF) 방지.
    • 값:
      • Strict: 쿠키는 동일한 사이트에서만 전송.
      • Lax: 대부분의 크로스 사이트 요청에서 쿠키가 전송되지 않음.
      • None: 크로스 사이트 요청에서도 쿠키 전송(단, Secure 필요).
Cookie cookie = new Cookie("sessionId", "abc123");
cookie.setHttpOnly(true);
cookie.setSecure(true);
cookie.setPath("/");
cookie.setMaxAge(3600); // 1시간
response.addCookie(cookie);

7. 쿠키의 단점

  1. 크기 제한: 4KB 제한으로 인해 대규모 데이터를 저장할 수 없음.
  2. 클라이언트 의존성: 쿠키가 손상되거나 삭제될 가능성.
  3. 보안 취약성: 잘못 설정된 쿠키는 보안 문제를 초래.

8. 요약: 쿠키의 장단점

장점단점
클라이언트 상태 정보를 쉽게 저장하고 관리 가능용량 제한(4KB)
서버 부하 감소 (상태 정보를 서버에 저장하지 않음)클라이언트에서 조작 가능 (보안 문제 발생 가능)
수명 설정 가능 (짧거나 긴 시간 동안 유지 가능)HTTP를 통해 전송되므로 도청 위험 (HTTPS 필요)
브라우저 간 호환성 높음쿠키의 잘못된 설정으로 보안 문제가 발생할 가능성 있음

Session?

세션은 비밀번호, 카드번호 등의 중요한 정보는 서버측에서 관리하는 방식입니다. 쿠키만 사용해서 서버와 클라이언트 간 연결을 유지하게 될 경우, 중요한 정보들을 모두 쿠키를 통해 브라우저에 저장하고 있게 됩니다. 따라서 보안적으로 매우 취약하다는 단점을 가지고 있습니다.

이것을 보완해줄 수 있는 것이 session입니다.
중요한 유저의 정보(비밀번호…)는 모두 서버에 저장되어 있고, 클라이언트는 오직 세션 ID만 가지고 있습니다.
session id 자체는 정보를 담고 있지 않기 때문에 외부에서 이를 참조하는 것 만으로는 문제가 되지 않지만, session id를 가로채서 사용자인 척 서버에 요청을 보내는 경우 문제가 생길 수 있습니다.

⭐️ 즉 정리하자면,

클라이언트는 session Id를 쿠키를 통해서 전달받고 저장하며,

브라우저에 세션Id를 저장해둔 클라이언트는 다음 요청때마다
헤더의 cookie에 세션Id를 담아서 전송합니다.

서버는 클라이언트가 보낸 요청의 쿠키에 담긴 세션Id와,
세션 스토리지에 담긴 세션Id를 대조해 인증상태를 판단하는 것입니다.
따라서 세션과 쿠키는 별개의 개념이 아니며, 세션은 쿠키를 기반으로 동작하게 됩니다.

session을 사용할 때의 간단한 flow입니다.

세션 방식을 사용하게 되면, 클라이언트가 로그인에 성공하면 서버는 session id를 생성해 클라이언트 측으로 쿠키를 통해 전송하게 됩니다. 이 경우 cookie는 서버와 클라이언트 간의 매개체이자, 정보를 전달하는 수단이 되게 됩니다.

이후 클라이언트가 서버로부터 요청을 전송할 때, 쿠키를 통해 저장해놓은 session id를 전송하고, 서버에서는 이 session id가 서버 측에 존재하고, 유효하다면 사용자를 식별해 정보를 제공하게 됩니다.

session 특징

특징설명
저장 위치서버 메모리 또는 외부 저장소(Redis, DB 등).
데이터 수명세션 타임아웃(일정 시간 동안 활동이 없으면 만료).
식별 방식클라이언트는 세션 ID를 쿠키 또는 URL 파라미터를 통해 서버에 전달.
보안세션 데이터는 서버에서 관리되므로 클라이언트는 데이터에 직접 접근할 수 없음.
사용 사례로그인 상태 유지, 장바구니, 폼 데이터 유지 등.

세션의 속성

java의 httpSession class

메서드설명
setAttribute(String, Object)세션에 데이터를 저장.
getAttribute(String)세션에서 데이터를 가져옴.
removeAttribute(String)세션에서 특정 데이터를 제거.
invalidate()세션 무효화(모든 데이터 삭제 및 세션 종료).
getId()현재 세션의 고유 ID를 반환.
getCreationTime()세션 생성 시간을 반환.
getLastAccessedTime()마지막으로 세션에 접근한 시간을 반환.

세션 설정 방식

Spring Boot 기본 설정

  • application.properties에서 세션 타임아웃을 설정할 수 있습니다.
server.servlet.session.timeout=30m # 30분

프로그램으로 설정

@Bean
public ServletContextInitializer initializer() {
    return servletContext -> {
        servletContext.setSessionTimeout(1800); // 30분
    };
}

세션 관리 전략

5.1 세션 스토리지

  1. 메모리 기반(Default):
    • 서버의 메모리에 세션 데이터를 저장.
    • 단점: 서버가 재시작되면 데이터 손실.
  2. 데이터베이스 기반:
    • 외부 DB에 세션 데이터를 저장.
    • 서버 재시작 시 데이터 유지 가능.
  3. Redis 기반:
    • Redis와 같은 인메모리 데이터베이스를 사용.
    • 고성능, 다중 서버 환경에서 유용.

1) 세션 스토리지

  1. 메모리 기반(Default):
    • 서버의 메모리에 세션 데이터를 저장.
    • 단점: 서버가 재시작되면 데이터 손실.
  2. 데이터베이스 기반:
    • 외부 DB에 세션 데이터를 저장.
    • 서버 재시작 시 데이터 유지 가능.
  3. Redis 기반:
    • Redis와 같은 인메모리 데이터베이스를 사용.
    • 고성능, 다중 서버 환경에서 유용.

2) 세션 고정 공격(Session Fixation) 방지

  • 세션 ID 재발급:
    • 로그인 성공 시 기존 세션 ID를 무효화하고 새 세션 ID를 발급.
@PostMapping("/login")
public ResponseEntity<String> login(HttpServletRequest request) {
    HttpSession oldSession = request.getSession(false);
    if (oldSession != null) {
        oldSession.invalidate(); // 기존 세션 무효화
    }
    HttpSession newSession = request.getSession(true); // 새 세션 생성
    newSession.setAttribute("user", "홍길동");

    return ResponseEntity.ok("Login successful!");
}

session 방식 장점

서버는 로그인된 유저의 모든 정보를 저장하기 때문에, 이 정보를 사용해 새로운 기능을 추가할 수 있습니다.

예를 들어 특정 유저를 로그아웃 시키고 싶을 때, 세션을 삭제해버릴 수 있습니다. (session id를 클라이언트가 전송해도 유효하지 않으므로 통과되지 않음.)
또한 세션에 로그인된 기기의 정보를 함께 저장하면, 로그인된 디바이스를 모두 보여줘서 원하지 않는 디바이스를 로그아웃 시킬 수 있고, 넷플릭스처럼 계정의 공유 숫자를 제한할 수 있습니다.

즉, 서버 측에서 로그인된 유저의 정보와 권환을 제한하고 control 할 수 있습니다.

session 방식의 한계점

  • 서버는 로그인한 유저들의 모든 세션 ID를 데이터베이스에 저장해야 하기 때문에, 데이터베이스를 사고, 유지해야 합니다. 유저가 많아질 수록, 데이터베이스도 커져야 할 것입니다.
  • 요청이 들어올 때마다, 서버는 쿠키를 받아서 세션 ID를 확인하고, 세션 ID에 해당하는 유저를 데이터베이스에서 조회해야 다음 작업을 수행할 수 있기 때문에, 많은 리소스가 들어갑니다.
  • CSRF 공격 등의 session 하이재킹 공격에 취약합니다.

CSRF 공격이란?

CSRF란, Cross Site Request Forgery의 약자로, 한글 뜻으로는 사이트간 요청 위조를 뜻합니다.CSRF는 웹 보안 취약점의 일종이며, 사용자가 자신의 의지와는 무관하게 공격자가 의도한 행위(데이터 수정, 삭제, 등록 등) 을 특정 웹사이트에 요청하게 하는 공격입니다.

  1. 사용자는 보안이 취약한 서버에 로그인합니다.
  2. 서버에 저장된 세션 정보를 사용할 수 있는 session ID가 사용자의 브라우저 쿠키에 저장됩니다.
  3. 공격자는 사용자가 악성 스크립트 페이지를 누르도록 유도합니다.악성 스크립트 페이지를 누르도록 유도하는 방식은 아래와 같은 방식들이 있습니다.
    • 게시판이 있는 웹사이트에 악성 스크립트를 게시글로 작성하여 사용자들이 게시글을 클릭하도록 유도- 메일 등으로 악성 스크립트를 직접 전달하거나, 악성 스크립트가 적힌 페이지 링크를 전달
  4. 사용자가 악성 스크립트가 작성된 페이지 접근시 웹 브라우저에 의해 쿠키에 저장된 session ID와 함께 서버로 요청됩니다.
  5. 서버는 쿠키에 담긴 session ID를 통해 해당 요청이 인증된 사용자로부터 온 것으로 판단하고 처리합니다.

조건 : 요청에 필요한 파라미터들을 공격자가 알고 있어야 요청을 조작할 수 있으며, 요청에 필요한 예측 불가능한 파라미터가 없음.

즉, session id를 쿠키를 통해 브라우저에 저장함으로써 발생할 수 있는 문제점입니다.

이러한 공격은 아래오 같은 방법으로 방지할 수 있습니다.

  1. Referer check (리퍼러 체크)
  • 들어온 요청의 refere를 체크해, 요청을 보낸 host와 session의 host가 동일한지 확인.
  1. csrf token
    사용자가 요청한 페이지에 사용자의 세션과 연결된 랜덤값을 생성해서 넣어두고, 나중에 오는 요청에 해당 랜덤값이 원본과 일치하는지 검사해서 일치할 경우에만 요청에 대한 처리를 수행하도록 하는 방법.
    공격자는 csrf token을 요청에 필요한 파라미터로 알고 있지 않기 때문에, 공격을 어느정도 방지할 수 있음.

보안 강화 전략을 정리하면 다음과 같습니다.

  1. HTTPS 사용:
    • 세션 ID를 암호화된 통신으로만 전송.
  2. 세션 타임아웃 설정:
    • 비활동 시간이 일정 시간 초과하면 자동으로 세션 만료.
  3. 세션 ID 재발급:
    • 로그인 또는 중요한 작업 이후 세션 ID를 변경.
  4. CSRF 방지:
    • 세션과 연동된 CSRF 토큰을 사용.
  5. 서버 간 세션 동기화:
    • 다중 서버 환경에서는 Redis 등을 활용해 세션 동기화.

1.3 쿠키와 세션의 특징

항목쿠키(Cookie)세션(Session)
저장 위치클라이언트(브라우저)서버
데이터 용량4KB 제한서버 메모리에 의존
보안클라이언트에서 쉽게 조작 가능 (HTTPS로 전송 암호화 필요)클라이언트에서 직접 접근 불가, 서버가 관리
속도빠름 (클라이언트에 저장)상대적으로 느림 (매 요청마다 서버 확인 필요)
유지 시간만료 시간 설정 가능, 브라우저 종료 시 삭제 가능세션 타임아웃 설정 가능
사용 사례사용자의 기본 설정 저장, 로그인 상태 유지사용자 인증, 장바구니 데이터, 민감한 데이터 처리

0개의 댓글