---
term: '세션 관리'
seoTitle: '세션 관리란? 수명 주기, 쿠키, 하이재킹, 타임아웃'
headline: '세션 관리란?'
slug: session-management
category: auth-security
shortDefinition: '세션 관리는 HTTP 요청을 한 사용자에게 연결하는 서버 측 상태를 생성하고 검증하고 파기하는 분야입니다.'
relatedTerms:
  - json-web-token-jwt
  - authentication-vs-authorization
  - cross-site-scripting-xss-prevention
  - multi-factor-authentication-mfa
contrastsWith:
  - json-web-token-jwt
aboutTerms:
  - 'Session ID'
  - 'Session Hijacking'
  - 'Session Fixation'
  - 'Session Cookies'
faq:
  - question: '세션은 어떻게 동작합니까?'
    answer: '로그인 시 서버가 세션 레코드를 만들고 무작위 세션 ID를 쿠키에 담아 발급합니다. 브라우저는 모든 요청에 이 ID를 돌려보내고, 서버는 연결된 상태를 조회하며, 레코드는 로그아웃이나 만료 시점에 파기됩니다. 이 ID가 자격 증명의 전부입니다. 누구든 이를 제시하면 그 사용자로 취급됩니다.'
  - question: '세션 인증과 토큰(JWT) 인증의 차이는 무엇입니까?'
    answer: '상태가 어디에 있는가의 차이입니다. 세션은 상태를 서버 측에 두므로 요청마다 한 번 조회하며 즉시 폐기할 수 있습니다. JWT는 상태를 토큰 안에 담으므로 조회가 없고 어디서든 검증할 수 있지만, 무슨 일이 있어도 만료 전까지 유효합니다. 세션은 통제가 필요한 단일 도메인 앱에, 토큰은 이식성이 필요한 API와 마이크로서비스에 적합합니다.'
  - question: '세션 하이재킹이란 무엇이며 어떻게 방지합니까?'
    answer: '스니핑, XSS, 악성 코드로 유효한 세션 ID를 훔친 뒤 이를 제시해 비밀번호를 전혀 모르는 채로 사용자를 사칭하는 공격입니다. 방어 수단은 전 구간 HTTPS, HttpOnly와 Secure 쿠키 플래그, 엔트로피가 높은 ID, 짧은 수명, 권한 변경 시 재생성, 이상 징후 모니터링입니다.'
  - question: '세션 고정이란 무엇입니까?'
    answer: '공격자가 이미 알고 있는 세션 ID를 조작된 링크나 서브도메인 쿠키로 심어 두고, 피해자가 그 ID로 로그인하기를 기다리는 공격입니다. 그러면 알려진 ID가 인증된 세션이 됩니다. 완전한 해결책은 모든 인증 시점에 완전히 새로운 ID를 발급하고, 서버가 생성한 적 없는 ID는 거부하는 것입니다.'
  - question: '세션 쿠키 플래그는 각각 무슨 역할을 합니까?'
    answer: '각 플래그가 탈취 경로 하나씩을 막습니다. Secure는 쿠키를 HTTPS로만 전송하고(스니핑 차단), HttpOnly는 JavaScript에서 쿠키를 숨기며(XSS를 통한 쿠키 탈취 차단), SameSite는 교차 사이트 요청에 쿠키를 싣지 않고(CSRF 차단), __Host- 이름 접두사는 쿠키를 하나의 출처에 고정합니다.'
  - question: '적절한 세션 타임아웃은 얼마입니까?'
    answer: '서버가 강제하는 두 개의 시계가 필요합니다. 유휴 타임아웃은 고가치 앱에서는 몇 분, 일반적인 앱에서는 15–30분이고, 절대 타임아웃은 활동 여부와 무관하게 몇 시간입니다. 미국 연방 디지털 ID 지침은 두 번째 보증 수준에서 유휴 최대 1시간, 그리고 최소 24시간마다 재인증할 것을 권고합니다.'
  - question: '로그아웃은 어떻게 동작해야 합니까?'
    answer: '서버 측이 먼저입니다. 세션 레코드를 파기해 ID가 모든 곳에서 무효가 되게 한 뒤 쿠키를 지웁니다. 전형적인 실패는 그 반대입니다. 쿠키만 삭제하면 ID를 가로챈 누구에게나 세션이 살아 있게 되어, "로그아웃"이 UI 애니메이션에 불과해집니다.'
  - question: '"로그인 상태 유지"는 안전합니까?'
    answer: '보안을 편의와 의도적으로 맞바꾸는 기능입니다. 책임 있게 구현하려면 별도의 장기 토큰을 두고, 일회용으로 방문할 때마다 회전하며, 강화된 쿠키에 저장하고, 서버 측에서 폐기할 수 있게 하며, 비밀번호 변경 시 무효화해야 합니다. 그리고 민감한 작업 전의 재인증을 결코 대신해서는 안 됩니다.'
codeLanguages: [javascript, dart, swift, kotlin]
externalAuthorities:
  - name: 'OWASP Session Management Cheat Sheet'
    url: 'https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html'
  - name: 'NIST SP 800-63B-4 §5 — Session Management'
    url: 'https://pages.nist.gov/800-63-4/sp800-63b.html'
  - name: 'RFC 6265 — HTTP State Management Mechanism'
    url: 'https://datatracker.ietf.org/doc/html/rfc6265'
  - name: 'Using HTTP cookies — MDN Web Docs'
    url: 'https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Cookies'
cta:
  title: '쿼리할 수 있는 세션'
  text: 'Back4app의 세션은 데이터베이스 객체입니다. 디바이스별로 존재하고, "활성 세션" 화면을 위해 목록으로 조회할 수 있으며, 사용자가 로그아웃하거나 비밀번호를 바꾸거나 여러분이 원하는 순간 서버 측에서 즉시 폐기됩니다.'
  linkText: '무료로 시작하기'
  linkUrl: 'https://www.back4app.com/signup'
author: 'Back4app Engineering'
publishedDate: '2026-10-29'
translationKey: session-management
---

**세션 관리는 HTTP 요청을 한 사용자에게 연결하는 서버 측 상태를 생성하고 검증하고 파기하는 분야입니다.** HTTP 자체는 아무것도 기억하지 않습니다. 서버 입장에서 모든 요청은 처음 보는 요청입니다. 그래서 애플리케이션은 세션으로 이 간극을 메웁니다. 서버 측 레코드와, 브라우저가 요청마다 제시하는 무작위 ID의 조합입니다. 나머지 모든 보안 원칙의 출발점이 되는 통찰은 이것입니다. **그 ID는 자격 증명과 완전히 동등합니다.** 비밀번호 없이도 ID를 가진 사람이 곧 그 사용자*입니다*. 따라서 ID의 생성, 전송, 파기는 비밀번호 수준으로 다뤄야 합니다.

## 핵심 요약

| 질문 | 답변 |
| --- | --- |
| 메커니즘 | 로그인 → 서버 레코드 + 쿠키 속 무작위 ID → 요청마다 ID 반환 |
| 통찰 | 세션 ID *자체가* 자격 증명 – 하이재킹된 ID = 계정 탈취 |
| 수명 주기 | 생성 → 로그인/권한 변경 시 재생성 → 검증 → 만료 → 서버 측 파기 |
| 수치 | CSPRNG 엔트로피 ≥64비트 · 유휴 15–30분 · 절대 몇 시간 |
| 전형적인 버그 | 쿠키는 지우지만 서버 레코드는 살려 두는 "로그아웃" |

## 다섯 단계의 수명 주기

```text
1 생성        로그인 시: 서버 측 레코드 + 새 무작위 ID(≥64비트, CSPRNG)
2 재생성      권한이 바뀔 때마다 예외 없이(로그인, 역할 상승, 비밀번호 변경)
              새 ID를 발급하고 이전 ID는 폐기 (세션 고정 차단)
3 검증        매 요청: ID가 존재하고, 만료되지 않았고, 이 사용자와 일치
4 만료        서버가 강제하는 두 개의 시계: 유휴 타임아웃 + 절대 타임아웃
5 파기        로그아웃 = 서버 레코드를 반드시 먼저 삭제한 뒤 쿠키를 지움
              (쿠키만 지우는 "로그아웃"은 도둑에게 세션을 살려 둠)
```

세션을 일급 객체이자 쿼리할 수 있는 객체로 다루면, 수명 주기의 각 단계를 코드에서 직접 제어할 수 있습니다.

**JavaScript:**

```javascript
// JavaScript / Node.js — Back4app JS SDK
// Sessions are objects: queryable, per-device, revocable
const user = await Parse.User.logIn('ada', password); // Session object created
console.log(user.getSessionToken()); // r:… — the credential

// "Active devices" UI: each login is a Session row (ACL: owner-only)
const sessions = await new Parse.Query(Parse.Session).find();

// Logout = server-side destroy — the token dies NOW
await Parse.User.logOut();
```

**Flutter:**

```dart
// Flutter / Dart — Back4app Flutter SDK
// Sessions are objects: queryable, per-device, revocable
final user = ParseUser('ada', password, null);
await user.login(); // Session object created
print(user.sessionToken); // r:… — the credential

// "Active devices" UI: each login is a Session row (ACL: owner-only)
final sessions = await QueryBuilder(ParseSession.forQuery()).query();

// Logout = server-side destroy — the token dies NOW
await user.logout();
```

**Swift:**

```swift
// iOS / Swift — Back4app Swift SDK
// Sessions are objects: queryable, per-device, revocable
let user = try await User.login(username: "ada", password: password)
print(user.sessionToken ?? "") // r:… — the credential

// "Active devices" UI: each login is a Session row (ACL: owner-only)
let sessions = try await ParseSession.query().find()

// Logout = server-side destroy — the token dies NOW
try await User.logout()
```

**Kotlin:**

```kotlin
// Android / Kotlin — Back4app Android SDK
// Sessions are objects: queryable, per-device, revocable
val user = ParseUser.logIn("ada", password) // Session object created
println(user.sessionToken) // r:… — the credential

// "Active devices" UI: each login is a Session row (ACL: owner-only)
val sessions = ParseQuery.getQuery(ParseSession::class.java).find()

// Logout = server-side destroy — the token dies NOW
ParseUser.logOut()
```

```mermaid
flowchart LR
  accTitle: 로그인부터 서버 측 파기까지의 세션 수명 주기
  accDescr: 로그인 시 서버가 세션 레코드를 만들고 무작위 ID를 쿠키에 담아 발급합니다. ID는 권한 변경 시 재생성되고, 매 요청마다 서버 레코드와 대조해 검증되며, 유휴 타임아웃과 절대 타임아웃으로 만료되고, 로그아웃 시 서버 측에서 파기되어 모든 곳에서 무효가 됩니다.
  L["로그인<br/>(인증)"] --> C["레코드 생성 +<br/>무작위 ID → 쿠키"]
  C --> R["권한 변경 시<br/>ID 재생성"]
  R --> V["매 요청마다<br/>검증"]
  V -->|"유휴 / 절대<br/>타임아웃"| X["만료"]
  V -->|"로그아웃"| D["서버 측에서<br/>레코드 파기"]
  X --> D
```

## 세션 쿠키: 플래그와 각 플래그가 막는 것

상위 노출 페이지 어디에도 표로 정리되어 있지 않은 대응 관계입니다. 플래그마다 막아 내는 공격이 하나씩 정해져 있습니다.

| 플래그 | 역할 | 막는 공격 |
| --- | --- | --- |
| `Secure` | 쿠키를 HTTPS로만 전송 | 네트워크 스니핑 |
| `HttpOnly` | JavaScript에서 보이지 않음 | [XSS](/glossary/ko/cross-site-scripting-xss-prevention/)를 통한 쿠키 탈취 |
| `SameSite=Lax/Strict` | 교차 사이트 요청에는 싣지 않음 | CSRF |
| `__Host-` 접두사 | 쿠키를 출처에 고정, 서브도메인 속임수 불가 | 서브도메인을 통한 세션 고정 |
| *(Max-Age/Expires 없음)* | 브라우저 세션과 함께 소멸 | 공용 기기에 남는 오래된 세션 |

[RFC 6265](https://datatracker.ietf.org/doc/html/rfc6265)의 의미론을 따르며, 실무 세부 사항은 [MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Cookies)에 있습니다. 다섯 가지를 모두 갖춘 것이 강화된 구성이 아니라 기준선입니다.

## 공격과 각각의 방어

**하이재킹**은 유효한 ID를 훔쳐(평문 HTTP에서의 스니핑, XSS, 악성 코드) 제시하는 공격입니다. 서버에는 정상 사용자로 보입니다. 방어는 전 구간 TLS, 위의 플래그 표, 짧은 수명, 불가능한 이동(impossible travel) 모니터링입니다. **세션 고정**은 메커니즘 차원에서 이해할 가치가 있는 역전된 공격입니다. 공격자가 로그인 전에 피해자에게 ID를 *건네고*(조작된 링크, 심어 둔 쿠키), 피해자가 인증하면, 공격자가 아는 ID가 이제 로그인된 세션이 됩니다. 방어는 한 수로 끝납니다. **인증 시점에 ID를 재생성하는 것**입니다. 공격자가 아는 로그인 전 ID는 권한이 붙는 순간 쓸모없어지며, 엄격한 서버는 자신이 발급하지 않은 ID를 모두 거부합니다. **XSS 탈취**는 주입된 스크립트가 쿠키를 읽는 공격입니다. `HttpOnly`로 쿠키 읽기를 막을 수 있지만, 이는 [XSS 자체를 고치는](/glossary/ko/cross-site-scripting-xss-prevention/) 동안의 피해 제한일 뿐입니다. **CSRF**는 브라우저가 위조된 교차 사이트 요청에 친절하게 쿠키를 붙여 주는 공격입니다. `SameSite`와 CSRF 방지 토큰이 이를 막습니다.

## 세션 vs. JWT

| | 서버 측 세션 | JWT |
| --- | --- | --- |
| 상태의 위치 | 서버 | 토큰 내부 |
| 폐기 | 즉시 – 레코드 삭제 | `exp`까지 대기, 또는 거부 목록 상태 |
| 요청당 비용 | 저장소 조회 한 번 | 서명 검증 |
| 서비스 간 확장 | 공유 저장소 필요 | 키를 가진 누구나 검증 |

핵심은 **폐기 가능성**이며, 이는 기능 체크박스가 아니라 아키텍처 결정입니다. 세션은 원하는 순간 소멸시킬 수 있지만 무상태 토큰은 그럴 수 없고, 모든 우회책은 제거했던 상태를 다시 도입합니다. [JWT 항목](/glossary/ko/json-web-token-jwt/)이 무상태 쪽을 변호하며, 이 글의 주제는 상태 유지 방식을 *제대로* 하려면 무엇이 필요한가입니다.

## 구체적인 수치

[OWASP 치트 시트](https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html)는 엔트로피를 **CSPRNG에서 얻은 ≥64비트**로 제시합니다. 무작위 16진수 문자 16개로, 현실적인 요청 속도에서 ID를 무차별 대입하려면 수백 년이 걸리는 수준이며, ID에는 의미 있는 정보를 일절 인코딩하지 않습니다. 타임아웃은 두 개의 시계로 동작합니다. **유휴** 타임아웃(고가치 애플리케이션은 2–5분, 일반적인 애플리케이션은 15–30분)과 **절대** 타임아웃(몇 시간, 활동 중인 세션도 종료해 도난당한 ID에 확실한 상한을 둠)입니다. [NIST 디지털 ID 지침](https://pages.nist.gov/800-63-4/sp800-63b.html)도 같은 형태를 공식화합니다. 보증 수준 2에서는 유휴 상태가 최대 1시간을 넘기 전에, 그리고 활동과 무관하게 최소 24시간마다 재인증해야 합니다(수준 3에서는 12시간).

## 세션 확장: 스티키 라우팅 vs. 공유 저장소

| | 스티키 세션 | 공유 저장소(Redis 방식) |
| --- | --- | --- |
| 방식 | 로드 밸런서가 사용자 → 서버를 고정 | 모든 서버가 하나의 세션 저장소를 읽음 |
| 서버 장애 시 | 그 서버의 세션도 함께 소멸 | 사용자는 알아차리지 못함 |
| 확장 | 불균등한 부하, 배포 시 드레인 필요 | 어떤 서버든, 어떤 요청이든 |
| 판정 | 라우팅 땜질 | 아키텍처 |

프로세스 내 세션 메모리는 정확히 서버 한 대에서만 동작합니다. 스티키 라우팅은 이를 연장하는 방법이지만, 서버 한 대가 내려갈 때마다 그 서버에 붙은 사용자가 모두 로그아웃되는 작은 장애 지점을 서버마다 만듭니다. 표준적인 답은 공유 인메모리 저장소(Redis, Memcached)나 데이터베이스입니다. 세션 상태가 인프라가 되고 웹 계층은 무상태가 됩니다. JWT 아키텍처를 매력적으로 만드는 바로 그 속성을, 즉시 폐기 능력을 유지한 채로 얻는 것입니다.

## 제품 기능으로서의 세션

세션이 *보이게* 되면 보안 계층은 UX도 겸합니다. 디바이스별 로그인 시각과 위치를 나열하는 "활성 세션" 화면, "모든 곳에서 로그아웃" 버튼, 비밀번호 변경이나 침해 의심 시 모든 세션의 자동 폐기가 그 예입니다. 사용자는 이를 안전으로 받아들이지만, 엔지니어는 아키텍처에 대한 요구 사항으로 읽어야 합니다. 세션은 캐시 속 불투명한 덩어리가 아니라 *소유자가 있는 쿼리 가능한 객체*여야 하며, 조회 용도로만 만든 세션 저장소가 부족해지는 지점이 바로 여기입니다.

## 일반적인 사용 사례

- **웹 앱 로그인 상태** – 전형적인 사례입니다. 플래그를 모두 갖춘 쿠키로 세션을 전달합니다.
- **전자상거래 장바구니와 흐름** – 페이지 이동은 견뎌야 하지만 일주일까지 남아서는 안 되는 다단계 상태입니다.
- **뱅킹과 고가치 앱** – 짧은 유휴 타임아웃, 절대 상한, 민감한 작업을 위한 세션 중간의 [단계적 MFA](/glossary/ko/multi-factor-authentication-mfa/)를 사용합니다.
- **디바이스 관리** – 디바이스별 세션이 "도난당한 휴대폰에서 로그아웃"을 가능하게 합니다.
- **관리자 패널** – 권한 상승 시 재생성과 공격적인 타임아웃이 제값을 하는 곳입니다.

## 세션과 토큰 중 무엇을 선택해야 할까? 결정 매트릭스

| 상황 | 선택 |
| --- | --- |
| 단일 도메인 웹 앱 | 세션 – 더 단순하고 즉시 폐기 가능 |
| 즉각적인 차단이 절대 조건 | 세션(또는 토큰 + 버리겠다던 상태) |
| 여러 서비스가 독립적으로 검증 | [JWT](/glossary/ko/json-web-token-jwt/) |
| BaaS 위의 모바일 앱 | 플랫폼의 세션 토큰 – 폐기 가능, 기본 제공 |
| 세션을 쓰면서 수평 확장 | 스티키 라우팅이 아니라 공유 저장소 |
| 기능으로서의 "활성 디바이스" | 쿼리 가능한 객체로서의 세션 |

## 한계와 트레이드오프

- **저장소는 핫 패스 인프라입니다.** 모든 요청이 저장소를 읽으므로, 저장소의 지연 시간이 곧 애플리케이션의 지연 시간이고, 저장소에 장애가 나면 모든 사용자가 로그아웃됩니다.
- **교차 도메인은 어색합니다.** 쿠키는 출처에 묶이고, 여러 주체가 소비하는 API는 토큰 쪽으로 기웁니다. 솔직한 답은 흔히 앱에는 세션, API에는 토큰이라는 하이브리드입니다.
- **타임아웃은 사용자에게 부담을 줍니다.** 유휴 로그아웃은 매번 마찰입니다. 위의 수치는 상수가 아니라 위험에 관한 결정이며, 제품 측의 승인을 받아야 합니다.
- **폐기는 사용자가 하는 동작과 연결되어야 합니다.** 즉시 폐기는 비밀번호 변경과 "모든 곳에서 로그아웃"이 실제로 이를 실행할 때만 가치가 있습니다. 기능만 갖추지 말고 이벤트를 연결해야 합니다.
- **세션은 쿠키 정책의 영향을 그대로 받습니다.** 서드파티 쿠키 정책 변화와 브라우저의 개인정보 보호 작업이 지형을 계속 바꿉니다. 퍼스트파티 세션 쿠키는 여전히 안전한 영역이지만, 의도적으로 그 안에 머물러야 합니다.

## Back4app에서의 세션

Back4app은 관리형 데이터베이스, 자동 생성되는 REST 및 GraphQL API, 인증, 파일 스토리지, Cloud Code 서버리스 함수를 결합한 오픈소스 Backend as a Service(BaaS) 플랫폼입니다. 여기서 세션은 이 글이 계속 요구한 "쿼리 가능한 객체" 그 자체입니다. 로그인할 때마다 폐기 가능한 토큰, 그 사용자, 생성 컨텍스트, 만료 시각을 담은 `Session` 객체가 생성되며, ACL 범위가 지정되어 사용자는 자신의 세션만 볼 수 있습니다. 코드 탭이 그 결과를 보여 줍니다. "활성 디바이스" 화면은 쿼리 하나이고, 로그아웃은 토큰을 모든 곳에서 즉시 소멸시키는 서버 측 파기이며, 비밀번호 변경 시 모든 세션을 폐기할 수 있고, Cloud Code 트리거는 단계적 인증 규칙과 감사 추적을 위한 연결 지점입니다. 수명 주기, 폐기, 제품 기능이 모두 같은 기본 요소, 즉 데이터로서의 세션 위에 있으며, 엔트로피, 저장, 검증 메커니즘은 플랫폼이 운영합니다.
