As part of Thali we need to enable iOS and Android devices to communicate to each other just using local radios. For reasons explained below the only way we can figure out how to do this involves security issues and user intervention on the iOS side. If anyone has any better way to make this work I’m all ears!
For the Thali Project we need to enable devices to communicate with each other locally. That is, without any Internet infrastructure. This is possible but only in a way so complicated and insecure that one wonders if it’s workable in the real world. To understand the awful solution, let’s look at the problem. If you pull out your cell phone you will find that you likely have at least three options for communicating with other devices locally:
- Bluetooth Low Energy (BLE)
The good news is that iOS and Android support all three of these. In fact, BLE seems to work reasonably well between iOS and Android. The problem is that BLE is glacially slow. One can expect to move a megabyte of data in around 30 seconds. So while this makes BLE a great signaling channel between iOS and Android, it can’t reasonably be used for moving big data.
Bluetooth would be a great choice for iOS/Android interop since it is designed for ad-hoc communication but unfortunately, near as we can tell, Apple has added their own proprietary extension to Bluetooth that will only allow iOS devices to accept Bluetooth connections from folks who present a cert that is rooted with Apple’s key. To get such a cert one apparently has to join Apple’s MFI program and pay money. We can’t do that as an open source project so that means we can’t use Bluetooth as a way to communicate between Android and iOS.
Finally we have Wi-Fi. Here the situation gets murky. Apple has something they call the Multi-Peer Connectivity Framework. It enables P2P connections using local radios (Bluetooth and Wi-Fi) between iOS and OS/X devices. So Apple already supports Wi-Fi for P2P. However they have set up the Wi-Fi so that its P2P functionality doesn’t use the industry standard Wi-Fi Direct protocol but rather uses some other, apparently proprietary protocol from Apple. So we aren’t going to be able to get Multi-Peer Connectivity to work with Android. And we can’t use Android’s support for Wi-Fi Direct since iOS doesn’t seem to support it.
So what we are left with is that on Android we can use an API to turn an Android phone into a WiFi Access Point (AP). This allows the iOS device to connect to the Android phone in exactly the same way it can connect to any Wi-Fi AP. The problem is that iOS doesn’t support any APIs to allow apps to control the device’s Wi-Fi configuration. So to get the iOS device to actually connect to the Android AP we have to do something like this:
- We use BLE to enable an iOS and Android device to find each other.
- The Android device then turns itself into a WiFi AP and over BLE we tell the iOS device the name of the access point.
- The iOS device then displays a message to the user that says something to the effect of “Dear User, please exit this app, go to Settings->Wi-Fi and choose the access point ’foo’ and then please come back to this app.” If the user does all of that then the iOS device can connect to the Android device.
There are some obvious questions to ask about this approach.
Do we really expect users to figure out how to change their Wi-Fi AP? The answer is - yes, we do. We don’t like it, but we don’t seem to have any choice. The mildly good news is that once the iOS and Android devices are done communicating the Android device can programmatically turn off its WiFi AP and the iOS user doesn’t need to do anything further. Also note that no where in here did the Android user ever have to take any actions. The WiFi setup and tear down is completely programmatic. So while this experience is almost comically bad for the iOS user it’s fine for the Android user. And at least it will work. Which given how hard it has been to get Android and iOS to interop is certainly something.
We said above that when the Android and iOS devices are done talking then the Android device can shut down its WiFi AP. Which is true. But what if the Android device doesn’t do that? Or what if it does do that but at some point later it turns the WiFi AP back on while in range of the iOS device and uses the same SSID?
In each of these cases the iOS device is now connected to the Android device and all Internet communications from the iOS device are going to go through the Android device. Everything.
This threat is essentially identical to what happens if someone connects to a random Wi-Fi AP in order to get Internet. If that Wi-Fi AP isn’t trustworthy then it can intercept, examine, manipulate, etc. all Internet traffic from the phone.
Now if the phone is reasonably secure and exclusively uses HTTPS or equivalent for all connections then we are at worst inconvenienced. But what about communications that are sent in the clear? Well, in that case the Android phone can see and change everything.
Let’s imagine that the Android phone is a “good actor”. But there is another bad actor in the vicinity. In that case the bad actor can easily see what SSID the Android phone is using and can either try to hijack the SSID for itself or can just wait until later and advertise the SSID around the iOS device. In either case the bad actor can likely fool the iOS device into connect to it and at that point we are in the same situation as the previous question.
From Thali’s perspective this is a denial of service attack, not a security breach. The reason is that all Thali connections are authenticated with mutual TLS auth. So it doesn’t matter if someone hijacks the AP SSID (the name of the connection) and impersonates the Android device. They aren’t going to get any data, at least not from Thali. The problem is that an iOS device has lots of other apps (including web browsers) that are likely not using HTTPS or equivalent and so they are vulnerable.
In theory we could prevent the hijack attack all together by putting a password on the Android WiFi AP and then sending that password over to the user via BLE encrypted with the user’s Thali public key. This should prevent any hijack attacks. But it also creates a user experience that we think is unworkable. We would have to ask the user not just to switch their Wi-Fi AP but to also remember some at least 8 or 10 digit randomly generated password.
Another approach is to restrict what SSID names we use. iOS, for example, will not auto-join networks that have certain names like “default” or “linksys’ or “dlink” or what have you. These are the default names used by popular Wi-Fi routers and by blocking them from auto-connection iOS prevents users from accidentally connecting to whatever random Wi-Fi AP is in the vicinity. So in theory we could use a name like that for the Android WiFi AP. This wouldn’t prevent an attack happening if the attacker is right there when the Android and iOS devices happen to connect. But it would prevent future “drive by” attacks. Still, what happens if there are multiple Android and iOS devices that want to connect in the same room? How many of these reserved names are there? Each Android WiFi endpoint would have to use a different one. Still, this is an approach worth investigating.
It doesn’t look technically possible to connect Android and iOS devices in the same seamless way one can connect Android to Android or iOS to iOS. The best we can do is expose iOS users to security threats by using the WiFi hack. By using certain restricted SSID names we might be able to limit the threat but that is a palliative, not a cure. All in all the situation is truly sad. If anyone has a better way to handle Android to iOS connectivity in environments without Internet infrastructure I’m all ears!