HTTP Tunneling
HTTP Tunneling이란?
HTTP Tunneling은 HTTP 프로토콜을 통로(터널)로 사용하여, 원래 HTTP가 아닌 트래픽을 전달하는 기법이다.
많은 기업 네트워크/방화벽은 HTTP(80)와 HTTPS(443) 포트만 허용한다. HTTP tunneling을 사용하면 이 제한된 환경에서도 다른 프로토콜의 트래픽을 주고받을 수 있다.
주요 방식
1. HTTP CONNECT (가장 대표적)
- 클라이언트가 프록시 서버에
CONNECT메서드를 전송 - 프록시가 목적지와 TCP 연결을 수립하면, 이후 양방향 바이트 스트림이 됨
- HTTPS 통신의 기본 동작 방식
Client → Proxy: CONNECT example.com:443 HTTP/1.1
Proxy → Client: HTTP/1.1 200 Connection Established
(이후 TLS 핸드셰이크 및 암호화된 데이터가 그대로 통과)
2. HTTP Encapsulation
- 비-HTTP 데이터를 HTTP 요청/응답 body에 감싸서 전달
- 예: SSH-over-HTTP, DNS-over-HTTPS (DoH)
- 각 메시지가 일반 HTTP 요청처럼 보이므로 방화벽 통과가 용이
3. WebSocket Upgrade
- 초기 HTTP 핸드셰이크 후 풀-듀플렉스 TCP 연결로 전환
- 실시간 양방향 통신에 사용 (채팅, 스트리밍 등)
일반 프록시 vs HTTP Tunnel
[일반 HTTP 프록시]
Client → Proxy → Server (프록시가 HTTP 내용을 읽고 중계)
[HTTP Tunnel (CONNECT)]
Client → Proxy → Server (프록시는 바이트를 그대로 전달, 내용 못 봄)
════════════════ ← 투명한 TCP 파이프
핵심 차이는 프록시가 payload를 해석하느냐 여부이다. 터널에서는 프록시가 단순 relay 역할만 하므로 TLS 등 암호화된 트래픽도 통과시킬 수 있다.
실제 사용 사례
| 사례 | 설명 |
|---|---|
| HTTPS | 브라우저가 프록시 환경에서 CONNECT로 TLS 터널 생성 |
| Corporate proxy 우회 | 방화벽 뒤에서 SSH, VPN 등을 HTTP로 감싸서 사용 |
| ngrok / Cloudflare Tunnel | 로컬 서비스를 외부에 노출할 때 HTTP 터널 활용 |
| DNS-over-HTTPS | DNS 쿼리를 HTTPS 요청으로 캡슐화 |
실습: Squid 프록시 + CLI 도구
환경 준비
# Squid 설치
sudo apt install -y squid
# 기본 포트: 3128
# 설정 파일: /etc/squid/squid.conf
Step 1: HTTPS 트래픽 터널링 (curl + CONNECT)
# CONNECT 터널 경유 HTTPS 요청
curl -x http://localhost:3128 https://httpbin.org/ip
# -v 옵션으로 CONNECT 핸드셰이크 과정 확인
curl -v -x http://localhost:3128 https://httpbin.org/ip
curl -v 출력에서 다음과 같은 흐름이 보인다:
* Establish HTTP proxy tunnel to httpbin.org:443
> CONNECT httpbin.org:443 HTTP/1.1
> Host: httpbin.org:443
>
< HTTP/1.1 200 Connection established
<
* CONNECT tunnel established, response 200
* TLS handshake starts...
Squid 로그 확인:
sudo tail -f /var/log/squid/access.log
# TCP_TUNNEL/200 CONNECT httpbin.org:443 형태의 로그가 기록됨
Step 2: 패킷 캡처로 CONNECT 동작 관찰
# 터미널 1: loopback 트래픽 캡처
sudo tcpdump -i lo port 3128 -A
# 터미널 2: curl 요청
curl -x http://localhost:3128 https://httpbin.org/ip
관찰 포인트:
- CONNECT 요청/응답 헤더는 평문으로 보임
- 이후 TLS 핸드셰이크 데이터는 암호화되어 읽을 수 없음
- 프록시는 목적지 호스트:포트만 알 수 있고, 실제 전송 내용은 알 수 없음
Step 3: Raw CONNECT 핸드셰이크 직접 해보기 (nc)
# netcat으로 Squid에 직접 접속
nc localhost 3128
수동으로 아래 내용을 입력:
CONNECT httpbin.org:443 HTTP/1.1
Host: httpbin.org:443
응답:
HTTP/1.1 200 Connection established
이 시점에서 터널이 열린 상태이다. 이후 입력하는 모든 바이트는 httpbin.org:443으로 그대로 전달된다.
Step 4: SSH over HTTP Tunnel
Squid 설정에서 포트 22에 대한 CONNECT를 허용해야 한다:
# /etc/squid/squid.conf에 추가
# acl Safe_ports port 22
# acl SSL_ports port 22
# 설정 변경 후: sudo systemctl reload squid
SSH 터널링 실행:
# nc를 ProxyCommand로 사용하여 SSH를 HTTP CONNECT 터널로 통과
ssh -o ProxyCommand='nc -X connect -x localhost:3128 %h %p' localhost
Squid 로그에서 SSH 연결이 CONNECT로 터널링된 것을 확인할 수 있다.
정리
# 실습 후 정리
sudo apt remove --purge squid
sudo apt autoremove
보안 관점
- 정당한 용도: HTTPS 통신, 기업 VPN, 보안 DNS
- 리스크: 방화벽/DLP를 우회할 수 있어 데이터 유출 경로가 될 수 있음
- 대응: 프록시에서 CONNECT 대상 도메인/포트를 화이트리스트로 제한
핵심 정리
- CONNECT 메서드 — 프록시에게 “이 호스트:포트로 TCP 파이프를 열어달라"는 요청
- 터널 vs 프록시 — 터널은 프록시가 payload를 해석하지 않음 (바이트 릴레이)
- 보안 시사점 — CONNECT로 임의 포트를 열 수 있으면 방화벽 우회 가능 → 포트 제한 필수