I would like to inspect network traffic going through web sockets, I have no control over the networking code as this is a binary lib for which I do not have the source code, so I cannot do any log/breakpoint in the networking part of the code.
I have tried using the latest version of CharlesProxy which claim to be able to sniff websockets however when I tried the url and apis using websockets were not even mentionned in the list of endpoints called from my iPhone.
I have verified that CharlesProxy is configured correctly as I am able to inspect non-websocket traffic even under SSL.
So my question is: did anyone find a solution to inspect traffic going through websockets with CharlesProxy?
Note: I have ATS disabled when using iOS9
Thanks!
I finally found the answer.
Charles 3.11.2 works perfectly with WebSocket.
I use socketIO, so I've already seen http requests sent during the negotiation phase, but I missed websockets traffic.
In the beginning, socketIO try to use polling then switches to use websockets.
The websocket traffic is visible when you go to the request with status: "Sending request body" which is actually wss:// request.
You even have a dedicated tab for this kind of traffic. The rest of messages will appear right there.
PS1. Ensure you're connected to socket properly then it appears in Charles.
PS2. I suggest using socketIO it's a great enhancement for full-duplex traffic like websockets.
UPDATE: Apparently socket.io-client-swift v15.1.0 now properly supports SOCKS proxy. I have not yet tried it, but it would mean that these manual edits to Starscream are no longer required.
The accepted answer does not seem to work with Socket.IO on iOS devices.
The latest version of Socket.IO-Client-Swift (15.0.0 at the time of writing) uses Starscream for WebSockets on iOS/OS X.
The good news is that Starscream supports SOCKS proxying however:
Socket.IO does not expose the Starscream websocket or provide any API for enabling the SOCKS proxying behaviour.
The SOCKS proxying built into Starscream uses the OS SOCKS proxy settings which are cumbersome to setup (at least for iOS).
If I get some time I might propose a PR to address this more thoroughly, but given that it requires work to both Starscream and Socket.IO-Client-Swift, this is not entirely straightforward.
The easiest way to hack around this for temporary debugging purposes (which is the use case for Charles!), is to edit the WebSocket.swift
file as part of Starscream, and replace this code:
if enableSOCKSProxy {
let proxyDict = CFNetworkCopySystemProxySettings()
let socksConfig = CFDictionaryCreateMutableCopy(nil, 0, proxyDict!.takeRetainedValue())
let propertyKey = CFStreamPropertyKey(rawValue: kCFStreamPropertySOCKSProxy)
CFWriteStreamSetProperty(outputStream, propertyKey, socksConfig)
CFReadStreamSetProperty(inputStream, propertyKey, socksConfig)
}
with this code:
let socksConfig = CFDictionaryCreateMutableCopy(nil, 0, CFNetworkCopySystemProxySettings()!.takeRetainedValue()) as! [String: Any]
let propertyKey = CFStreamPropertyKey(rawValue: kCFStreamPropertySOCKSProxy)
let ip = socksConfig["HTTPSProxy"]
let proxySocksConfig = ["SOCKSProxy": ip, "SOCKSPort": 8889, "SOCKSEnable": true] as CFDictionary // Where 8889 is the SOCKS proxy port in Charles
CFWriteStreamSetProperty(outputStream, propertyKey, proxySocksConfig)
CFReadStreamSetProperty(inputStream, propertyKey, proxySocksConfig)
This will ensure the SOCKS proxy is enabled by default, and will route all the websockets traffic via Charles.
You then need to ensure that the HTTP proxy settings are configured in iOS (since the same IP will be used for both HTTP and SOCKS), SOCKS proxy is enabled in Charles, and that the port matches the port in the code above (by default 8889).
Thanks for your very very helpful answer Jonathan Ellis! I'm using Pusher and this worked great!
However, I found socksConfig
to not always contain valid data and didn't work or would crash the app when I pulled the IP from there. Since the only thing we are getting from there is the localhost IP I just replaced the following in WebSocket.swift
if enableSOCKSProxy {
let proxyDict = CFNetworkCopySystemProxySettings()
let socksConfig = CFDictionaryCreateMutableCopy(nil, 0, proxyDict!.takeRetainedValue())
let propertyKey = CFStreamPropertyKey(rawValue: kCFStreamPropertySOCKSProxy)
CFWriteStreamSetProperty(outputStream, propertyKey, socksConfig)
CFReadStreamSetProperty(inputStream, propertyKey, socksConfig)
}
with this:
let propertyKey = CFStreamPropertyKey(rawValue: kCFStreamPropertySOCKSProxy)
let proxySocksConfig = ["SOCKSProxy": "127.0.0.1", "SOCKSPort": 8889, "SOCKSEnable": true] as CFDictionary // Where 8889 is the SOCKS proxy port in Charles
CFWriteStreamSetProperty(outputStream, propertyKey, proxySocksConfig)
CFReadStreamSetProperty(inputStream, propertyKey, proxySocksConfig)
And then enabled the socks proxy in Charles as you described.
Thanks Again!
来源:https://stackoverflow.com/questions/33090087/how-to-inspect-websocket-traffic-with-charlesproxy-for-ios-simulator-devices