개념
프록시가 답을 못 주는 순간
앞 레슨에서 프록시로 트래픽을 보고 조작하는 법을 익혔다. 대부분의 API 문제는 거기서 끝난다. 그런데 프록시가 아무 도움이 안 되는 상황이 있다.
| 증상 | 프록시로 안 되는 이유 |
|---|---|
| 앱이 인증서 피닝을 써서 프록시를 거부한다 | 트래픽 자체가 안 흐른다 |
| "가끔" 연결이 끊긴다 | 요청 자체가 성립하지 않아 목록에 안 뜬다 |
| HTTP가 아닌 통신(gRPC 스트림, WebSocket, DB, MQTT) | 프록시가 다루는 계층이 아니다 |
| 서버에서만 재현된다 | 서버에 GUI 프록시를 띄울 수 없다 |
| 방화벽·라우팅 문제로 의심된다 | 연결 이전 단계의 문제다 |
공통점은 "요청이 성립하기 전 또는 바깥"에서 문제가 난다는 것 이다. 모듈 9(레슨 6)에서 배운 DNS·TCP/IP·포트 지식이 여기서 도구를 만난다.
이 레슨의 목표는 패킷 분석 전문가가 되는 것이 아니다. QA가 원인을 한 단계 좁혀 "네트워크 계층 문제로 보인다"까지 말할 수 있게 되는 것 이 목표다. 그 한 단계가 인프라팀과의 대화를 완전히 바꾼다.
두 도구의 역할 분담
tcpdump 터미널에서 캡처한다. 서버·CI·원격 장비에서 쓴다.
│ GUI가 없는 곳에서 유일한 선택지다.
│
└─▶ .pcap 파일 ──▶ Wireshark 받아서 분석한다. GUI로 읽는다.
필터·통계·흐름 추적이 강하다.실무의 정석 조합 은 이것이다 — 서버에서 tcpdump로 캡처해 파일로 남기고, 그 파일을 내 PC로 가져와 Wireshark로 분석한다. 서버에 Wireshark를 설치할 일은 거의 없다.
tcpdump — 캡처하는 쪽
기본 형태는 단순하다.
# eth0 인터페이스에서 80·443 포트 트래픽을 파일로 저장
sudo tcpdump -i eth0 -w capture.pcap 'port 80 or port 443'
# 특정 호스트와의 통신만
sudo tcpdump -i any -w capture.pcap 'host api.example.com'
# 화면에서 바로 보기 (-n: 이름 해석 안 함, 빠르다)
sudo tcpdump -i any -n 'port 443'QA가 알아둘 옵션은 몇 개 안 된다.
| 옵션 | 의미 | 왜 필요한가 |
|---|---|---|
-i any | 모든 인터페이스 | 어느 인터페이스인지 모를 때 |
-w 파일 | 파일로 저장 | Wireshark로 넘기려면 필수 |
-n | DNS 역조회 안 함 | 캡처가 느려지는 것을 막는다 |
-s 0 | 패킷 전체 저장 | 잘린 패킷은 분석이 안 된다 |
-C 100 -W 5 | 100MB씩 5개 순환 | 장시간 캡처의 필수 옵션 |
-c 1000 | 1,000개만 잡고 종료 | 짧게 확인할 때 |
-C·-W 조합이 실무에서 중요하다. "가끔 발생하는" 문제를 잡으려면
몇 시간을 켜둬야 하는데, 옵션 없이 두면 디스크가 가득 찬다. 순환 저장으로
최근 N개 파일만 남긴다.
캡처 필터와 디스플레이 필터는 다르다 — 이걸 헷갈리면 계속 막힌다.
| 캡처 필터(tcpdump·Wireshark 캡처 시) | 디스플레이 필터(Wireshark 분석 시) | |
|---|---|---|
| 적용 시점 | 잡을 때 — 안 잡힌 건 영원히 없다 | 잡은 것 중에서 보여줄 것만 |
| 문법 | BPF (port 443, host x) | Wireshark 문법 (tcp.port == 443) |
| 실수하면 | 필요한 패킷을 못 잡는다 | 다시 필터만 바꾸면 된다 |
캡처 필터는 넓게, 디스플레이 필터로 좁힌다. 처음에는 host 정도만
걸고 넓게 잡는 편이 안전하다.
Wireshark — 분석하는 쪽
파일을 열면 패킷 수만 개가 쏟아진다. 여기서 필요한 것은 디스플레이 필터 다. QA가 쓸 것은 열 개 남짓이다.
ip.addr == 10.0.1.5 특정 IP와 오간 것
tcp.port == 443 포트
http HTTP만
tls.handshake.type == 1 TLS Client Hello (연결 시작)
tcp.flags.reset == 1 RST — 연결이 강제로 끊긴 지점
tcp.analysis.retransmission 재전송 — 네트워크 불안정 신호
tcp.analysis.flags TCP 이상 징후 전체
dns DNS 질의·응답
frame contains "orderId" 내용에 특정 문자열 포함
http.response.code >= 500 5xx 응답만tcp.flags.reset == 1 과 tcp.analysis.retransmission 두 개만
알아도 절반은 해결된다. "연결이 끊긴다", "가끔 느리다"의 직접 증거이기
때문이다.
메뉴에서 알아둘 것도 셋뿐이다.
- Statistics → Conversations — 어느 상대와 얼마나 주고받았는지. 예상 밖의 서버와 통신하고 있는지 확인할 때
- Statistics → Protocol Hierarchy — 프로토콜 비중. "이게 전부 TLS인가, 아니면 평문이 섞여 있나"
- 우클릭 → Follow → TCP Stream — 한 연결의 대화를 처음부터 끝까지 이어서 본다. 가장 자주 쓰게 된다
읽어야 할 세 가지 패턴
패킷을 다 이해할 필요는 없다. QA가 알아볼 패턴은 셋이다.
1) 연결이 안 맺어진다 — 핸드셰이크가 안 끝남
정상적인 TCP 연결은 세 단계로 시작한다.
정상
클라이언트 ── SYN ──▶ 서버
클라이언트 ◀─ SYN,ACK ── 서버
클라이언트 ── ACK ──▶ 서버 → 연결 성립
문제 A: SYN만 반복
클라이언트 ── SYN ──▶ (응답 없음)
클라이언트 ── SYN ──▶ (응답 없음) → 방화벽 차단, 잘못된 IP/포트,
클라이언트 ── SYN ──▶ (응답 없음) 서버가 안 떠 있음
문제 B: SYN에 RST로 응답
클라이언트 ── SYN ──▶ 서버
클라이언트 ◀─── RST ── 서버 → 그 포트에 아무도 안 듣고 있음A와 B의 구분이 실무에서 값을 한다. A는 패킷이 사라진 것(방화벽· 라우팅)이고, B는 서버까지 도달했는데 거절당한 것(프로세스 미기동·포트 불일치)이다. 원인 범위와 담당 팀이 다르다.
2) 연결은 됐는데 중간에 끊긴다 — RST
... 정상 통신 ...
클라이언트 ◀─── RST ── 서버 → 서버가 연결을 끊었다RST가 어느 쪽에서, 언제 나왔는지가 단서다. 흔한 원인들이다.
| RST 발생 지점 | 흔한 원인 |
|---|---|
| 일정 시간 무통신 후 | 유휴 타임아웃(로드밸런서·방화벽) |
| 대용량 전송 중 | 크기 제한, 타임아웃 |
| 특정 요청에서만 | 서버 애플리케이션이 예외로 연결 종료 |
| TLS 핸드셰이크 직후 | 인증서·프로토콜 버전 불일치 |
"가끔 연결이 끊깁니다"라는 리포트에 RST 발생 시점 정보가 붙으면 인프라팀이 볼 곳이 정해진다.
3) 느리다 — 재전송과 지연
tcp.analysis.retransmission 이 많이 보이면 패킷이 유실되고 있다는
뜻이다. 애플리케이션 로그에는 "응답이 느림"으로만 보이는 현상의 실제
원인일 수 있다.
Wireshark의 시간 열을 Time since previous displayed packet 으로
바꾸면 어디서 시간이 비는지 바로 보인다. 요청을 보내고 응답까지 3초가
비었다면 그건 서버 처리 시간이고, 재전송이 반복되며 3초가 갔다면
네트워크 문제다. 같은 "3초"인데 원인이 완전히 다르다.
TLS 문제 진단 — 인증서 오류의 실제 원인 찾기
"인증서 오류가 납니다"는 QA가 자주 만나는데 원인이 여럿이다. 패킷을 보면 좁혀진다.
tls.handshake.type == 1 Client Hello — 클라이언트가 제안한 것
tls.handshake.type == 2 Server Hello — 서버가 고른 것
tls.alert_message 경고·오류 메시지| Client Hello 이후 상황 | 추정 원인 |
|---|---|
| Server Hello 없이 끊김 | 프로토콜 버전 불일치(구형 TLS 지원 중단 등) |
| Alert: certificate_expired | 서버 인증서 만료 |
| Alert: unknown_ca | 클라이언트가 그 CA를 모름 — 중간 인증서 누락이 흔하다 |
| Alert: handshake_failure | 암호 스위트 협상 실패 |
| Client Hello의 SNI가 예상과 다름 | 요청이 엉뚱한 호스트로 가고 있다 |
'중간 인증서 누락'이 실무에서 자주 나온다. 브라우저에서는 잘 되는데 모바일 앱이나 서버 간 통신에서만 실패하는 전형적 패턴이다. 브라우저는 중간 인증서를 캐시해두는 경우가 있어 문제를 가리기 때문이다. 이 차이를 알고 있으면 "브라우저에서는 되는데요"라는 반론에 답할 수 있다.
실무 시나리오 — 어떤 문제에 어디를 보나
| 증상 | 먼저 볼 것 |
|---|---|
| 앱이 서버에 아예 못 붙는다 | SYN 재시도 / RST 여부, DNS 응답 |
| 로그인은 되는데 특정 API만 실패 | 그 요청의 TCP 스트림, HTTP 응답 코드 |
| 간헐적 타임아웃 | 재전송, RST 발생 시점, 유휴 시간 패턴 |
| 인증서 오류 | TLS Alert 메시지, 인증서 체인 |
| 응답이 느리다 | 시간 열을 delta로, 서버 처리 시간과 네트워크 시간 분리 |
| 앱이 예상 밖 서버와 통신 | Statistics → Conversations |
| 데이터가 깨져서 도착 | Follow TCP Stream으로 원본 확인 |
마지막 줄이 QA에게 유용하다. "한글이 깨진다"는 문제가 서버가 잘못 보낸 것인지, 클라이언트가 잘못 해석한 것인지를 패킷의 원본 바이트로 가릴 수 있다. 이건 프록시로도 되지만, 프록시가 못 붙는 상황이면 여기가 답이다.
캡처는 그 자체로 민감 정보다
앞 레슨의 원칙이 여기서는 더 강하게 적용된다.
패킷 캡처에는 그 시간 동안의 모든 통신이 들어 있다. 우리 서비스 트래픽만이 아니라, 같은 기기에서 나간 다른 통신, 다른 사용자의 세션(서버에서 캡처한 경우)까지 들어갈 수 있다.
| 원칙 | 이유 |
|---|---|
| 캡처 필터로 대상을 좁힌다 | 애초에 무관한 것을 안 담는다 |
| 필요 시간만 캡처한다 | 장시간 캡처는 그만큼 위험이 크다 |
| pcap 파일을 이슈에 그대로 첨부하지 않는다 | 토큰·개인정보·타 사용자 세션 포함 |
| 공유해야 하면 해당 스트림만 내보낸다 | Wireshark의 Export Specified Packets |
| 운영 서버 캡처는 승인을 받는다 | 성능 영향 + 개인정보 처리 문제 |
| 분석 후 파일을 삭제한다 | 남겨두면 잊는다 |
운영 서버에서의 캡처는 특히 신중해야 한다. 성능에 영향을 주고, 개인정보 처리 방침에 걸릴 수 있다. 반드시 인프라·보안 담당과 합의하고, 캡처 범위와 보관 기간을 정해두고 시작한다.
어디까지가 QA의 일인가
패킷 분석은 깊게 들어가면 네트워크 엔지니어의 영역이다. QA가 여기서 목표로 삼을 것은 명확하다.
"안 됩니다"
↓
"앱에서 서버로 SYN을 보내는데 응답이 없습니다.
3회 재시도 후 타임아웃입니다. 캡처 첨부합니다."
↓
→ 인프라팀이 방화벽·라우팅을 보면 되는 상태원인을 규명하는 것이 아니라 범위를 좁혀 넘기는 것 이 목표다. 그리고 그 한 단계가 문제 해결 시간을 크게 줄인다. 모듈 6(레슨 2)에서 배운 좋은 결함 리포트의 원칙이 네트워크 계층으로 확장되는 셈이다.
실무에서 왜 필요한가
QA가 마주치는 문제 중 애플리케이션 로그에 아무 흔적이 없는 것들이 있다. "가끔 끊긴다", "특정 통신사에서만 안 된다", "사무실에서는 되는데 고객사 망에서는 안 된다" 같은 것들이다. 이런 문제는 재현 조건을 못 잡으면 영원히 미해결로 남는다.
패킷 캡처는 그 재현을 증거로 고정 한다. 한 번만 잡아두면 그 파일을 가지고 몇 번이고 분석할 수 있고, 담당 팀에 넘길 수도 있다. 모듈 5 (레슨 12)에서 다룬 "재현 불가능한 버그"에 대한 가장 강력한 대응 수단 중 하나다.
그리고 이 능력은 QA의 범위를 넓힌다. 대부분의 QA가 애플리케이션 계층에서 멈추기 때문에, "네트워크 계층 문제로 보입니다"까지 말할 수 있는 QA는 드물다. 임베디드·IoT·B2B 솔루션처럼 네트워크 환경이 다양한 도메인에서는 특히 그렇다.