사이트는 Cloudflare에 의해 차단되었고, Turnstile은 두 번째 요청마다 나타나며, 레이아웃은 2주마다 변경됩니다. 그러나 같은 서비스는 백엔드에 직접 접근하여 준비된 JSON을 가져오는 모바일 애플리케이션을 가지고 있습니다. 챌린지 없이, 마크업 없이, 안정적인 필드 스키마로. 이것이 바로 "숨겨진 API"입니다: 문서화되지 않았지만 완전히 작동하는 인터페이스로, 공식 클라이언트가 사용합니다.
mitmproxy를 사용하여 이를 찾는 방법을 단계별로 살펴보고, 인증서 핀닝에 대해 무엇을 해야 하는지, 그리고 프록시 없이 수집을 확장하는 단계에서 왜 모든 것이 무너지는지 알아보겠습니다.
애플리케이션 트래픽에 접근해야 하는 이유
웹 버전을 스크래핑하고 비공식 API를 호출하는 것은 비용 측면에서 다른 작업입니다. 비교해 보세요:
- 웹. 헤드리스 브라우저, 안티봇 우회, HTML 파싱, 선택기 정기 수리 필요. 하나의 요청 = 메가바이트의 트래픽과 몇 초의 프로세서 시간.
- 비공식 API. 몇 개의 헤더가 있는 일반 HTTP 요청, 응답은 타입화된 필드가 있는 컴팩트한 JSON. 종종 인터페이스가 보여주는 것보다 더 많은 데이터를 반환합니다: 내부 식별자, 플래그, 서비스 필드.
모바일 백엔드는 역사적으로 웹보다 덜 보호되어 있습니다. 이유는 간단합니다: 안티봇 플랫폼은 브라우저 트래픽에 맞춰져 있으며 (JS 챌린지, 캔버스, 행동 신호), 모바일 클라이언트는 이를 통과하지 못합니다. 대신 개발자는 애플리케이션의 정적 키와 TLS 핀닝에 의존합니다. 둘 다 로컬 장치에서 제거됩니다.
필요한 것
- mitmproxy — 오픈 소스 HTTPS 프록시 인터셉터 (GitHub에서 44,000개 이상의 별, 현재 버전 12.2.2는 2026년 4월에 출시, Python 3.12+ 필요). 한 명령으로 설치: pip install mitmproxy. HTTP/1, HTTP/2, HTTP/3, WebSocket 및 원시 TCP를 이해하며, TLS 1.2 및 1.3과 함께 작동합니다.
- 루트가 있는 Android 장치 또는 에뮬레이터. 실습에 따르면 Android 7-11이 가장 편리합니다: 새로운 버전은 인증서 작업을 크게 강화했습니다.
- ADB는 장치와의 연결을 위해 필요하며 Frida (pip install frida-tools) — 애플리케이션이 인증서를 핀닝하는 경우 필요합니다.
mitmproxy는 하나의 엔진 위에 세 가지 인터페이스를 가지고 있습니다: mitmproxy (터미널 TUI), mitmweb (웹 인터페이스, 초보자에게 더 편리함) 및 mitmdump (헤드리스, 스크립트 및 자동화를 위한).
1단계. 인터셉터 시작하기
웹 인터페이스를 외부 연결을 수신하도록 시작합니다. localhost만이 아니라:
mitmweb --web-host 0.0.0.0
기본적으로 프록시는 8080 포트에서 시작됩니다. mitmproxy를 처음 시작하면 자체 인증 기관을 생성하고 키를 ~/.mitmproxy 디렉토리에 저장합니다. 네 개의 파일이 생성됩니다: mitmproxy-ca.pem (개인 키와 함께 인증서), mitmproxy-ca-cert.pem (인증서만), mitmproxy-ca-cert.p12 (Windows용) 및 mitmproxy-ca-cert.cer (Android용 형식).
2단계. 장치를 프록시를 통해 연결하기
전화기의 Wi-Fi 설정에서 수동 프록시를 선택합니다: 로컬 네트워크에서 컴퓨터의 IP와 8080 포트. 그런 다음 장치의 브라우저에서 특별한 도메인 mitm.it를 엽니다. 이는 mitmproxy에 내장된 페이지로, 플랫폼을 자동으로 감지하고 필요한 형식의 인증서를 제공하는 지침을 제공합니다.
iOS에서는 절차가 세 부분으로 나뉘며, 두 번째 절반을 모두 잊어버립니다: Safari를 통해 프로필을 다운로드하고 "설정 → 일반 → VPN 및 장치 관리"에 설치한 후, "설정 → 일반 → 이 장치에 대하여 → 인증서 신뢰"에서 전체 신뢰를 별도로 활성화해야 합니다. 마지막 단계 없이 인증서는 설치되지만 작동하지 않습니다.
Wi-Fi 설정을 조정하는 것이 귀찮다면, mitmproxy에는 VPN 서버 모드가 있습니다: mitmweb --mode wireguard. 장치는 WireGuard의 기본 클라이언트를 통해 연결되며, 트래픽은 수동 프록시 설정 없이 투명하게 인터셉트됩니다.
3단계. 주요 장벽 — 인증서에 대한 신뢰
여기서 대부분의 시도가 실패합니다. 문제는 정확히 두 가지이며, 서로 다른 문제입니다.
사용자 CA는 2016년 이후로 신뢰받지 않음
Android 7 Nougat (API 24)부터 애플리케이션은 기본적으로 시스템 인증서 저장소에만 신뢰를 둡니다. 개발자가 Network Security Config에서 명시적으로 허용하지 않는 한 사용자 CA는 무시됩니다 — <certificates src="user" /> 블록을 통해 신뢰 앵커에 추가해야 합니다. 이는 공격 표면을 줄이기 위한 Google의 의도적인 결정이며, 전화 설정으로 이를 우회할 수 없습니다. 참고로 Chrome도 사용자 인증서에 신뢰를 두지 않습니다. Android 11에서는 제한이 더욱 강화되었습니다.
실질적인 결론: 루트가 있는 장치에서 mitmproxy 인증서는 시스템 저장소에 배치해야 합니다, 사용자 저장소가 아닙니다. 그래서 루트가 요구 사항 목록에 있는 것입니다.
인증서 핀닝
두 번째 장벽은 핀닝입니다: 애플리케이션은 예상되는 서버 인증서의 지문을 포함하고 있으며, 다른 누구와도 대화하기를 거부합니다. 심지어 시스템 CA도 구제하지 않습니다. 2022년 ACM 연구에 따르면 핀닝은 "고위험" 분야 (은행, 택시, 암호화폐)에서 널리 퍼져 있지만 종종 불완전하게 구현되어 우회할 수 있습니다.
이 작업을 위한 도구는 여러 가지가 있으며, 각기 다른 방식으로 문제를 해결합니다:
- Frida — 런타임에서 동작 수정: 인증서 확인 함수를 후킹하여 성공을 반환하도록 합니다. 이 경우 애플리케이션은 수정되지 않으며, 가장 유연한 옵션입니다. 일반적인 실행: frida -U -f com.target.app -l ssl_bypass.js --no-pause.
- apk-mitm — APK 파일에서 핀닝을 자동으로 제거합니다.
- android-unpinner — Frida와 핀닝 제거 스크립트를 주입하여 APK를 재구성합니다.
- objection — Frida 위의 툴킷으로, iOS와 Android 모두 지원합니다.
- ssl-kill-switch2 — iOS 및 macOS 애플리케이션에서 핀닝을 비활성화합니다.
특정 도메인이 철저하게 핀닝되어 작업을 방해하는 경우, ignore_hosts 옵션을 사용하여 인터셉트를 제외할 수 있습니다 (정규 표현식을 수용합니다) — 트래픽은 mitmproxy를 우회하여 해독되지 않고 진행됩니다.
4단계. 필요한 요청 찾기
다음은 일상적인 작업입니다. 애플리케이션을 열고 정확히 하나의 의미 있는 작업 (상품 카드 열기, 피드 스크롤, 필터 적용)을 수행한 다음 어떤 요청이 발생했는지 확인합니다. 터미널 인터페이스에서는 빠르게 수행할 수 있습니다: Z는 흐름 목록을 지우고, Enter는 선택한 요청을 열고, E는 이를 내보냅니다 — 준비된 curl 명령으로도 가능합니다.
인터셉트된 요청에서 찾아야 할 것:
- 엔드포인트 및 매개변수. 종종 애플리케이션 인터페이스에서 사용하는 것보다 더 많은 것이 있습니다.
- 클라이언트 키. 전형적인 예 — 애플리케이션에 내장된 정적 식별자. 유명한 MyAnimeList의 공개 API 분석에서 이 키는 x-mal-client-id 헤더로, 값은 6591a087c62b3e94d769cd8e35ffe909로, api.myanimelist.net/v3/anime/season 및 /v3/anime 엔드포인트에 접근할 수 있게 해주었습니다.
- User-Agent. 모바일 클라이언트의 경우 특이하며 "통과"의 일부로 작용합니다 — 같은 예에서 MAL (ios, 139)입니다.
- 토큰 및 그 유효 기간. 즉시 키가 정적이거나 업데이트되는지 확인하세요: 이는 수집기의 전체 아키텍처에 영향을 미칩니다.
내보낸 curl을 코드로 쉽게 변환할 수 있습니다. curlconverter를 사용하면 requests에 대한 준비된 요청을 얻을 수 있으며, 이후에는 일반 HTTP 클라이언트로 작업할 수 있습니다.
5단계. 확장 — 모든 것이 무너지는 곳
이 지점에서 실망이 찾아옵니다. 집에서 하나의 IP로 비공식 API는 처음 30분 동안 잘 응답하지만, 그 후 429 및 403을 반환하기 시작합니다. 모바일 백엔드는 클라이언트 위조에 대해 덜 보호되지만, IP에 대한 제한은 더 엄격합니다 — 서버는 하나의 전화가 해당 주소에 있다고 가정합니다, 파서가 20개의 스레드로 있는 것이 아닙니다.
여기서 실질적인 결론이 나옵니다.
- 요청 프로필을 신뢰할 수 있게 유지하세요. 실제 애플리케이션은 초당 50개의 요청을 하지 않으며, 엄격한 일정에 따라 움직이지 않습니다. 호출 순서도 중요합니다: 실제 클라이언트는 먼저 세션 구성을 요청하고, 그 다음 콘텐츠를 요청합니다.
- 부하를 주소에 분산하세요. 하나의 IP = 하나의 "전화". 주소 회전 전략, 지연 및 지터, 지수 백오프에 대한 자세한 내용은 프록시를 통한 API 속도 제한 우회 방법에서 다루었습니다.
- 지리적 요소를 고려하세요. 많은 모바일 API는 주소 국가에 따라 다른 콘텐츠와 가격을 반환합니다 — 이는 동시에 제한이자 기회입니다.
디버깅은 mitmproxy를 떠나지 않고도 편리하게 진행할 수 있습니다: 상위 프록시에 연결할 수 있습니다. mitmdump --mode upstream:http://example.com:8081 명령은 모든 트래픽을 업스트림으로 전송하며, 인증은 --upstream-auth 옵션을 통해 username:password 형식으로 설정됩니다. 이렇게 하면 이전과 동일한 요청을 볼 수 있지만, 외부 주소에서 전송됩니다 — API가 특정 국가 또는 IP 유형에 어떻게 반응하는지 즉시 확인할 수 있습니다.
모바일 API에 적합한 프록시 유형 선택하기
여기서 선택은 추상적이지 않으며, 당신이 누구인지를 반영합니다.
- 모바일 프록시 — 우선 옵션입니다. 애플리케이션의 트래픽을 모방하며, 이동통신사의 주소는 백엔드에서 완전히 자연스럽게 보입니다: CGNAT 덕분에 하나의 주소 뒤에는 실제로 수백 명의 가입자가 있기 때문에 이러한 IP에 대한 제한이 더 느슨합니다. 모바일 4G/LTE 프록시가 적합합니다.
- 레지던셜 프록시 — 대량의 데이터가 필요하고 이동통신사에 대한 의존성이 크지 않은 경우 적절한 중간 옵션입니다: 가정용 IP 제공자는 적절한 가격에 넓은 지리적 범위를 제공합니다. 이는 레지던셜 프록시입니다.
- 데이터 센터 프록시 — 심각한 주소 평판 검사가 없는 엔드포인트에만 사용합니다. 이들의 ASN은 즉시 인식되며, 모바일 백엔드에서는 이상하게 보입니다: 데이터 센터에는 전화가 없습니다.
늦게 알게 되는 함정들
- HTTP/3. mitmproxy는 QUIC 지원이 있으며 기본적으로 활성화되어 있지만, 실제 모바일 트래픽에서는 제한적입니다: 종종 ALPN 조작을 통해 HTTP/2로 강제로 롤백해야 합니다. QUIC는 리버스 및 WireGuard 모드에서 가장 잘 작동합니다.
- 비공식 API는 예고 없이 변경됩니다. 이에는 하위 호환성에 대한 의무가 없습니다 — 내부 인터페이스입니다. User-Agent의 애플리케이션 버전이 언젠가 서비스되지 않게 되고, 수집기는 조용히 빈 응답을 받기 시작합니다. 응답 코드뿐만 아니라 JSON 구조도 모니터링하세요.
- "키를 찾았다"와 "권한을 얻었다"를 혼동하지 마세요. 정적 클라이언트 키는 무제한 수집에 대한 허가가 아닙니다.
법적 측면에 대하여
자신의 장치에서 트래픽을 가로채는 것은 합법적이고 일상적인 디버깅 관행이며, 모바일 개발자와 보안 전문가가 사용합니다. 경계는 그 이후에 시작됩니다: 서비스 이용 약관을 준수하고, 법적 근거 없이 개인 데이터를 수집하지 않으며 (EU에서는 GDPR에 의해 직접 규제됨), 타인의 인증이 필요한 엔드포인트를 건드리지 않고, 서비스 작동에 방해가 되지 않는 수준으로 부하를 유지하세요. 실질적인 기준: 데이터가 계정 로그인 없이 모든 사용자에게 애플리케이션에서 보이는 경우 — 상대적으로 안전한 영역에 있습니다; 접근을 위해 타인의 계정이 필요한 경우 — 이미 그 경계를 넘어선 것입니다.
요약
이 프로세스는 작동하며 안티봇과의 수고를 주간 단위로 절약합니다: mitmproxy를 시작하고, 루트가 있는 장치의 시스템 저장소에 인증서를 배치하고, 필요시 Frida를 통해 핀닝을 제거하고, 하나의 의미 있는 요청을 포착하여 curl로 내보내고 Python으로 다시 작성합니다. 이후 "보안을 우회하는" 작업은 "부하를 신중하게 분산하는" 작업으로 변모하며, 주소 회전, 합리적인 지연 및 적절한 프록시 유형으로 해결됩니다. 모바일 프록시로 시작하는 것이 가장 쉽습니다: 이는 백엔드가 기대하는 트래픽에 가장 가깝습니다.
```