PHP 세션 충돌 문제와 해결책

프리터코더·2025년 5월 30일
0

php 문제 해결

목록 보기
47/79

PHP 애플리케이션에서 세션 충돌은 여러 사용자나 요청 간에 세션 데이터가 섞이거나 덮어써지는 심각한 문제입니다. 다음은 세션 충돌의 주요 원인과 해결책들입니다.

1. 세션 ID 고정 공격 방지

문제: 공격자가 세션 ID를 고정하여 사용자 세션을 탈취

해결책:

// 로그인 성공 시 세션 ID 재생성
function secureLogin($username, $password) {
    if (validateCredentials($username, $password)) {
        session_regenerate_id(true); // 기존 세션 파일 삭제
        $_SESSION['user_id'] = getUserId($username);
        $_SESSION['login_time'] = time();
        return true;
    }
    return false;
}

2. 세션 저장 경로 분리

문제: 여러 애플리케이션이 동일한 세션 저장소를 공유하여 충돌

해결책:

// 애플리케이션별 세션 저장 경로 설정
ini_set('session.save_path', '/tmp/myapp_sessions');
ini_set('session.name', 'MYAPP_SESSIONID');

// 또는 세션 시작 전에 설정
if (!is_dir('/tmp/myapp_sessions')) {
    mkdir('/tmp/myapp_sessions', 0755, true);
}
session_save_path('/tmp/myapp_sessions');
session_name('MYAPP_SESSIONID');
session_start();

3. 도메인별 쿠키 설정

문제: 여러 하위 도메인에서 세션 쿠키가 겹쳐서 충돌

해결책:

// 특정 도메인에만 쿠키 설정
session_set_cookie_params([
    'lifetime' => 3600,
    'path' => '/',
    'domain' => '.myapp.com', // 특정 도메인 지정
    'secure' => true,
    'httponly' => true,
    'samesite' => 'Strict'
]);

session_start();

4. 세션 잠금 처리

문제: 동시 요청에서 세션 데이터가 덮어써짐

해결책:

function safeSessionUpdate($callback) {
    session_start();
    
    // 세션 잠금을 위한 임시 파일 생성
    $lockFile = sys_get_temp_dir() . '/session_' . session_id() . '.lock';
    $lock = fopen($lockFile, 'w');
    
    if (flock($lock, LOCK_EX)) {
        try {
            $callback();
            session_write_close();
        } finally {
            flock($lock, LOCK_UN);
            fclose($lock);
            unlink($lockFile);
        }
    }
}

// 사용 예시
safeSessionUpdate(function() {
    $_SESSION['counter'] = ($_SESSION['counter'] ?? 0) + 1;
});

5. AJAX 요청에서 세션 관리

문제: 동시 AJAX 요청으로 인한 세션 데이터 손실

해결책:

// 읽기 전용 세션 처리
function startReadOnlySession() {
    session_start();
    session_write_close(); // 즉시 세션 잠금 해제
}

// API 엔드포인트에서 사용
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
    startReadOnlySession();
    // 세션 데이터 읽기만 수행
    echo json_encode(['user_id' => $_SESSION['user_id'] ?? null]);
}

6. 세션 데이터 검증

문제: 세션 데이터 무결성 검증 부족으로 인한 보안 취약점

해결책:

function validateSession() {
    if (!isset($_SESSION['user_id']) || !isset($_SESSION['login_time'])) {
        return false;
    }
    
    // 세션 만료 시간 체크
    if (time() - $_SESSION['login_time'] > 3600) {
        session_destroy();
        return false;
    }
    
    // IP 주소 검증 (선택적)
    if (isset($_SESSION['ip_address']) && $_SESSION['ip_address'] !== $_SERVER['REMOTE_ADDR']) {
        session_destroy();
        return false;
    }
    
    return true;
}

7. 커스텀 세션 핸들러

문제: 기본 파일 기반 세션의 한계로 인한 충돌

해결책:

class DatabaseSessionHandler implements SessionHandlerInterface {
    private $pdo;
    
    public function __construct($pdo) {
        $this->pdo = $pdo;
    }
    
    public function read($id) {
        $stmt = $this->pdo->prepare("SELECT data FROM sessions WHERE id = ? AND expires > NOW()");
        $stmt->execute([$id]);
        return $stmt->fetchColumn() ?: '';
    }
    
    public function write($id, $data) {
        $stmt = $this->pdo->prepare("REPLACE INTO sessions (id, data, expires) VALUES (?, ?, DATE_ADD(NOW(), INTERVAL 1 HOUR))");
        return $stmt->execute([$id, $data]);
    }
    
    public function destroy($id) {
        $stmt = $this->pdo->prepare("DELETE FROM sessions WHERE id = ?");
        return $stmt->execute([$id]);
    }
    
    // 기타 필수 메서드들...
}

// 세션 핸들러 등록
session_set_save_handler(new DatabaseSessionHandler($pdo));

8. 멀티탭 환경 세션 관리

문제: 동일 사용자의 여러 탭에서 세션 정보가 충돌

해결책:

// 탭별 고유 식별자 생성
function generateTabId() {
    return uniqid('tab_', true);
}

// 세션에 탭 정보 저장
if (!isset($_SESSION['tabs'])) {
    $_SESSION['tabs'] = [];
}

$tabId = $_POST['tab_id'] ?? generateTabId();
$_SESSION['tabs'][$tabId] = [
    'last_activity' => time(),
    'data' => $_SESSION['tabs'][$tabId]['data'] ?? []
];

// 비활성 탭 정리
foreach ($_SESSION['tabs'] as $id => $tab) {
    if (time() - $tab['last_activity'] > 1800) { // 30분
        unset($_SESSION['tabs'][$id]);
    }
}
profile
일용직 개발자. freetercoder@gmail.com

0개의 댓글