GET POST 차이 — HTTPS인데도 비밀번호가 로그에 남는 이유

@JavaPark · 2026년 11월 13일 · 12 min read

GET POST 차이 커버 — GET 로그에는 /login?pw=coffee1234, POST 로그에는 /login, 주소 16,364B는 431, POST 본문 1MB는 200
GET POST 차이 커버 — GET 로그에는 /login?pw=coffee1234, POST 로그에는 /login, 주소 16,364B는 431, POST 본문 1MB는 200

안녕하세요, 자바파커입니다.

"GET은 조회, POST는 생성. 그리고 HTTPS 쓰면 둘 다 안전하다."

면접 준비할 때 이렇게 정리하셨다면, 하나가 빠져 있습니다.

로그인 폼을 GET으로 만들면, HTTPS를 써도 비밀번호가 서버 로그에 그대로 찍힙니다. 브라우저 주소창과 방문 기록에도 남습니다.

결론부터 말씀드리면, GET은 보낼 내용을 주소에 적고, POST는 본문(봉투)에 담습니다. HTTPS는 가는 길만 잠그고, 도착한 뒤 주소가 남는 곳까지는 지켜 주지 않습니다.

제 PC에서 작은 서버와 크롬(Chromium 151)으로 같은 로그인 폼을 GET과 POST로 보내 보고, 서버 로그에 무엇이 찍히는지 직접 확인했습니다. 이 장면은 영상으로도 정리했습니다.

GET POST 차이 영상 — 서버 로그의 pw=coffee1234에 빨간 형광펜, 상단 띠 'GET은 주소에 남고, POST는 봉투에 담긴다'
GET POST 차이 영상 — 서버 로그의 pw=coffee1234에 빨간 형광펜, 상단 띠 'GET은 주소에 남고, POST는 봉투에 담긴다'


GET POST 차이 한눈에 보기

GET POST
데이터 위치 URL 뒤(쿼리 스트링 ?id=…&pw=…) 요청 본문(body)
접속 로그 URL 전체가 남는다 메서드와 경로만 남는다
주소창·방문 기록·북마크 그대로 남는다 남지 않는다
크기 서버 헤더 한도에 걸린다 (실측: Node 기본 16KB) 본문 한도까지 (실측: 1MB 통과)
의미 (RFC 9110) 안전(safe)·멱등(idempotent), 캐시 가능 안전하지 않음, 멱등 아님
비유 카운터 칠판에 주문 적기 주문서를 봉투에 넣어 건네기

직접 확인했습니다 — 서버 로그에 무엇이 찍히나

실험 방법

Node 기본 http 모듈로 서버를 띄우고, 흔한 접속 로그처럼 메서드와 URL만 남기게 했습니다. 같은 로그인 폼을 method=get과 method=post로 하나씩 만들어 Playwright 크롬으로 제출했습니다. 외부 네트워크 없이 127.0.0.1에서만 돌았고, 3회 모두 결과가 같았습니다.

const server = http.createServer((req, res) => {
  log.push(`${req.method} ${req.url}`) // 접속 로그: 메서드 + URL
  // ...
})
// <form method=get action=/login><input name=id value=ara><input name=pw value=coffee1234></form>
// <form method=post action=/login> ... 같은 입력 ... </form>

결과

측정 GET POST
서버 접속 로그 GET /login?id=ara&pw=coffee1234 POST /login
브라우저 주소창 /login?id=ara&pw=coffee1234 /login
주소 16,363바이트 200
주소 16,364바이트 431 Request Header Fields Too Large
본문 1MB(1,048,576바이트) 200, 전부 수신

HTTPS인데 왜 로그에 남을까 — 길만 잠근다

HTTPS는 브라우저와 서버 사이의 길을 암호화합니다. URL의 경로와 쿼리(/login?pw=…)도 길 위에서는 암호화됩니다. 그래서 같은 와이파이를 쓰는 사람이 엿봐도 비밀번호는 안 보입니다.

문제는 양 끝입니다.

  • 서버 쪽: TLS는 서버(또는 앞단 프록시)에서 풀립니다. 그 뒤 웹 서버·로드밸런서·프록시가 접속 로그를 남기는데, 로그에는 보통 요청 URL 전체가 들어갑니다. 실측의 GET /login?id=ara&pw=coffee1234가 그 모습입니다.
  • 브라우저 쪽: 주소창, 방문 기록, 북마크, 자동 완성에 URL이 남습니다. 공용 PC라면 다음 사람이 볼 수 있습니다.
  • 다른 사이트로: 그 페이지에서 외부 링크를 누르면 Referer 헤더로 URL이 넘어갈 수 있습니다.

영상의 비유로는 배달 가방의 자물쇠입니다. 가는 길에서는 아무도 못 열지만, 카운터에 도착해 칠판에 적힌 주문은 누구나 봅니다. OWASP도 쿼리 스트링에 민감 정보를 넣는 것을 대표적인 정보 노출 원인으로 꼽습니다.

그렇다고 POST가 암호화인 것은 아닙니다. HTTPS가 없으면 POST 본문도 평문으로 갑니다. 그리고 앱이 요청 본문을 일부러 로그에 남기면 POST도 남습니다. "비밀번호는 POST + HTTPS + 본문 로그 끄기"가 한 세트입니다.

주소 길이 한계 — 16,364바이트에서 431

GET은 데이터를 주소에 붙이니, 보낼 데이터가 커지면 주소가 길어집니다. Node의 기본 설정(http.maxHeaderSize = 16,384바이트)은 요청 줄과 헤더를 합친 크기를 제한합니다. 실측에서 주소가 16,363바이트일 때는 200, 16,364바이트부터 431이 났습니다(나머지 헤더 몇 바이트와 합쳐 한도를 넘는 지점).

같은 서버에 POST 본문 1MB는 문제없이 들어갔습니다.

이 숫자는 Node 기본값 기준입니다. nginx, 클라우드 로드밸런서, 브라우저마다 한도가 다릅니다. 핵심은 "GET은 주소 한도에, POST는 본문 한도에 걸린다"는 구조입니다. 참고로 Express의 express.json()은 본문 한도가 기본 100kb라 프레임워크를 쓰면 POST도 따로 한도가 있습니다.

그럼 GET은 언제 쓰나 — 멱등성과 캐시

"GET = 조회"가 틀린 말은 아닙니다. RFC 9110은 GET을 안전(safe)한 메서드로 정의합니다. 서버 상태를 바꾸지 않는다는 약속입니다. 그래서:

  • 여러 번 보내도 결과가 같다(멱등). 새로고침해도 문제가 없습니다.
  • 캐시할 수 있다. 브라우저와 CDN이 응답을 저장해 둡니다.
  • 링크로 공유할 수 있다. 검색 결과 ?q=쿠키처럼 주소 자체가 의미가 있습니다.

POST는 반대입니다. 두 번 보내면 주문이 두 번 들어갈 수 있어서, 새로고침하면 브라우저가 "양식을 다시 제출할까요?"라고 묻습니다.

정리하면, 공유돼도 괜찮고 반복돼도 괜찮은 조회는 GET, 상태를 바꾸거나 민감한 값을 보내면 POST입니다.

면접에서 GET POST 차이를 답하는 법

한 줄 답변

"GET은 데이터를 URL 쿼리에 담아 조회에 쓰고, 안전하고 멱등이라 캐시할 수 있습니다. POST는 데이터를 본문에 담아 상태를 바꿀 때 씁니다. URL은 HTTPS여도 서버 로그와 방문 기록에 남기 때문에 비밀번호 같은 민감한 값은 POST로 보냅니다."

꼬리 질문에 대비할 세 가지

  1. "HTTPS면 GET도 안전하지 않나요?" → 길 위는 안전합니다. 하지만 접속 로그, 방문 기록, Referer처럼 URL이 남는 곳은 HTTPS가 지켜 주지 않습니다.
  2. "GET에 본문을 넣으면요?" → 스펙상 의미가 정해져 있지 않아 서버·프록시가 무시하거나 거부할 수 있습니다. 쓰지 않습니다.
  3. "PUT, PATCH는요?" → 둘 다 수정입니다. PUT은 통째로 바꾸고 멱등, PATCH는 일부만 바꿉니다.

자주 묻는 것

검색어처럼 민감하지 않은 값도 POST로 보내야 하나요?

아닙니다. 검색은 GET이 맞습니다. 주소를 공유하고, 뒤로 가기·새로고침·캐시가 자연스럽게 됩니다. 민감한 값이 들어갈 때만 POST로 옮깁니다.

로그에 쿼리 스트링을 아예 안 남기면 GET도 괜찮지 않나요?

서버 로그는 막을 수 있지만, 브라우저 방문 기록과 Referer는 서버가 통제하기 어렵습니다. 그리고 중간 프록시나 CDN 로그까지 모두 설정해야 합니다. 처음부터 POST로 보내는 편이 간단하고 확실합니다.

URL 길이 한계는 브라우저마다 다른가요?

다릅니다. 이 글의 16,364바이트는 Node 24 기본 설정에서 서버가 거절한 지점입니다. 브라우저는 이보다 훨씬 긴 주소를 만들 수 있어서, 보통은 서버나 중간 장비의 한도에 먼저 걸립니다.


정리

  • GET은 주소에 남고, POST는 봉투(본문)에 담긴다.
  • 실측: GET 로그인 → 로그에 GET /login?id=ara&pw=coffee1234, POST → POST /login.
  • HTTPS는 가는 길만 잠근다. 서버 로그·방문 기록·Referer에 남는 URL은 못 지킨다.
  • 주소는 16,364바이트부터 431(Node 기본), 본문 1MB는 통과.
  • GET은 안전·멱등·캐시 가능한 조회에, 민감한 값과 상태 변경은 POST로.

로그인 상태가 어떻게 유지되는지는 쿠키 세션 차이에서, 응답 코드 431·401·403은 HTTP 응답 코드 정리에서 이어서 볼 수 있습니다.

여러분 서비스의 접속 로그에는 쿼리 스트링이 그대로 남고 있나요? 한 번 열어 보고 댓글로 알려 주세요.

참고 자료

퀴즈

HTTPS를 쓰는 사이트의 로그인 폼이 GET으로 비밀번호를 보냅니다. 비밀번호가 실제로 노출되기 쉬운 곳은?

이 문제가 쉬웠다면 — 백엔드 CS 능력고사 20문제→
그림으로 말하는 백엔드 CS 20 무료 샘플 표지

판매 중 · 14,900원 · 무료 샘플 15쪽

그림으로 말하는 백엔드 CS 20

백엔드 CS 20문항을 면접에서 60초로 설명하는 연습. 샘플 5문항부터 받아 보세요.

→
@JavaPark
AI 시대의 개발자 도구, 실전 경험을 공유합니다