HTTP는 왜 인증 방식이 필요한가
HTTP는 본래 무상태(stateless) 프로토콜입니다. 서버는 이전 요청을 기억하지 못합니다.
사용자가 로그인 후 다음 페이지로 이동하면 서버 입장에서는 그 사용자가 누구인지 알 수 없습니다.
이 문제를 해결하기 위해 서버가 "로그인된 사용자"라는 상태를 유지하는 방식이 필요했고, 그래서 세션과 토큰이 등장했습니다.
1. 세션
세션 기반 인증은 서버가 사용자 상태를 직접 저장하는 방식입니다.
동작 방식
- 사용자가 ID와 비밀번호로 로그인합니다.
- 서버는 인증에 성공하면 세션 ID를 생성하고 서버 메모리(또는 Redis 같은 저장소)에 저장합니다.
- 서버는 클라이언트에게 세션 ID를 쿠키로 전달합니다.
- 이후 모든 요청에서 브라우저는 자동으로 쿠키를 함께 보냅니다.
- 서버는 쿠키에 담긴 세션 ID로 저장소를 조회하여 사용자를 식별합니다.
장점
- 서버에서 세션을 직접 관리하므로 강제 로그아웃이 쉽습니다.
- 세션 ID 자체에는 의미가 없어 노출되어도 정보 유출이 적습니다.
- 구현이 비교적 단순하고 검증된 방식입니다.
단점
- 서버가 모든 세션을 저장해야 하므로 사용자가 많아지면 메모리 부담이 커집니다.
- 서버 확장 시 세션을 공유할 별도 저장소가 필요합니다.
- 모바일 앱이나 외부 API와 연동할 때 쿠키 기반이라 처리하기 번거롭습니다.
2. 토큰
토큰 기반 인증은 서버가 상태를 저장하지 않고, 클라이언트가 인증 정보를 토큰 형태로 들고 다니는 방식입니다. 대표적으로 JWT(JSON Web Token)가 있습니다.
동작 방식
- 사용자가 ID와 비밀번호로 로그인합니다.
- 서버는 인증 성공 시 토큰을 생성하여 클라이언트에게 전달합니다.
- 클라이언트는 토큰을 로컬 스토리지나 쿠키에 저장합니다.
- 이후 요청 시 Authorization 헤더에 토큰을 담아 전송합니다.
- 서버는 토큰의 서명을 검증하여 사용자를 식별합니다.
장점
- 서버가 상태를 저장하지 않아 확장에 유리합니다.
- 토큰 안에 사용자 정보가 있어 별도 조회가 필요 없습니다.
- 모바일, 웹, 외부 서비스 등 다양한 클라이언트에서 사용하기 좋습니다.
단점
- 한번 발급된 토큰은 만료 전까지 무효화하기 어렵습니다.
- 토큰에 정보가 담겨 있어 길이가 길고 매 요청마다 전송 부담이 있습니다.
- 토큰이 탈취되면 만료 전까지 그대로 사용될 수 있습니다.
3. 세션 기반 인증의 보안 고려사항
3.1 세션 하이재킹
공격자가 세션 ID를 탈취하여 사용자를 가장하는 공격입니다. HTTPS를 적용하여 통신 구간에서 세션 ID가 노출되지 않도록 해야 합니다.
3.2 CSRF (Cross-Site Request Forgery)
사용자가 로그인된 상태에서 악의적인 사이트에 접속하면, 그 사이트가 사용자 권한으로 요청을 보내는 공격입니다. 쿠키가 자동으로 전송되는 특성을 악용합니다.
대응 방법
- CSRF 토큰을 발급하여 요청마다 검증합니다.
- SameSite 쿠키 속성을 Strict 또는 Lax로 설정합니다.
- 중요한 요청은 재인증을 요구합니다.
3.3 세션 고정 공격
공격자가 미리 발급받은 세션 ID를 피해자가 사용하도록 유도하는 공격입니다. 로그인 성공 후 반드시 새로운 세션 ID를 발급해야 합니다.
3.4 쿠키 보안 속성
쿠키에는 다음 속성을 반드시 설정해야 합니다.
- HttpOnly: 자바스크립트에서 쿠키 접근을 차단하여 XSS 피해를 줄입니다.
- Secure: HTTPS 통신에서만 쿠키를 전송합니다.
- SameSite: 크로스 사이트 요청에서 쿠키 전송을 제한합니다.
4. 토큰 기반 인증의 보안 고려사항
4.1 XSS (Cross-Site Scripting)
토큰을 로컬 스토리지에 저장하면 자바스크립트로 접근이 가능하므로 XSS 공격에 취약합니다. 사용자 입력값에 대한 적절한 이스케이프 처리가 필수입니다.
HttpOnly 쿠키에 토큰을 저장하는 방식도 고려할 수 있습니다.
4.2 토큰 탈취와 만료 관리
토큰이 탈취되면 만료 전까지 그대로 사용될 수 있습니다. 이를 완화하기 위해 다음을 고려합니다.
- Access Token의 만료 시간을 짧게 설정합니다 (예: 15분~1시간).
- Refresh Token을 별도로 발급하여 Access Token을 재발급합니다.
- Refresh Token은 더 안전한 곳에 저장하고 만료 시간을 길게 설정합니다.
4.3 서명 검증
토큰의 서명 알고리즘과 비밀키 관리가 중요합니다.
- 비밀키는 충분히 길고 복잡해야 하며 외부에 노출되면 안 됩니다.
- 알고리즘을 None으로 설정하는 공격을 막기 위해 서버에서 허용 알고리즘을 명시합니다.
- 가능하면 비대칭 키 방식(RS256)을 사용합니다.
4.4 민감 정보 미포함
JWT의 Payload는 Base64로 인코딩될 뿐 암호화되지 않습니다. 따라서 비밀번호나 주민번호 같은 민감 정보를 절대 포함하면 안 됩니다.
4.5 토큰 무효화 전략
발급된 토큰을 즉시 무효화하기 어렵다는 단점을 보완하기 위해 다음 방법을 사용합니다.
- 블랙리스트를 운영하여 무효화된 토큰을 별도로 관리합니다.
- 짧은 만료 시간과 Refresh Token 조합으로 노출 시간을 최소화합니다.
- 비밀번호 변경이나 로그아웃 시 모든 Refresh Token을 폐기합니다.