웹 애플리케이션을 개발하면서 세션(Session) 기반 로그인을 구현해본 경험은 누구나 있을 것이다. 사용자 인증 상태를 유지하기 위해 필수적인 세션이지만, 기본 설정 그대로 사용하는 개발자가 태반이다. 다만 세션 ID가 네트워크 상에서 유출되거나 탈취당했을 때 발생하는 보안 사고의 위험성을 제대로 아는 경우는 의외로 드물다.

실무에서 세션 ID를 탈취하는 Session Hijacking(세션 하이재킹)이나 세션 고정(Session Fixation) 공격이 발생하면 공격자는 비밀번호 없이도 타인의 계정에 로그인할 수 있게 된다. 이번에는 세션 탈취 공격의 작동 원리와 왜 발생하는지, 그리고 session_regenerate_id() 함수와 안전한 쿠키 옵션을 활용해 이를 어떻게 완벽하게 방어하는지 정리해서 소개하겠다.

 

세션 탈취와 세션 고정 공격의 원리

PHP는 기본적으로 사용자가 접속하면 브라우저에 PHPSESSID라는 쿠키를 발급한다. 서버는 이 쿠키에 담긴 고유 문자열(세션 ID)을 보고 접속자가 누구인지 식별한다. 문제점은 이 세션 ID만 손에 넣으면 서버는 그 사람이 진짜 사용자인지 공격자인지 구분할 수 없다는 사실이다.

공격 방식은 크게 두 가지로 나뉜다. 세션 탈취는 사용자가 이미 로그인한 상태에서 자바스크립트(XSS 공격)나 네트워크 패킷 감청을 통해 PHPSESSID 값을 빼앗는 방식이다. 반면 세션 고정은 공격자가 자신이 생성한 세션 ID를 미리 피해자에게 쿠키나 URL 파라미터로 주입한 뒤, 피해자가 해당 세션 ID로 로그인하면 그 세션을 그대로 점유하는 기법이다.

 

세션 보안 강화를 위한 3가지 필수 조치

PHP에서 세션 기반 공격을 방어하기 위해 적용해야 하는 핵심 기법은 다음과 같다.

 

1. 로그인 성공 시 세션 ID 재발급 (session_regenerate_id)

사용자가 인증에 성공했을 때 기존 사용하던 세션 ID를 버리고 완전히 새로운 세션 ID를 생성해야 한다. 이렇게 하면 로그인 전에 공격자가 주입해둔 세션 ID는 더 이상 유효하지 않게 되므로 세션 고정 공격이 완벽하게 차단된다.

 

2. 쿠키 보안 속성 설정 (HttpOnly, Secure, SameSite)

세션 ID가 저장되는 PHPSESSID 쿠키에 보안 속성을 부여해야 한다. HttpOnly 속성은 자바스크립트를 통한 document.cookie 접근을 막아 XSS 공격으로부터 세션 ID를 보호하며, Secure 속성은 HTTPS 암호화 통신에서만 쿠키가 전송되도록 제한한다.

 

3. 세션 바인딩 검증 (IP 및 User-Agent)

세션이 생성될 때 접속한 클라이언트의 IP 주소와 User-Agent 정보를 세션 데이터에 저장하고, 페이지 이동 시마다 현재 요청 정보와 일치하는지 검증한다. 갑자기 IP나 브라우저 정보가 변경되었다면 탈취된 세션으로 판단하여 즉시 세션을 파기한다.

 

비교 및 보안 속성 요약
보안 설정 / 함수주요 역할방어하는 공격 유형
session_regenerate_id(true)로그인 시 세션 ID 변경 및 이전 세션 파일 삭제세션 고정 (Session Fixation)
httponly = true자바스크립트로 세션 쿠키 접근 차단XSS 기반 세션 탈취
secure = trueHTTPS 통신에서만 세션 쿠키 전송네트워크 패킷 감청 (Man-in-the-Middle)
samesite = 'Strict' / 'Lax'타 사이트 간 요청 시 쿠키 전송 제한CSRF (Cross-Site Request Forgery)

 

실전 예제: 안전한 로그인 세션 처리

실무 환경에서 세션을 다룰 때 보안 설정이 누락된 코드와 안전하게 개선된 코드를 비교해보자.

 

✗ 잘못된 코드 (취약한 로그인 세션 처리)

대부분의 개발자가 단순하게 session_start() 후 세션 변수에 사용자 정보만 담는 방식으로 구현한다.

<?php
session_start();

// 로그인 인증 검증 (예시)
if ($user_id === 'admin' && $password === '1234') {
    // ✗ 기존 세션 ID를 그대로 유지한 채 로그인 처리
    $_SESSION['is_logged_in'] = true;
    $_SESSION['user_id'] = $user_id;
    
    echo "로그인 성공";
}
?>

이 코드에서는 로그인 전 사용하던 세션 ID가 로그인 후에도 그대로 유지된다. 공격자가 비로그인 상태의 세션 ID를 알고 있었다면, 피해자가 로그인하는 순간 공격자도 동일한 권한을 획득하게 된다.

 

✓ 올바른 코드 (보안 쿠키 설정 및 세션 재발급 적용)

session_start() 호출 전에 세션 쿠키 옵션을 설정하고, 인증 성공 시 session_regenerate_id(true)를 호출하여 안전하게 세션을 갱신한다.

<?php
// 1. 세션 쿠키 보안 옵션 설정 (session_start 전에 실행 필수)
session_set_cookie_params([
    'lifetime' => 0,             // 브라우저 종료 시 쿠키 만료
    'path' => '/',
    'domain' => '',
    'secure' => true,           // HTTPS 통신에서만 쿠키 전송
    'httponly' => true,         // 자바스크립트 접근 방지 (XSS 차단)
    'samesite' => 'Strict'      // CSRF 공격 방지
]);

session_start();

// 2. 로그인 인증 성공 시 처리
if ($is_authenticated) {
    // ✓ 세션 고정 공격 방지: 기존 세션 데이터를 지우지 않고 새 ID 발급
    // true 파라미터를 넘겨야 이전 세션 ID 파일이 서버에서 완전히 삭제됨
    session_regenerate_id(true);

    $_SESSION['is_logged_in'] = true;
    $_SESSION['user_id'] = $user_id;
    $_SESSION['user_ip'] = $_SERVER['REMOTE_ADDR'];
    $_SESSION['user_agent'] = $_SERVER['HTTP_USER_AGENT'];

    echo "안전하게 로그인되었습니다.";
}
?>

 

출력/동작 결과

로그인 시 브라우저의 개발자 도구(F12) 내 Application -> Cookies 항목을 확인하면, PHPSESSID 쿠키의 HTTPOnly 및 Secure 항목에 체크 표시가 활성화된다. 또한 로그인 실행 직후 PHPSESSID의 Value 값이 새로운 난수 문자열로 완전히 교체되는 것을 확인할 수 있다.

 

주의사항 및 흔한 실수

세션 보안을 적용할 때 개발자들이 자주 범하는 실수를 모아두었다.

✗ session_regenerate_id() 파라미터 누락
`session_regenerate_id()`를 인수 없이 호출하면 새 세션 ID만 발급될 뿐, 서버에 남아있는 예전 세션 파일이 삭제되지 않는다. 반드시 `session_regenerate_id(true)` 형태로 인자에 true를 전달해 기존 세션 데이터를 파기해야 한다.

✓ session_start() 호출 위치 미준수
`session_set_cookie_params()` 함수는 반드시 `session_start()`가 호출되기 이전에 실행되어야 정상 적용된다. 이미 세션이 시작된 후에 쿠키 파라미터를 변경하면 설정이 무시된다.

✗ HTTP 환경에서 Secure 옵션 사용
로컬 개발 환경(http://localhost)에서 `secure => true` 옵션을 켜두면 브라우저가 세션 쿠키를 저장하지 않아서 로그인 상태가 유지되지 않는다. 개발 환경에서는 SSL 적용 여부를 조건문으로 판별해 옵션을 분기 처리해야 한다.

 

정리

세션 보안은 웹 서비스 전체 권한 체계를 지키는 기본 중의 기본이다. 로그인 로직에 몇 줄의 보안 코드를 추가하는 작은 습관이 모여서 서비스 전체의 강력한 안전성을 만든다는 점을 잊지 말자. 로그인 처리 파일과 세션 설정 부분을 다시 점검하고 session_set_cookie_params()와 session_regenerate_id(true)를 바로 적용해보자. 세션 탈취 공격으로부터 사용자 계정을 완벽하게 보호할 수 있을 것이다.