로그인 할 때는 GET?, POST?
카카오 로그인에 GET을 사용하다 POST로 전환해야 하는 이유를 보안 취약점 관점에서 분석했다.
지금 서비스의 로그인 기능이 카카오로그인만 있는 상태. 근데 그 카카오로그인은 GET 으로 되어 있음.
로그인기능을 평소에 아무렇지 않게 POST 로 사용해왔는데, POST로 바꿔야 할 근거를 찾는 동시에 각각의 메서드들을 한 번 더 살펴봄
GET / POST 구조도(흐름도) 및 특징
아래 구조도는 로그인 요청 시 GET과 POST가 각각 어떻게 동작하고 어디에 위험/장점이 있는지 한눈에 보이도록 정리한 것입니다.
GET 구조도
[사용자 브라우저]
|
| GET /login?userId=alice&password=secret
| (데이터가 URL 쿼리스트링에 포함)
v
[네트워크 / 프록시 / 캐시 등]
|
v
[서버]
- 웹서버 접근 로그에 전체 URL 기록
- 리버스프록시/로깅 레이어에 URL 기록
- 브라우저: 방문기록(history)에 URL 저장
- 공유/스크린샷/백업 등으로 민감정보 유출 가능
GET의 핵심 특징
- 데이터가 URL에 노출되어 브라우저 히스토리, 서버 로그, 프록시 로그, 캐시 등에 기록된다.
- URL 길이 제한과 인코딩 이슈로 긴 데이터나 복잡한 인증 흐름에 취약.
- 안전하지 않은 링크 공유/리디렉션 시 민감 정보가 쉽게 유출될 수 있음.
- 의도된 목적: 리소스 조회 (부작용 없는 요청, 캐시 친화적).
POST 구조도
[사용자 브라우저]
|
| POST /login
| Content-Type: application/json
| Body: {"userId":"alice","password":"secret"}
v
[네트워크 (TLS 권장)]
|
v
[서버]
- 요청 본문(body)에서 데이터 파싱
- 기본적으로 URL에 민감정보가 남지 않음
- 서버 접근 로그에 URL만 기록되고, 본문은 별도로 로깅하지 않도록 구성 가능
- HTTPS 사용 시 전송 중 데이터 암호화
POST의 핵심 특징 (로그인에 적합)
- 민감 데이터가 요청 본문(body) 에 포함되어 URL에 노출되지 않음.
- 서버 로그에 URL만 남고, 본문은 기본 설정상 로그에 남지 않도록 제어 가능(로깅 정책 필요).
- 데이터 길이 제한이 사실상 없음(실무상 큰 제약 X).
- 의도된 목적: 리소스 생성/변경, 민감 정보 제출에 적합.
- 반드시 HTTPS(TLS)와 함께 사용해야 전송 중 도청을 막을 수 있음.
문제의 원인: GET 요청의 치명적인 한계
로그인 정보가 URL에 노출되는 것은 웹 보안의 가장 기본적인 원칙을 위반하는 것입니다. 다음 표는 왜 GET이 로그인에 부적합한지 명확하게 보여줍니다.
| 구분 | GET | POST |
|---|---|---|
| 목적 | 서버의 리소스 조회 (Read) | 서버의 리소스 생성/변경 (Create/Update) |
| 데이터 전송 위치 | URL의 쿼리스트링 | HTTP Request Body |
| URL 노출 여부 | 노출됨 (예: /login?id=...&pw=...) | 노출되지 않음 |
| 보안 | 민감 데이터 전송에 매우 취약 | 민감 데이터 전송에 적합 |
| 데이터 길이 제한 | 존재함 (브라우저/서버별 상이) | 제한 없음 |
GET 요청의 URL은 사용자의 브라우저 방문 기록에 그대로 저장되며, 서버의 접근 로그에도 기록됩니다. 이는 마치 "현관문 비밀번호를 문 앞에 크게 써 붙여놓는 것"과 같습니다. 누구나 해당 기록에 접근하면 비밀번호를 탈취할 수 있어 매우 위험합니다.
캐시단계에서도 문제가 되는데,
GET은 브라우저, CDN, 서버 등 많은 환경에서 자동으로 캐시가 된다. 이때 URL에 로그인 정보가 포함되어 있다면, 브라우저 히스토리나 캐시, 중간 프록시 서버, CDN 등 다양한 곳에 민감한 정보가 저장될 수 있어, 정보 유출 위험이 매우 크다. 따라서 로그인과 같은 민감 데이터를 전송할 때는 POST처럼 요청 본문(body)에 데이터를 담는 방식이 권장된다.
웹 캐시 기만(Web Cache Deception) 공격
실제 공격 기법:
-
공격자가 로그인 페이지 URL 뒤에 **가짜 파일 확장자(.css, .js 등)**를 붙여 요청:
https://example.com/login?userId=alice&password=1234.css- 서버는 URL에
.css가 붙었다고 “정적 리소스”로 인식하고, 캐시 가능 응답으로 처리.
- 서버는 URL에
-
CDN/프록시 서버가 해당 응답을 캐싱:
- 이때 응답 본문에는 민감 정보가 그대로 포함됨.
-
다른 사용자가 동일한 URL을 요청:
- CDN 캐시에서 바로 응답을 돌려줌 → 공격자가 민감 정보 획득 가능.
즉, CDN이 URL 기반 캐싱을 할 때 민감 정보가 URL에 있으면 누구나 접근 가능하게 되어 유출되는 구조입니다.
해결 방안: 로그인 API를 POST로 전환
서버측 고려사항 (권장 체크리스트)
- 로그인 엔드포인트를 GET → POST로 변경하고, 기존 GET 엔드포인트는 폐기하거나 405로 응답하도록 설정.
- 서버 로그(웹서버, 프록시, APM 등)에서 요청 본문(body)이 기록되지 않도록 로깅 정책 검토/수정.
- HTTPS (TLS) 적용 확인 — POST라도 TLS 없이는 전송 중 탈취 위험.
- CSRF 방어: 세션 기반 인증을 사용하는 경우 CSRF 토큰 적용 검토(소셜 OAuth 등 토큰 기반은 해당 상황에 맞게).
- 입력값 검증 및 실패 응답 시 민감 정보가 노출되지 않도록 메시지 표준화.
- 기존 카카오 로그인 연동(Callback URL 등)은 OAuth 규약대로 동작하는지 확인 — 내부 로그인(API에 직접 id/pw 전달)과 혼동하지 않도록 문서화.
기대 효과
- URL을 통한 정보 유출 원천 차단: 브라우저 방문 기록, 서버 로그, 그리고 URL 공유나 캐싱으로 인한 비밀번호 유출 위험을 크게 감소.
- 웹 표준 및 보안 가이드라인 준수: 로그인과 같은 민감한 데이터 제출에 POST를 사용하는 것은 전 세계적인 웹 표준이자 기본 보안 원칙. 이를 준수하면 서비스 신뢰성 향상.
END OF ARTICLE