에디블로그
Engineer's Field Notes

AI 자동화로 매일
한 편씩 쓰는
엔지니어 운영 노트

Claude Code · 자동화 파이프라인 · 사고 회고까지. 잘 굴러간 기록 + 깨진 흔적도 같이 남깁니다.

사람이 할 수 있는 일은,
AI도 할 수 있어야 합니다.
매일 한 편 쓰면서 검증 중.
— 이번 주 가장 많이 읽힌 글 TOP 3
개발자 도구/API & DB

[mitmproxy] 트래픽을 파이썬으로 고치는 오픈소스 프록시

반응형
[mitmproxy] 트래픽을 파이썬으로 고치는 오픈소스 프록시

개발자 도구 · API & DB · 소개

[mitmproxy] 트래픽을 파이썬으로 고치는 오픈소스 프록시

mitmproxy는 HTTP·HTTPS 요청을 가로채서 보고 고치고 다시 보내는 오픈소스 프록시예요. Charles나 Proxyman 같은 GUI 디버깅 프록시와 하는 일은 겹쳐요. 다만 규칙을 파이썬 코드로 쓴다는 점이 달라요. 이 글에서는 세 가지 실행 도구, 인증서 설정 순서, 필터 문법, 애드온 스크립트 예시, 그리고 처음 쓸 때 막히는 지점까지 정리합니다.

클릭 대신 코드로 규칙을 쓰는 프록시예요

GitHub 저장소 소개 문구는 "An interactive TLS-capable intercepting HTTP proxy for penetration testers and software developers"예요. 보안 테스트하는 사람과 개발자를 둘 다 대상으로 잡고 있어요. 라이선스는 MIT예요. 공식 문서 기준으로 HTTP/1, HTTP/2, WebSocket을 다뤄요.

GUI 프록시에서 "이 API 응답을 로컬 파일로 바꿔줘" 같은 규칙은 보통 메뉴에서 하나씩 만들어요. mitmproxy에서는 같은 일을 옵션 한 줄이나 파이썬 함수 하나로 해요. 그래서 규칙을 파일로 저장해 두고 팀원과 공유하거나, CI 같은 곳에서 화면 없이 돌리기 쉬워요.

항목 GUI 디버깅 프록시(Charles·Proxyman 등) mitmproxy
가격 유료 라이선스 중심 무료, MIT 라이선스
규칙 작성 메뉴·대화상자 옵션 문자열 또는 파이썬 애드온
화면 없는 실행 제한적 mitmdump로 가능
플랫폼 제품마다 다름 macOS·Linux·Windows
첫 사용 난이도 낮음 필터 문법·키 조작 익혀야 함

정리하면, 클릭 몇 번으로 요청을 훑어보는 용도면 GUI 도구가 편해요. 같은 조작을 반복하거나 자동화해야 하면 mitmproxy 쪽이 맞아요.

실행 도구는 세 개, 코어는 하나예요

mitmproxy를 설치하면 명령이 세 개 생겨요. 셋 다 같은 프록시 코어 위에 얹힌 프런트엔드예요. 그래서 옵션과 스크립트는 어디서나 똑같이 먹혀요.

mitmproxy: 터미널 UI

터미널 안에서 요청 목록을 보고 고치는 대화형 앱이에요. 공식 문서에 따르면 모든 flow를 메모리에 들고 있어요. 그래서 트래픽을 오래 쌓아두는 용도보다는 짧게 살펴보는 데 맞아요.

mitmweb: 브라우저 UI

같은 기능을 웹 화면으로 보여줘요. 문서에는 아직 beta로 표시돼 있어요. 다만 UI에 노출된 기능은 안정적이라고 적혀 있어요. 터미널 조작이 낯설면 여기서 시작하는 게 진입 장벽이 낮아요.

mitmdump: 화면 없는 CLI

문서 표현으로는 "tcpdump 같은" 도구예요. 트래픽을 기록하고 스크립트로 변환하는 일을 화면 없이 해요. 자동화나 서버에 붙여 돌릴 때 주로 이걸 써요.

설치 후 인증서부터 넣어야 HTTPS가 보여요

macOS는 Homebrew cask로 설치해요. Linux와 Windows는 mitmproxy.org에서 단독 실행 파일이나 설치 프로그램을 받는 방식이 공식 안내예요. 배포판 저장소 패키지도 있지만 최신 버전보다 늦는 경우가 많다고 적혀 있어요. 파이썬 패키지를 같이 쓰는 애드온을 만들 거라면 uv 설치가 권장돼요.

# macOS
brew install --cask mitmproxy

# 애드온에서 외부 파이썬 패키지를 쓸 때
uv tool install mitmproxy
uv tool install --with requests mitmproxy

# 실행 (기본 포트 8080)
mitmproxy        # 터미널 UI
mitmweb          # 브라우저 UI
mitmdump         # 화면 없이

실행 후 순서는 이렇게 돼요.

  1. mitmproxy를 한 번 띄우면 홈 디렉터리에 ~/.mitmproxy 폴더가 생겨요. 그 안에 CA 인증서가 만들어져요.
  2. 확인할 기기(브라우저, 휴대폰 등)의 프록시를 mitmproxy가 떠 있는 주소의 8080 포트로 지정해요.
  3. 그 기기 브라우저에서 mitm.it에 접속해요. 플랫폼별 아이콘이 나와요. 누르면 인증서 설치 안내가 이어져요.
  4. iOS는 설치만으로 끝나지 않아요. 설정의 인증서 신뢰 설정에서 전체 신뢰를 따로 켜야 해요.

~/.mitmproxy 폴더에는 용도별 파일이 같이 들어 있어요. mitmproxy-ca-cert.pem은 대부분의 비Windows 플랫폼용, .p12는 Windows용, .cer는 확장자를 가리는 일부 Android 기기용이에요. mitmproxy-ca.pem은 개인키까지 들어 있는 파일이라 밖으로 돌리면 안 돼요. 인증서는 설치마다 따로 생성돼서, 다른 사람 PC의 인증서와 공유되지 않아요.

필터 문법을 알면 원하는 요청만 골라요

요청 목록 거르기, 가로채기 대상 지정, 규칙 적용 범위 지정에 전부 같은 필터 문법이 쓰여요. 이것만 익히면 나머지 기능이 쉬워져요.

필터 의미
~d 정규식 도메인 일치
~u 정규식 URL 일치
~m 정규식 HTTP 메서드
~c 숫자 응답 상태 코드
~h / ~b / ~t 헤더 / 본문 / Content-Type
~q / ~s 응답 없는 요청 / 응답
! & | not / and / or

예를 들어 터미널 UI에서 i를 누르면 하단에 set intercept ''가 채워져요. 따옴표 안에 ~d api.example.com & ~m POST를 넣으면 그 도메인의 POST 요청만 멈춰 세워요. 멈춘 요청은 내용을 고친 뒤 a로 그대로 보내거나 X로 버려요. 다른 단축키는 어느 화면에서든 ?로 확인할 수 있어요.

자주 쓰는 기능은 옵션 한 줄로 끝나요

Map Local: 원격 파일을 로컬 파일로 바꾸기

운영 사이트의 main.js를 내 PC의 수정본으로 바꿔 끼워서 확인할 때 써요. 배포 없이 프런트엔드 수정을 실제 환경에서 보는 용도예요.

Map Remote: 요청 주소 바꾸기

요청이 서버에 닿기 전에 URL을 다시 써요. 앱이 운영 API를 부르게 둔 채로, 실제로는 스테이징 서버로 보내는 식이에요.

Modify Headers·Block List

Modify Headers는 헤더를 넣거나 덮어쓰거나 지워요. 값을 비우면 삭제예요. Block List는 조건에 맞는 요청에 고정 상태 코드를 돌려줘요. 444를 쓰면 응답 없이 연결을 끊어요. 그래서 분석 스크립트 같은 서드파티 요청을 끄고 화면을 볼 때 유용해요.

# 운영 main.js를 로컬 파일로 대체
mitmproxy --map-local "|example.com/main.js|~/main-local.js"

# GET 요청만 다른 호스트로 돌리기
mitmproxy --map-remote "|~m GET|//example.org/|//staging.example.org/"

# 모든 요청에 헤더 추가
mitmdump --modify-headers "/~q/X-Debug/1"

# google-analytics 요청에 404 응답
mitmdump --set block_list=":~d google-analytics.com:404"

# 트래픽을 파일로 저장했다가 다시 읽기
mitmdump -w flows.mitm
mitmproxy -r flows.mitm

패턴 맨 앞 글자(| 나 / 나 :)가 구분자 역할을 해요. URL에 | 가 들어가면 다른 글자로 시작하면 돼요.

애드온은 파이썬 파일 하나에서 시작해요

옵션으로 안 되는 조건부 로직은 애드온으로 짜요. request, response 같은 이벤트 함수를 정의하고 -s로 넘기면 끝이에요. 아래는 특정 호스트 요청에 헤더를 붙이는 예시예요. 아직 서버가 없는 엔드포인트에는 가짜 JSON을 돌려주고 5xx 응답은 로그로 남겨요.

# debug_addon.py
import logging
from mitmproxy import http

def request(flow: http.HTTPFlow) -> None:
    if flow.request.pretty_host.endswith("api.example.com"):
        flow.request.headers["X-Debug"] = "1"

    # 아직 구현 안 된 API는 가짜 응답으로
    if flow.request.path.startswith("/v2/coupons"):
        flow.response = http.Response.make(
            200,
            b'{"coupons": []}',
            {"Content-Type": "application/json"},
        )

def response(flow: http.HTTPFlow) -> None:
    if flow.response.status_code >= 500:
        logging.warning("5xx: %s %s", flow.request.method, flow.request.pretty_url)
mitmdump -s debug_addon.py

-s로 불러온 스크립트는 저장할 때마다 자동으로 다시 로드돼요. 문서 기준으로 저장 후 1초 안팎에 반영돼요. 프록시를 재시작하지 않아서 다른 애드온 상태나 진행 중인 요청도 유지돼요. import 단계에서 에러가 나면 이전 버전도 내려간 상태로 남아요. 고쳐서 다시 저장하면 돼요. 반면 request·response 안에서 난 에러는 로그만 남고 애드온은 계속 붙어 있어요.

미리 알아두면 덜 막히는 것들

  • 인증서 고정(certificate pinning)을 쓰는 앱은 mitmproxy 인증서를 거부해요. 볼 필요 없는 도메인이면 ignore_hosts에 넣어 가로채지 않게 하는 게 공식 안내예요. 꼭 봐야 하면 앱 자체를 패치해야 해요.
  • 프록시 설정을 무시하는 앱이 있어요. 이 경우 같은 PC 앱은 local 모드(--mode local, 프로세스 이름이나 PID 지정 가능), 휴대폰은 wireguard 모드(기본 51820/UDP)로 우회할 수 있어요. Linux의 local 모드는 커널 6.8 이상과 sudo가 필요해요.
  • 터미널 UI는 모든 flow를 메모리에 들고 있어요. 장시간 기록은 mitmdump -w로 파일에 쌓는 편이 맞아요.
  • mitmweb은 문서상 아직 beta 표기예요. 기능은 터미널 UI 쪽이 더 넓어요.
  • ~/.mitmproxy/mitmproxy-ca.pem에는 개인키가 들어 있어요. 이 파일이 새면 그 CA를 신뢰한 기기의 HTTPS가 위험해져요. 쓰지 않을 땐 기기에서 CA 신뢰를 해제해 두는 게 안전해요.

반복 디버깅이 많은 팀에 맞아요

모바일 앱과 API를 같이 만지는 개발자, 프런트엔드 수정본을 운영 환경에서 미리 보고 싶은 사람, QA에서 특정 에러 응답을 재현해야 하는 경우에 쓰임새가 커요. 반대로 가끔 요청 하나 열어보는 정도면 브라우저 개발자 도구나 GUI 프록시로 충분해요.

시작은 mitmweb을 띄우고 브라우저 프록시를 8080으로 돌린 뒤 mitm.it에서 인증서를 넣는 데까지만 해보면 돼요. 그다음 필터 몇 개를 써본 뒤 같은 조작을 세 번 이상 반복하게 될 때 애드온 파일로 옮기는 순서가 자연스러워요.

주의 mitmproxy는 자기 기기나 테스트 권한이 있는 환경의 트래픽을 볼 때만 쓰세요. 다른 사람의 통신을 동의 없이 가로채는 건 법적 문제가 될 수 있어요. 회사 네트워크에서는 보안 정책을 먼저 확인하는 게 좋아요.

이 글은 직접 사용기가 아니라 mitmproxy 공식 문서와 저장소를 바탕으로 정리한 객관 소개입니다. 글 작성 시점 최신 릴리즈는 12.2.3(2026년 5월)이에요. 이후 버전에서 옵션 이름이나 동작이 바뀔 수 있어요.

반응형

📚 같이 보면 좋은

"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 일정액의 수수료를 제공받습니다."