동시 접속 제한 정책 우회 세션 토큰 복제 공격 탐지

📅 January 21, 2026 👤 Floyd Owen
한 대의 디지털 서버 랙에 단 하나만 꾸준히 빛나는 표시등이 있고, 그 주변으로 같은 빛들이 불규칙하게 깜빡이며 복제되어 퍼지는 모습이다.

증상 확인: 세션이 예상치 못하게 유지되거나 중복 생성되는가?

웹 애플리케이션 또는 서비스에 동시 접속 제한 정책(예: 하나의 계정으로는 하나의 장치에서만 로그인 가능)이 존재함에도 불구하고, 아래와 같은 증상이 관찰된다면 세션 토큰 복제 공격을 의심해야 합니다. 사용자 A가 로그인한 후, 사용자 B가 동일한 계정으로 다른 장치/브라우저에서 로그인해도 기존 세션(A)이 정상적으로 종료되지 않고 유지됩니다. 또는, 단일 사용자가 명시적으로 로그아웃하지 않았는데도 불구하고, 시스템 로그에 동일한 세션 ID로부터의 요청이 서로 다른 IP 주소 또는 User-Agent에서 거의 동시에 발생하는 기록이 확인됩니다. 이는 공격자가 합법적으로 발급받은 세션 토큰을 탈취하여 다른 환경에서 재사용(복제)하고 있음을 강력히 시사합니다.

원인 분석: 세션 관리의 근본적 취약점

이 공격이 성공하는 핵심 원인은 서버 측 세션 상태 관리의 논리적 결함에 있습니다. 대부분의 동시 접속 제한은 사용자가 새로 로그인할 때, 기존에 저장된 해당 사용자의 세션 데이터를 무효화하는 방식으로 구현됩니다. 문제는, 이미 발급되어 클라이언트 측(예: 브라우저 쿠키)에 저장된 세션 토큰 값 자체가 변경되지 않는다는 점입니다. 공격자가 이 토큰 값을 미리 복제해 두면, 서버는 동일한 유효한 토큰으로 들어오는 요청을 모두 정당한 사용자의 요청으로 판단하게 됩니다. 세션 저장소(인메모리, DB, Redis 등)가 토큰 값만으로 사용자를 식별하기 때문입니다. 이는 인증(Authentication)과 세션 관리(Session Management)를 분리하여 생각하지 않은 설계에서 비롯됩니다.

해결 방법 1: 세션 고유 식별자 강화 및 적극적 무효화

가장 확실한 방법은 세션 토큰을 사용자 계정과 1:1로만 매핑하는 단순한 구조를 버리고, 세션 자체에 고유한 식별 정보를 더해 관리하는 것입니다, 이는 기존 인프라를 크게 변경하지 않고 적용 가능한 실전 조치입니다.

  1. 세션 바인딩 정보 추가: 사용자 로그인 시 생성되는 세션 데이터에 반드시 생성 타임스탬프, 로그인 ip 주소(또는 대역), user-agent 문자열 해시를 함께 저장합니다. 이 정보들은 토큰 값과 별도로 서버 측에 보관해야 합니다.
  2. 요청 시 검증 로직 구현: 세션 토큰으로 사용자 식별 후, 실제 요청의 IP, User-Agent 정보를 1단계에서 저장된 정보와 비교합니다. 불일치할 경우, 즉시 해당 세션을 무효화하고 모든 클라이언트에게 재인증을 요구합니다.
  3. 적극적인 세션 무효화: 새로운 로그인이 발생하면 기존 세션을 삭제하는 수준을 넘어, 해당 사용자 ID에 연결된 모든 활성 세션 토큰을 저장소에서 조회하여 일괄 무효화합니다. Redis의 Set 자료구조를 활용해 `user:{userId}:sessions` 키에 세션 ID들을 저장해두고, 무효화 시점에 이 Set에 있는 모든 ID를 삭제하는 패턴이 효과적입니다.

이 방법은 공격자가 토큰만 복제했을 경우, IP나 User-Agent 불일치로 차단되며, 정상적인 사용자의 새 로그인으로 인해 복제된 토큰도 강제로 만료될 수 있습니다.

해결 방법 2: 동적 세션 토큰 및 단일 세션 정책 강제

보다 근본적인 해결책은 세션 토큰을 정적(Static)이 아닌 동적(Dynamic)으로 만들어 복제 자체를 무의미하게 만드는 것입니다. OWASP 세션 관리 체크리스트에도 권장되는 방식입니다.

  1. 로그인 시 새 토큰 강제 발급: 사용자가 인증을 성공할 때마다(새 로그인, 재인증) 반드시 새로운 세션 ID(토큰)를 발급합니다. 기존 쿠키를 덮어쓰도록 응답해야 합니다.
  2. 단일 활성 세션 정책 구현: 데이터베이스나 세션 저장소에 사용자 테이블 또는 문서에 `current_active_session_id` 필드를 두고, 로그인 시 이 값을 최신 세션 ID로 업데이트합니다.
  3. 모든 요청에 대한 세션 유효성 2중 검사: 요청이 들어올 때마다 다음 두 가지를 모두 검증합니다.
    • 전통적 검증: 전달받은 세션 ID가 저장소에 존재하는가?
    • 단일 세션 검증: 저장소에 있는 해당 사용자의 `current_active_session_id` 값과 요청의 세션 ID가 일치하는가?

일치하지 않을 경우, 해당 요청의 세션을 즉시 삭제하고 401 Unauthorized 또는 재로그인 페이지로 안내합니다. 이 방식은 토큰 복제 공격을 원천 차단하며, 사용자에게는 가장 최근의 로그인만이 유효한 세션으로 유지되는 직관적인 경험을 제공합니다.

주의사항: 방법 2를 구현할 때, 사용자가 ‘다른 탭에서 작업 중’인 일반적인 시나리오를 고려해야 합니다. 이는 새 로그인이 아니므로 세션 토큰이 갱신되어서는 안 됩니다. 따라서 ‘로그인’ 이벤트와 ‘세션 갱신’ 이벤트를 명확히 구분하는 로직이 필요합니다, 게다가, 모든 세션 관련 작업은 반드시 트랜잭션 내에서 수행되어, 세션 생성과 `current_active_session_id` 업데이트가 원자적으로 실행되도록 해야 합니다. 부분적 성공으로 인한 데이터 불일치가 발생하면 사용자가 로그인 자체를 못 할 수 있습니다.

해결 방법 3: 보조 토큰(Secondary Token)을 이용한 상태 유지

고가용성 분산 환경에서 발생하는 세션 저장소의 동기화 지연 문제를 우회하거나, 클라이언트 상태를 완전히 폐기하기 어려운 레거시 시스템을 개선할 때 유용한 접근 방식입니다. 핵심은 기존 세션 토큰 체계는 유지하되, 보조적인 검증 수단을 추가하여 보안 강도를 높이는 데 있습니다.

  • 롤링 토큰(Rolling Token) 발급: 각 요청이 성공적으로 처리될 때마다 응답 헤더에 새로운 세션 토큰이나 전용 X-CSRF-Token을 포함시켜 클라이언트가 이를 지속적으로 갱신하도록 강제합니다. 실제 시스템 운영 환경의 로그 기록을 분석해 보면, 1분 내외의 매우 짧은 수명을 가진 토큰을 활용할 경우 공격자가 탈취한 정적 토큰은 첫 시도 이후 즉시 만료되어 재사용 공격(Replay Attack)을 효과적으로 차단하는 것으로 확인됩니다.
  • 암호화된 클라이언트 상태 활용: 세션 ID와는 별개로 로그인 시간, 요청 일련번호, 접속 IP의 일부 등을 암호화하여 클라이언트 측 쿠키에 저장합니다. 서버는 매 요청마다 이 값을 복호화하여 서버 측 세션 데이터와 대조합니다. 보안 사고 대응의 실무 리포트에 따르면, 공격자가 서버 내부의 암호화 키를 확보하지 못하는 한 유효한 상태 값을 위조하는 것이 물리적으로 불가능하므로 세션 탈취 리스크를 획기적으로 낮출 수 있습니다. 다만, 이는 키 관리의 복잡성과 서버 측의 암복호화 연산 부하를 동반합니다.
  • 요청 서명(Request Signing) 도입: 결제나 개인정보 수정과 같은 임계점 높은 API 호출 시, 세션 토큰 외에 서버가 직전 응답에서 전달한 난수(Nonce)와 타임스탬프를 조합하여 요청을 서명하도록 설계합니다. 실제 금융권 아키텍처에서 관측되는 확인된 패턴은 이러한 서명 방식이 클라이언트 환경 외부에서 재현하기 매우 까다롭다는 점을 보여줍니다. 설령 공격자가 세션 토큰을 복제하더라도, 매 순간 변하는 서명 값을 생성하지 못해 최종적인 권한 행사는 차단됩니다.

이 방법은 기존의 세션 관리 프레임워크를 전면 교체하기 힘든 상황에서, 특정 보안 취약 구간에만 전략적으로 배치하여 전체 시스템의 무결성을 보강할 수 있는 실무적인 대안입니다.를 대폭 수정하기 어려울 때, 핵심 기능 주변에 보안 레이어를 추가하는 점진적 보안 강화에 적합합니다.

탐지 및 대응 체계 구축

한 대의 디지털 서버 랙에 단 하나만 꾸준히 빛나는 표시등이 있고, 그 주변으로 같은 빛들이 불규칙하게 깜빡이며 복제되어 퍼지는 모습이다.

공격을 완벽히 차단하는 것과 함께, 시도 자체를 탐지하여 대응하는 것은 동등하게 중요합니다. 로그 분석과 실시간 모니터링을 결합하여 다음과 같은 의심 패턴에 대한 알림을 설정하십시오.

  • 지리적·기기적 불일치: 동일 세션 ID의 요청 IP가 짧은 시간 내에 물리적으로 불가능한 거리에서 교차 발생하거나, 세션 중간에 User-Agent(브라우저 정보)가 변경되는 경우.
  • 세션 과다 생성: 하나의 사용자 ID로 등록된 활성 세션 수가 임계치(예: 3개)를 초과하는 경우.

의심 패턴이 감지되면 WAF(웹 애플리케이션 방화벽)나 미들웨어 수준에서 해당 세션을 즉시 무효화하고 IP를 차단하십시오. 또한 사용자에게 즉시 알림을 발송하여 보안 인식을 높이는 동시에 공격 탐지의 정확도를 높여야 합니다.

이때 탐지의 신뢰도를 결정짓는 핵심 요소가 바로 관리자 접속 로그의 위변조 방지 체인 해시 저장 구조 검토입니다. 실시간 탐지 시스템이 아무리 정교하더라도, 공격자가 침입 후 탐지 로그 자체를 수정하거나 삭제할 수 있다면 대응 체계는 무력화됩니다.

각 로그 엔트리가 이전 로그의 해시값을 포함하는 체인 해시 구조를 적용하면, 특정 시점의 로그를 건드리는 순간 전체 사슬이 끊어지며 변조 사실이 즉각 드러납니다. 이는 탐지 시스템이 생성한 ‘공격의 기록’을 물리적으로 보호하여 사후 포렌식과 법적 증거로서의 가치를 보존하는 강력한 기술적 기반이 됩니다.

전문가 팁: 세션 저장소로 Redis와 같은 중앙 집중식 인메모리 시스템을 활용하십시오. 사용자 키 하위에 여러 세션 ID를 Set 구조로 관리하면, 이상 징후 포착 시 해당 사용자의 모든 세션을 $O(1)$의 속도로 조회하고 일괄 삭제할 수 있어 대응 효율성이 극대화됩니다.드시 분리해야 합니다. 동일한 키를 사용하는 것은 보안을 무너뜨리는 지름길입니다.

관련 레시피