본문으로 건너뛰기

쿠키와 세션

쿠키와 세션 면접 질문 및 답변

Q1. 쿠키와 세션의 차이는 무엇인가요?

쿠키와 세션은 모두 HTTP의 비상태성을 보완하기 위해 사용됩니다. 하지만 둘은 명확한 차이가 있습니다.

  • 쿠키: 클라이언트 측에 저장되는 데이터
  • 세션: 서버 측에서 관리하는 데이터. 클라이언트가 세션을 요청하면 세션ID를 쿠키에 저장해 서버에서 해당 사용자를 식별할 수 있게 합니다.

Q2. 쿠키는 클라이언트 측에서 저장된다고 했는데, 정확히 어디에 저장되나요?

브라우저의 쿠키 저장소에 저장됩니다. 운영체제별로 브라우저의 로컬 파일 시스템에 저장되고, 브라우저가 이를 관리합니다.

Q3. HttpOnly 속성이 설정된 쿠키는 어떤 특징을 가지나요?

HttpOnly 속성이 설정된 쿠키는 자바스크립트에서 접근할 수 없습니다. 즉, document.cookie를 사용해서 쿠키를 읽거나 수정할 수 없고 오직 서버와의 HTTP 요청/응답을 통해서만 쿠키가 전달됩니다. 이는 XSS 공격을 방지하기 위해 사용됩니다.

Q4. Secure 속성은 무엇이며, 언제 사용하는 것이 좋을까요?

쿠키의 Secure 속성을 설정하면 HTTPS에서만 쿠키가 전송됩니다. HTTP 환경에서는 쿠키가 전송되지 않습니다. 이는 중간자 공격을 방지하기 위함입니다.

경고

하지만 Secure 속성만 설정했다고 해서 쿠키가 완전히 안전한 것은 아니다. 쿠키 값이 평문으로 저장되면 브라우저가 보관하는 동안에도 탈취될 가능성이 있다. 따라서 Secure 속성과 함께 쿠키 값을 암호화하는 것이 더욱 안전한 방법이다.

Q5. SameSite 속성은 무엇이며 어떤 역할을 하나요?

쿠키가 다른 사이트에서 자동으로 전송되는 것을 막으며, CSRF 공격을 방지하기 위해 쿠키의 전송 범위를 제한하는 역할을 합니다.

옵션

  • Strict: 완전히 차단, 같은 사이트에서 요청할 때만 쿠키를 전송
  • Lax: 안전한 요청(GET)만 허용
  • None: 모든 요청에 대해 쿠키를 허용 - Secure 속성과 함께 사용해야 함

추가 질문: 최근 브라우저들이 기본적으로 SameSite=Lax를 적용하도록 변경한 이유는 무엇일까요?

CSRF 공격을 방지하기 위함입니다. 과거에는 SameSite 속성이 기본적으로 설정되지 않아서 사이트 간 요청이 자동으로 쿠키를 포함하여 전송되었습니다. 이로 인해 악성 사이트(A)가 사용자를 속여 정상적인 사이트(B)에 요청을 보내고 세션을 도용하는 CSRF 공격이 가능했습니다. 이를 막기 위해 GET 요청에서만 자동으로 쿠키를 보내고 그 외의 요청에서는 쿠키를 보내지 않도록 한 것입니다.

CSRF 공격에 대한 부가 설명

CSRF 공격사용자가 의도하지 않은 요청을 보내도록 유도하여 악의적인 작업을 수행하는 공격이다.

  • 사용자가 특정 사이트에 로그인하여 세션이 유지된 상태에서
  • 공격자가 다른 사이트를 이용해 자동으로 요청을 보내도록 한다.

예를 들어, 사용자가 온라인 뱅킹 사이트에 로그인 한다. 그러면 서버가 사용자에게 세션 쿠키를 발급해주는데, 만약 로그인이 유지된 상태에서 피싱 사이트에 들어간다고 치자. 피싱 사이트에는 아래와 같은 공격 코드가 있다.

<img src="https://bank.com/transfer?to=hacker&amount=10000">

사용자가 피싱사이트에 방문하면 브라우저는 해당 사이트의 HTML 문서를 파싱하면서 img 태그의 src URL을 파싱하며 자동으로 HTTP 요청을 보내고(이때 대부분의 요청은 GET 방식으로 수행된다.) 브라우저가 로그인 된 상태의 쿠키를 자동으로 전송하면 사용자는 알지 못하는 사이에 공격자의 계좌로 돈을 이체하게 되는 것이다.

하지만 위에 GET 요청은 안전하다고 하지 않았는가? 사실 그건 서버 개발자에게 달려있다. 만약 서버 개발자가 돈을 보내는 작업을 GET 요청을 통해 하도록 설계해놨다면 SameSite=Lax를 사용해도 꼼짝없이 털리는 것이다. 따라서 중요한 작업을 POST 요청으로만 제한하는 방법도 필요하다.

Q6. 쿠키와 로컬 스토리지, 세션 스트리지의 차이점은 무엇인가요?

셋 다 브라우저에서 데이터를 저장하는 기능을 하지만 동작 방식이 다릅니다.

  • 쿠키:
    • 서버 요청 시 자동 전송
    • 만료 시간 설정 가능
    • 작은 데이터 저장 용도
    • HttpOnly, Secure 등의 속성을 적용해 보안 강화 가능
    • 로그인 유지, 세션 관리, 인증 정보 저장 등에 사용
  • 로컬 스토리지:
    • 영구 저장
    • 장기적인 데이터 저장(예: 테마 설정)에 사용
  • 세션 스토리지:
    • 브라우저 탭을 닫으면 삭제됨.(탭 간 공유 불가)
    • 일시적인 데이터 저장(예: 입력 폼 유지)에 사용

Q7. JWT를 저장할 때, 쿠키와 로컬 스토리지 중 어느 것이 더 안전할까요? 그리고 그 이유는 무엇인가요?

쿠키가 더 안전합니다. HttpOnly, Secure, SameSite 등의 보안 옵션을 설정할 수 있어 XSS 공격과 CSRF 공격을 보호할 수 있기 때문입니다. 이에 비해 로컬 스토리지는 쿠키와 달리 서버에게 자동으로 데이터를 보내는 로직이 없어 CSRF 공격에는 안전하지만 자바스크립트 내에서 접근이 가능하므로 XSS 공격을 당하면 공격자가 JWT를 쉽게 탈취할 수 있습니다.

Q8. CSRF 방지를 위해 JWT를 로컬 스토리지에 저장하는 경우 추가적으로 고려해야 할 보안 대책은 무엇인가요?

로컬스토리지는 자바스크립트에서 접근할 수 있습니다. 따라서 악성 스크립트가 실행되었을 때 JWT 토큰을 탈취당할 위험이 있습니다.

이를 방어하기 위해 사용자 입력값을 검증해야 합니다. 입력값에 <script> 태그 입력을 방하고 HTML 인코딩을 적용해 브라우저가 코드 실행이 아니라 문자로 해석하도록 해야합니다.

또한 CSP(Content Security Policy)를 설정하여 현재 도메인에서만 자바스크립트를 실행하도록 할 수 있습니다.

Content-Security-Policy: default-src 'self'; script-src 'self'

Q9. JWT와 세션 기반 인증의 차이는 무엇이며 각각의 장단점이 무엇인가요?

JWT는 토큰을 클라이언트(쿠키, 로컬/세션 스토리지 등)에 저장해두고, 매 요청마다 토큰을 포함해 전송합니다. 세션 기반 인증은 세션 ID를 쿠키에 저장해두고 세션 ID를 쿠키로 전달 후 서버에서 인증하는 방식입니다.

JWT 기반 인증은 서버가 상태를 관리하지 않으므로 확장성이 뛰어나고 쿠키 없이 헤더로 전송이 가능해 CORS 문제를 피할 수 있으나, 토큰이 클라이언트 측에 저장되므로 XSS 공격에 취약하고 서버에서 토큰을 강제 만료시킬 수 없기에 만료까지 기다려야 한다는 장단점이 있습니다.

세션 기반 인증은 서버에서 세션을 관리하므로 보안성이 높고, 세션을 강제 만료할 수 있으나, 서버가 세션을 저장해야한다는 점에서 확장성이 낮고, CSRF 공격에 취약할 수 있다는 단점이 있습니다.

따라서 트래픽이 많아 서버 부하를 줄여야하는 상황에서는 JWT를, 보안이 중요한 상황에서는 서버 세션을 사용하는 것이 좋습니다.

Q10. 보안 강화를 위해 쿠키에 적용할 수 있는 모든 보안 속성을 설명해주세요.

  • HttpOnly: 자바스크립트에서 접근할 수 없고 오로지 http 요청을 통해서만 접근 가능(XSS 공격 방지)
  • Secure: Https에서만 요청 전송 가능
  • SameSite: 쿠키가 다른 사이트에서 자동으로 전송되는 것을 어디까지 허용할 것인지(CSRF 공격 방지)
  • Domain: 쿠키를 전송할 도메인 지정
  • Path: 쿠키가 유효한 URL 경로 지정

클라이언트 개발자가 특히 신경 써야 할 부분

Access Token과 Refresh Token의 차이를 이해하고 관리

JWT 기반 인증에서 두 토큰의 역할과 저장 위치를 제대로 설정해줘야 한다.

  • Access Token: API 요청 시 인증 용도로 사용하며, Authorization: Bearer token 헤더에 저장한다. XSS 방어가 필요하다.
  • Refresh Token: 새로운 Access Token을 발급하는 역할이며 HttpOnly 쿠키에 저장해야 한다.

토큰 갱신 로직(자동 로그아웃 방지)

JWT는 Access Token이 만료되면 새로 발급해야 한다.

  • Access Token이 만료되면 Refresh Token을 사용해 새로운 Access Token을 받아와야 한다.
  • API 요청에서 401 Unauthorized 응답을 받을 경우 자동으로 액세스 토큰을 재발급하는 로직을 추가해야 한다.