iOS 시뮬레이터와 기기에서 WebSocket을 가로채고 디버깅하는 방법
iOS 앱이 URLSessionWebSocketTask 또는 WebSocket 라이브러리(예: Starscream, SocketRocket 등)를 사용한다면, Proxyman이 기본 설정만으로는 WS/WSS 트래픽을 캡처하지 못할 수 있습니다.
원인
이는 Apple이 의도한 동작입니다. URLSessionWebSocketTask는 시스템 HTTP 프록시 설정을 따르지 않습니다. 모든 WS/WSS 트래픽이 인터넷으로 직접 전달되므로 Proxyman이나 Charles Proxy로는 이 트래픽을 캡처할 수 없습니다.
이 블로그에서 다루는 내용
- 개발 단계에서 Proxyman을 사용해 iOS 기기(iOS 18 이상)의 WebSocket 메시지를 캡처합니다.
해결 방법
이 튜토리얼에서는 Proxyman을 사용해 개발 단계에서 iOS 기기의 WebSocket 메시지를 가로채고 디버깅하는 방법을 소개합니다. Proxyman은 HTTP/HTTPS와 WebSocket을 디버깅하기 위한 강력한 도구입니다.
튜토리얼의 진행 단계는 다음과 같습니다:
- Proxyman 준비하기
- iOS 기기(iPhone / iPad) 또는 iOS 시뮬레이터에 Proxyman 설정하기
- Proxyman SOCKS 프록시 서버 시작하기
- 앱이 Proxyman SOCKS 프록시 서버를 사용하도록 설정하기
- 짜잔! Proxyman이 앱의 WebSocket 메시지를 캡처합니다. URLSessionWebSocketTask에서도 동작합니다.
코드를 보고 싶다면 GitHub를 방문하세요.
1. Proxyman 준비하기
Proxyman을 받는 가장 쉬운 방법은 Proxyman 홈페이지에서 직접 다운로드하거나 터미널을 이용하는 것입니다.
$ brew cask install proxyman
2. Proxyman으로 iOS 시뮬레이터 또는 iOS 기기 설정하기
2.1 iOS 시뮬레이터
Certificate Menu->Install for iOS->iOS Simulators로 이동합니다.- 안내에 따라 모든 단계를 진행해 iOS 시뮬레이터에 인증서를 설치하세요. (최소한 iOS 시뮬레이터가 하나 있는지 확인하세요.)
- 완료.

2.2 iOS 기기
Certificate Menu->Install for iOS->iOS Devices로 이동합니다.- 안내에 따라 모든 단계를 진행해 iOS 기기에 인증서를 설치하세요.
- 마지막 단계인 iOS 기기의 Proxyman 인증서 신뢰 설정까지 반드시 완료하세요.
- 완료.

3. Proxyman SOCKS 프록시 서버 시작하기
- Proxyman 앱에서
Tools->Proxy Settings->SOCKS Proxy settings로 이동한 뒤Enable로 설정합니다. - 포트 번호를 메모해 두세요. 현재 기본 포트는
8889입니다. - 완료.

4. 앱이 Proxyman SOCKS 프록시 서버를 사용하도록 설정하기
사용 중인 WebSocket 라이브러리에 따라 아래 안내를 따르세요:
4.1 NWConnection 사용 시
let parameters = webSocketURL.scheme == "wss" ? NWParameters.tls : NWParameters.tcp
let options = NWProtocolWebSocket.Options()
options.autoReplyPing = true
parameters.defaultProtocolStack.applicationProtocols.insert(options, at: 0)
if #available(iOS 17.0, *) {
let socksv5Proxy = NWEndpoint.hostPort(host: "x.x.x.x", port: 8889) // Replace with your Proxyman SOCKS Proxy Server IP address
let config = ProxyConfiguration.init(socksv5Proxy: socksv5Proxy)
let context = NWParameters.PrivacyContext(description: "my socksv5Proxy")
context.proxyConfigurations = [config]
parameters.setPrivacyContext(context)
}
let connection = NWConnection(to: .url(webSocketURL), using: parameters)
connection.start(queue: .main)
4.2 URLSession 및 URLSessionWebSocketTask 사용 시
private lazy var urlSession: URLSession = {
let config = URLSessionConfiguration.default
if #available(iOS 17.0, *) {
let socksv5Proxy = NWEndpoint.hostPort(host: "x.x.x.x", port: 8889) // Replace with your Proxyman SOCKS Proxy Server IP address
let proxyConfig = ProxyConfiguration.init(socksv5Proxy: socksv5Proxy)
config.proxyConfigurations = [proxyConfig]
}
return URLSession(configuration: config, delegate: nil, delegateQueue: nil)
}()
5. 완료
짜잔! Proxyman이 앱의 WebSocket 메시지를 캡처합니다 🎉

6. 대체 방법
앱 코드를 수정하고 싶지 않다면 Atlantis 프레임워크를 사용해 WebSocket 메시지를 캡처할 수 있습니다.
다음 단계
WebSocket에 대해 더 자세한 내용은 Proxyman 공식 문서에서 확인할 수 있습니다.
SOCKS 설정은 디버그 빌드에서만 사용하세요. 릴리스 앱이 개발용 프록시에 의존해서는 안 됩니다. Proxyman Automatic Setup 세션에서 시작한 웹 브라우저와 서버는 이 iOS 코드를 추가하지 않아도 대개 캡처할 수 있습니다. 또한 메시지 정보를 제공하면 Proxyman이 WebSocket Protobuf 페이로드를 디코딩할 수 있으며, 이는 바이너리 프레임을 직접 읽는 것보다 훨씬 쉽습니다.
Proxyman은 iOS 기기, iOS 시뮬레이터, Android 기기에서 앱과 도메인의 HTTP/HTTPS 요청을 캡처하고 검사할 수 있게 해 주는 고성능 macOS 앱입니다.
https://proxyman.com에서 다운로드하세요.
