4.1 세션통제

개요

세션(Session)은 사용자가 웹 애플리케이션에 로그인한 후 로그아웃할 때까지 인증 상태를 유지하는 메커니즘입니다. 서버는 각 사용자를 식별하기 위해 고유한 세션 ID를 발급하고, 사용자의 웹 브라우저는 이 ID를 쿠키 등에 저장하여 이후 요청 시마다 서버에 전송합니다.

세션 통제는 이러한 세션 ID를 안전하게 생성, 관리, 검증하고 세션의 생명주기(생성, 유지, 만료, 종료)를 적절히 제어하는 것을 의미합니다. 세션 통제가 부적절하면 공격자가 다른 사용자의 세션 ID를 탈취하거나(세션 하이재킹) 예측하여 해당 사용자로 위장하거나, 공격자가 미리 알고 있는 세션 ID를 사용자에게 부여하는(세션 고정) 등의 공격이 가능해집니다.

이 기준은 안전하고 신뢰할 수 있는 세션 관리를 통해 비인가된 접근을 방지하고 사용자 인증 상태를 보호하기 위한 필수적인 보안 요구사항을 정의합니다.

보안 대책

  • - 강력하고 예측 불가능한 세션 ID 사용: 세션 ID는 암호학적으로 안전한 난수 생성기(CSPRNG)를 사용하여 충분한 길이(최소 128비트 권장)로 생성하여 추측이 불가능하도록 합니다.
  • - 안전한 세션 ID 전송 및 관리:
    • 세션 ID는 반드시 HTTPS(TLS/SSL)를 통해 암호화되어 전송되어야 합니다.
    • 세션 ID를 URL 파라미터에 포함하여 전송하는 것은 로그 노출, Referer 헤더 노출 등의 위험이 있으므로 절대 금지합니다.
    • 세션 쿠키에는 `HttpOnly` 속성을 설정하여 클라이언트 측 스크립트(JavaScript)가 쿠키에 접근하는 것을 차단합니다 (XSS를 통한 세션 탈취 방지).
    • 세션 쿠키에는 `Secure` 속성을 설정하여 HTTPS 연결에서만 쿠키가 전송되도록 강제합니다.
    • 세션 쿠키에는 `SameSite` 속성(Lax 또는 Strict 권장)을 설정하여 CSRF 공격을 완화합니다.
  • - 세션 타임아웃 설정: 사용자가 일정 시간 동안 활동이 없을 경우(비활성 타임아웃, 예: 30분)와 로그인 후 최대 허용 시간(절대 타임아웃, 예: 8시간)이 경과하면 세션이 자동으로 만료되도록 설정합니다.
  • - 로그인 성공 시 세션 ID 재발급: 사용자가 성공적으로 로그인하면, 이전 세션 ID를 무효화하고 새로운 세션 ID를 발급하여 세션 고정(Session Fixation) 공격을 방지합니다.
  • - 로그아웃 시 세션 무효화: 사용자가 로그아웃을 요청하면 서버 측에서 해당 세션을 명확하게 무효화(파기)하고, 클라이언트 측의 세션 쿠키도 만료시킵니다.
  • - 동시 세션 제한: 필요 시, 한 사용자가 동시에 유지할 수 있는 세션의 수를 제한하여 계정 공유나 탈취 시 피해를 줄일 수 있습니다.

코드 예시 (Java - Servlet 세션 관리)

안전한 세션 관리는 웹 프레임워크(Spring Security, Apache Shiro 등)를 사용하는 것이 권장되지만, 기본적인 Servlet API를 사용한 예시는 다음과 같습니다.

안전한 코드 (로그인 시 세션 ID 재발급 및 로그아웃):

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.http.Cookie;

public class SessionManagementServlet extends HttpServlet {

    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        
        String action = request.getParameter("action");

        if ("login".equals(action)) {
            // ... 사용자 인증 로직 (아이디/비밀번호 검증) ...
            boolean isAuthenticated = performAuthentication(request.getParameter("username"), request.getParameter("password"));

            if (isAuthenticated) {
                // 1. 기존 세션 무효화 (세션 고정 방지)
                HttpSession oldSession = request.getSession(false);
                if (oldSession != null) {
                    oldSession.invalidate();
                }
                
                // 2. 새로운 세션 생성 및 세션 ID 발급
                HttpSession newSession = request.getSession(true); // true: 없으면 새로 생성
                
                // 3. 세션 타임아웃 설정 (web.xml 또는 코드에서 설정)
                newSession.setMaxInactiveInterval(30 * 60); // 30분 비활성 타임아웃 (초 단위)
                
                // 4. 세션에 사용자 정보 저장
                newSession.setAttribute("userId", request.getParameter("username"));
                newSession.setAttribute("userRole", "user"); // 예시 역할 정보
                
                // 5. 안전한 쿠키 속성 설정 (Servlet 3.0 이상, 또는 필터/프레임워크 사용 권장)
                // response.addHeader("Set-Cookie", "JSESSIONID=" + newSession.getId() + "; Path=/; HttpOnly; Secure; SameSite=Lax");
                // 서블릿 컨테이너(Tomcat 등) 설정(web.xml, context.xml)에서 쿠키 속성을 설정하는 것이 더 일반적임

                response.sendRedirect("/welcome"); // 로그인 성공 페이지로 이동
            } else {
                // 로그인 실패 처리
                response.sendRedirect("/login?error=true");
            }
        } else if ("logout".equals(action)) {
            // 로그아웃 처리
            HttpSession session = request.getSession(false);
            if (session != null) {
                // 6. 서버 측 세션 무효화
                session.invalidate(); 
            }
            
            // 7. 클라이언트 측 세션 쿠키 만료 (선택적이지만 권장)
            Cookie sessionCookie = new Cookie("JSESSIONID", ""); // JSESSIONID는 예시, 실제 쿠키 이름 사용
            sessionCookie.setMaxAge(0); // 즉시 만료
            sessionCookie.setPath("/"); // 쿠키 경로 설정 중요
            response.addCookie(sessionCookie);

            response.sendRedirect("/login?logout=true"); // 로그아웃 완료 페이지로 이동
        }
    }
    
    private boolean performAuthentication(String username, String password) {
        // 실제 인증 로직 구현 (DB 조회 등)
        return "testuser".equals(username) && "password123".equals(password); // 예시
    }
}
                        

Python(Flask-Session, Django Sessions), JavaScript(Node.js - express-session), C#(ASP.NET Core Session State), PHP(세션 함수) 등 대부분의 웹 환경에서는 세션 관리를 위한 내장 기능이나 라이브러리를 제공합니다. 이러한 기능을 사용하고, `HttpOnly`, `Secure`, `SameSite`와 같은 쿠키 보안 속성을 올바르게 설정하는 것이 중요합니다.