3583 단어
18 분
쿠키와 세션으로 알아보는 웹 인증 구조와 보안

웹 서비스를 만들다 보면 로그인 기능은 거의 필수적으로 들어간다. 사용자는 아이디와 비밀번호를 입력하고, 서버는 이를 확인한 뒤 사용자가 로그인된 상태라고 판단한다. 겉으로 보면 단순한 기능처럼 보이지만, 실제 내부 구조를 보면 웹 인증은 생각보다 많은 보안 요소와 연결되어 있다.

특히 웹은 기본적으로 HTTP라는 프로토콜 위에서 동작한다. HTTP는 요청과 응답이 끝나면 이전 상태를 기억하지 않는 Stateless 구조를 가진다. 즉, 서버는 사용자가 방금 전에 로그인했는지 기본적으로 알 수 없다. 이를 해결하기 위해 사용되는 대표적인 기술이 바로 쿠키와 세션이다.

하지만 쿠키와 세션을 잘못 설계하면 세션 탈취, XSS, CSRF, 인증 우회 같은 취약점으로 이어질 수 있다. 따라서 필자는 이번 글에서 웹 인증 구조의 기본 원리와 쿠키, 세션의 동작 방식, 그리고 이를 안전하게 사용하는 방법까지 정리해보려 한다.


1. HTTP의 Stateless 구조#

HTTP는 클라이언트가 요청을 보내고 서버가 응답을 반환하는 방식으로 동작한다.

ClientServer
요청 전송요청 처리
응답 수신응답 반환

문제는 HTTP 요청 하나하나가 서로 독립적이라는 점이다. 예를 들어 사용자가 /login에서 로그인에 성공한 뒤 /mypage로 이동한다고 해도, 서버 입장에서는 두 요청이 같은 사용자의 요청인지 자동으로 알 수 없다.

POST /login HTTP/1.1
Host: example.com
id=panda&password=1234

이 요청에서 로그인에 성공했다고 해도, 다음 요청은 별개의 요청이다.

GET /mypage HTTP/1.1
Host: example.com

서버가 이전 요청을 기억하지 못한다면 마이페이지 접근을 허용할 수 없다. 그래서 서버는 사용자를 식별하기 위한 별도의 값을 클라이언트에게 전달해야 한다. 이때 사용되는 것이 쿠키이다.

2. 쿠키의 동작 원리#

쿠키는 서버가 클라이언트에게 저장하라고 전달하는 작은 데이터이다. 서버는 응답 헤더의 Set-Cookie를 통해 쿠키를 설정하고, 브라우저는 이후 같은 사이트에 요청을 보낼 때 자동으로 해당 쿠키를 포함한다.

HTTP/1.1 200 OK
Set-Cookie: session_id=abc123; Path=/; HttpOnly

브라우저는 이후 요청에서 다음과 같이 쿠키를 자동으로 전송한다.

GET /mypage HTTP/1.1
Host: example.com
Cookie: session_id=abc123

이제 서버는 session_id=abc123 값을 보고 이 요청이 어떤 사용자의 요청인지 판단할 수 있다.

2.1 쿠키에 직접 사용자 정보를 넣으면 안 되는 이유#

초보 개발자는 다음과 같이 쿠키에 사용자 정보를 직접 넣는 실수를 할 수 있다.

Set-Cookie: user_id=admin

이 방식은 매우 위험하다. 쿠키는 클라이언트 측에 저장되므로 사용자가 직접 수정할 수 있기 때문이다. 만약 서버가 이 값을 그대로 신뢰한다면, 공격자는 쿠키 값을 바꿔 인증을 우회할 수 있다.

Cookie: user_id=admin

따라서 쿠키에는 사용자의 권한이나 중요한 정보를 그대로 넣는 것이 아니라, 서버에서 관리하는 세션을 찾기 위한 식별자만 저장하는 것이 일반적이다.

3. 세션의 동작 원리#

세션은 서버 측에서 사용자의 로그인 상태를 저장하는 방식이다. 클라이언트는 세션 ID만 쿠키로 가지고 있고, 실제 사용자 정보는 서버에 저장된다.

로그인 과정은 보통 다음과 같다.

  1. 사용자가 아이디와 비밀번호를 입력한다.
  2. 서버가 계정 정보를 확인한다.
  3. 로그인에 성공하면 서버가 랜덤한 세션 ID를 생성한다.
  4. 서버는 세션 저장소에 세션 ID와 사용자 정보를 저장한다.
  5. 클라이언트에게 세션 ID를 쿠키로 전달한다.

구조로 보면 다음과 같다.

위치저장되는 값
브라우저 쿠키session_id
서버 세션 저장소session_id에 해당하는 사용자 정보

예를 들어 서버의 세션 저장소에는 다음과 같은 정보가 있을 수 있다.

{
"abc123": {
"user_id": 10,
"name": "panda",
"role": "user"
}
}

클라이언트는 abc123이라는 세션 ID만 가지고 있다. 서버는 요청마다 이 세션 ID를 확인하고, 해당하는 사용자 정보를 세션 저장소에서 가져온다.

4. 쿠키 보안 속성#

쿠키는 인증에 자주 사용되기 때문에 보안 설정이 매우 중요하다. 대표적인 보안 속성은 HttpOnly, Secure, SameSite이다.

4.1 HttpOnly#

HttpOnly는 JavaScript에서 쿠키에 접근하지 못하게 하는 속성이다.

Set-Cookie: session_id=abc123; HttpOnly

만약 HttpOnly가 없다면 JavaScript에서 다음과 같이 쿠키를 읽을 수 있다.

console.log(document.cookie);

이 상태에서 XSS 취약점이 발생하면 공격자가 사용자의 쿠키를 탈취할 수 있다. 반대로 HttpOnly가 설정되어 있으면 JavaScript로 쿠키를 직접 읽을 수 없기 때문에 세션 탈취 위험을 줄일 수 있다.

단, HttpOnly가 XSS 자체를 막아주는 것은 아니다. XSS가 발생하면 공격자는 사용자의 브라우저에서 요청을 보내는 등의 다른 악성 동작을 시도할 수 있다. 따라서 HttpOnly는 XSS 방어의 일부이지 완전한 해결책은 아니다.

4.2 Secure#

Secure 속성은 HTTPS 연결에서만 쿠키가 전송되도록 한다.

Set-Cookie: session_id=abc123; Secure

만약 HTTPS가 아닌 HTTP 환경에서 세션 쿠키가 전송된다면 네트워크 중간에서 쿠키가 노출될 위험이 있다. 따라서 실제 서비스에서는 로그인 세션 쿠키에 반드시 Secure 속성을 설정하는 것이 좋다.

4.3 SameSite#

SameSite는 다른 사이트에서 발생한 요청에 쿠키를 포함할지 결정하는 속성이다. 주로 CSRF 공격을 완화하기 위해 사용된다.

Set-Cookie: session_id=abc123; SameSite=Lax

대표적인 값은 다음과 같다.

설명
Strict같은 사이트 요청에서만 쿠키 전송
Lax일부 안전한 외부 이동에는 쿠키 전송
None모든 크로스 사이트 요청에 쿠키 전송

일반적인 웹 서비스에서는 SameSite=Lax가 많이 사용된다. 외부 링크를 통한 일반적인 이동은 허용하면서도, 위험한 크로스 사이트 요청은 어느 정도 막을 수 있기 때문이다.

5. 세션 기반 인증에서 발생할 수 있는 취약점#

5.1 세션 탈취#

세션 탈취는 공격자가 사용자의 세션 ID를 얻어 해당 사용자처럼 행동하는 공격이다. 세션 ID는 로그인 상태를 증명하는 중요한 값이기 때문에 탈취되면 계정 접근으로 이어질 수 있다.

세션 탈취가 발생할 수 있는 원인은 다음과 같다.

  • XSS로 인한 쿠키 노출
  • HTTPS 미사용으로 인한 네트워크 감청
  • 너무 예측 가능한 세션 ID
  • 세션 만료 시간 미설정
  • 로그아웃 이후 세션 무효화 누락

특히 세션 ID는 절대 예측 가능하면 안 된다. 다음과 같은 방식은 위험하다.

session_id = user_id + current_time

공격자가 규칙을 추측할 수 있기 때문이다. 세션 ID는 충분히 긴 랜덤 값으로 생성해야 하며, 서버 측에서 안전하게 관리해야 한다.

5.2 세션 고정 공격#

세션 고정 공격은 공격자가 미리 정한 세션 ID를 피해자에게 사용하게 만든 뒤, 피해자가 로그인하면 공격자가 같은 세션 ID로 접근하는 방식이다.

예를 들어 다음과 같은 흐름이다.

  1. 공격자가 특정 세션 ID를 생성하거나 획득한다.
  2. 피해자에게 해당 세션 ID를 사용하게 만든다.
  3. 피해자가 로그인한다.
  4. 서버가 기존 세션 ID를 그대로 로그인 상태로 변경한다.
  5. 공격자가 같은 세션 ID로 피해자 계정에 접근한다.

이를 막기 위해서는 로그인 성공 시 기존 세션 ID를 재사용하지 않고 새로운 세션 ID를 발급해야 한다.

로그인 전 세션 ID: old_session
로그인 후 세션 ID: new_session

즉, 인증 상태가 바뀌는 중요한 시점에는 세션을 재발급해야 한다.

5.3 CSRF#

CSRF는 사용자가 로그인된 상태라는 점을 악용해, 공격자가 의도한 요청을 사용자의 브라우저에서 보내게 만드는 공격이다.

예를 들어 사용자가 특정 사이트에 로그인한 상태에서 공격자의 페이지에 접속했다고 가정해보자. 공격자 페이지가 다음과 같은 요청을 자동으로 보낼 수 있다.

<form action="https://example.com/change-email" method="POST">
<input type="hidden" name="email" value="attacker@example.com">
</form>

브라우저는 해당 사이트의 쿠키를 자동으로 포함할 수 있기 때문에, 서버가 별도의 검증을 하지 않으면 사용자가 직접 요청한 것처럼 처리될 수 있다.

CSRF를 막기 위해서는 다음과 같은 방어가 필요하다.

  • CSRF Token 사용
  • SameSite 쿠키 설정
  • 중요한 요청에서 Origin 또는 Referer 검증
  • GET 요청으로 상태 변경 금지

특히 게시글 삭제, 비밀번호 변경, 이메일 변경 같은 상태 변경 요청은 반드시 POST, PATCH, DELETE 등의 메서드를 사용하고 추가 검증을 해야 한다.

6. 안전한 인증 구현 방법#

6.1 세션 쿠키 설정#

세션 쿠키는 다음과 같이 설정하는 것이 좋다.

Set-Cookie: session_id=random_value; HttpOnly; Secure; SameSite=Lax; Path=/

각 속성의 의미는 다음과 같다.

속성목적
HttpOnlyJavaScript에서 쿠키 접근 방지
SecureHTTPS에서만 쿠키 전송
SameSiteCSRF 공격 완화
Path쿠키가 적용될 경로 제한

실제 서비스에서는 도메인 구조에 따라 Domain 설정도 신중하게 해야 한다. 너무 넓은 도메인에 쿠키를 설정하면 하위 도메인 취약점이 전체 서비스 인증에 영향을 줄 수 있다.

6.2 로그인 성공 시 세션 재발급#

로그인 전과 로그인 후의 세션 ID는 달라야 한다. 이를 통해 세션 고정 공격을 방어할 수 있다.

before login: anonymous session
after login: authenticated session

즉, 사용자가 로그인에 성공하는 순간 서버는 기존 세션을 폐기하고 새로운 세션을 발급해야 한다.

6.3 로그아웃 시 세션 무효화#

로그아웃은 단순히 브라우저의 쿠키를 삭제하는 것으로 끝나면 안 된다. 서버 측 세션 저장소에서도 해당 세션을 제거해야 한다.

1. 클라이언트 쿠키 삭제
2. 서버 세션 저장소에서 session_id 제거

서버 세션이 남아 있다면 쿠키 값이 다시 사용될 가능성이 있다. 따라서 로그아웃 시에는 클라이언트와 서버 양쪽에서 모두 세션을 정리해야 한다.

6.4 권한 검증은 서버에서 수행#

프론트엔드에서 버튼을 숨기는 것은 보안이 아니다. 예를 들어 일반 사용자에게 관리자 버튼을 보이지 않게 한다고 해서 관리자 기능이 보호되는 것은 아니다.

if (user.role === "admin") {
showAdminButton();
}

이 코드는 UI 제어일 뿐이다. 실제 요청이 들어왔을 때 서버에서 다시 권한을 확인해야 한다.

사용자 요청 → 서버에서 세션 확인 → 사용자 권한 확인 → 기능 실행 여부 결정

권한 검증은 반드시 서버에서 수행되어야 한다.

7. 개발자가 확인해야 할 체크리스트#

웹 인증 기능을 만들 때는 다음 항목을 확인하는 것이 좋다.

  • 세션 ID가 충분히 랜덤한가?
  • 로그인 성공 시 세션 ID를 재발급하는가?
  • 로그아웃 시 서버 세션을 제거하는가?
  • 세션 쿠키에 HttpOnly, Secure, SameSite가 설정되어 있는가?
  • 중요한 요청에 CSRF 방어가 적용되어 있는가?
  • 권한 검증을 프론트엔드가 아닌 서버에서 수행하는가?
  • 세션 만료 시간이 설정되어 있는가?
  • HTTPS를 강제하고 있는가?
  • 쿠키에 민감한 정보를 직접 저장하지 않는가?

이러한 항목들은 단순한 옵션처럼 보이지만 실제 서비스에서는 인증 보안의 기본이 된다.

8. 마무리#

오늘은 웹 인증 구조와 쿠키, 세션의 동작 원리에 대해 알아보았다. 로그인 기능은 겉으로 보기에는 단순하지만, 내부적으로는 HTTP의 Stateless 구조, 쿠키 전달 방식, 서버 세션 저장소, 브라우저 보안 정책 등 여러 개념이 연결되어 있다.

특히 세션 쿠키는 로그인 상태를 증명하는 중요한 값이므로 안전하게 보호해야 한다. HttpOnly, Secure, SameSite 같은 속성을 올바르게 설정하고, 로그인 시 세션 재발급, 로그아웃 시 세션 무효화, 서버 측 권한 검증을 적용해야 한다.

웹 보안은 특별한 해킹 기법을 아는 것에서만 시작되는 것이 아니다. 기본적인 웹 구조를 정확히 이해하고, 개발 과정에서 안전한 기본값을 선택하는 것부터 시작된다. 다음 글에서는 XSS나 CSRF처럼 실제 웹 서비스에서 자주 발생하는 취약점을 더 자세히 다뤄보겠다.

쿠키와 세션으로 알아보는 웹 인증 구조와 보안
https://blog.paisl.cloud/posts/008/
저자
PAISL
발행일
2026-06-05
콘텐츠 라이선스
CC BY-NC-SA 4.0