There
are several available mechanisms for obtaining resources over network
connections on the iPhone, depending on whether your needs are for
loading content over HTTP/FTP, doing lower level socket manipulation, or
networking with other devices over Bluetooth. We’ll look first at the
most common mechanism, the URL loading API.
The URL Loading API
The
URL Loading API supports HTTP, HTTPS, FTP, and file resource types;
these can be extended by subclassing the NSURLProtocol class. The normal
way to interface to this API is via NSURLConnection or NSURLDownload,
using an NSURL object as the input (see Listing 1).
Listing 1. Using NSURLConnection (Sample Code from Apple’s “URL Loading System Overview”)
NSURL *myURL = [NSURL URLWithString:@"https://cybervillains.com/"];
NSMutableURLRequest *myRequest = [NSMutableURLRequestrequestWithURL: myURLcachePolicy:NSURLRequestReload IgnoringCacheDatatimeoutInterval:60.0];
[[NSURLConnection alloc] initWithRequest:myRequest delegate:self];
|
The request object
simply gathers all the properties of the request you’re about to make,
with NSURLConnection performing the actual network connection. Requests
have a number of methods controlling their behavior—one method that
should never be used is setAllowsAnyHTTPSCertificate.
I hesitate to even mention
it, should it make some foolhardy developer aware of it. However, for
the benefit of penetration testers and QA engineers who have to look
specifically for terrible ideas, I’ll specifically call out: Don’t use
this method. The correct solution is to update the certificate store.
By default, HTTP and
HTTPS request results are cached on the device. For increased privacy,
you may consider changing this behavior using a delegate of
NSURLConnection implementing connection:willCacheResponse (see Listing 2).
Listing 2. Using NSURLConnection
-(NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse {
NSCachedURLResponse *newCachedResponse=cachedResponse; if ([[[[cachedResponse response] URL] scheme] isEqual:@"https"]) { newCachedResponse=nil; } return newCachedResponse; }
|
One
surprise about the NSURL family is that all cookies stored are
accessible by any application that uses the URL loading system (http://developer.apple.com/iphone/library/documentation/Cocoa/Conceptual/URLLoadingSystem/Concepts/URLOverview.html#//apple_ref/doc/uid/20001834-157091).
This underscores the need to set reasonable expiration dates on
cookies, as well as to refrain from storing sensitive data in cookies.
NSStreams
Cocoa Socket Streams are most
useful when the need arises to use network sockets for protocols other
than those handled by the URL loading system, or in places where you
need more control over how connections behave. To do this, you have to
create an NSStream object, instructing it to receive input, send output,
or both. For most networking purposes, both will be required (see Listing 3).
Listing 3. Creating a Socket Stream
// First we define the host to be contacted NSHost *myhost = [NSHost hostWithName:[@"www.conglomco.com"]];
// Then we create [NSStream getStreamsToHost:myhost port:80 inputStream:&MyInputStream outputStream:&MyOutputStream];
[MyInputStream setProperty:NSStreamSocketSecurityLevelTLSv1 forKey:NSStreamSocketSecurityLevelKey];
// After which you'll want to retain the streams and open them
|
The
key here is to set NSStreamSocketSecurityLevel appropriately. For
almost all situations, NSStreamSocketSecurityLevelSSLv3 or
NSStreamSocketSecurityLevelTLSv1 should be used. Unless, you’re writing a
program where transport security just doesn’t matter (for example, a
web crawler), SSLv2 or security negotiation should not be used.
Peer to Peer (P2P)
iPhone OS 3.0
introduced the ability to do P2P networking between devices via
Bluetooth. Although technically part of the GameKit, the GKSession class
is likely to be used by non-game applications as well, for
collaboration and data exchange. This means that opportunities for data
theft are increased. Also, because data can potentially be streamed to
the device by a malicious program or user, we have another untrusted
input to deal with.
GKSessions can behave in
one of three different modes—client, server, or peer (a combination of
client and server). The easiest way to interface to this functionality
is through a GKPeerPickerController object, which provides a UI to allow
the user to select from a list of peers. It should be noted, however,
that using this controller is not required. This effectively allows an
application to initiate or scan for a session without user interaction.
To find other devices (peers),
a server device advertises its availability using its sessionID, while a
client device polls for a particular ID. This session identifier can be
specified by the developer, or, if it’s unspecified, it can be
generated from the application’s App ID.
Because of the use of
developer-specified sessionIDs and the ability to have background P2P
activity, issues can arise where a developer uses a GKSession to
advertise or scan in the background, pairing with any matching device
that knows a shared sessionID. If sessionIDs are predictable, this means
that the user’s device might be paired without their knowledge and
against their will. This can lead to all manner of mischief.
In addition to
simple Bluetooth connectivity, the GKVoiceChatService allows for
full-duplex voice communication between devices. This is another
connection that can be done without user interaction. To establish a
voice connection with another device, another developer-specified
identifier is needed, the participantID. Because an active pairing is
already necessary for the use of Voice Chat, this ID can be a simple
username or other symbolic name.
Here are the three main important security considerations when working with the GameKit:
Ensure that you
use a unique identifier for the sessionID to avoid unwanted peering, and
use the provided Picker API to let users explicitly accept connections.
Remember that GKSession remote connections supply untrusted data—sanity checks must be performed before operating on this data.
Use GKPeerPickerController to allow users to confirm connections.