Any app that connects over the Internet
to a hosted service must have a security policy in place. The security policy
will depend primarily on the sensitivity of the data being transferred between
the app and the server. However, even if the app doesn’t transfer sensitive
customer information, it should protect itself from attack. Even the least
harmful attack will ruin the user’s experience and the app’s reputation.
Today most web services (including Twitter and Facebook) require
request authentication with OAuth
as part of getting login credentials from the user. The developer gets a
consumer and secret key after registering the app. When the app accesses the
web service, the app first exchanges its encoded keys for a bearer token. For
the life of this token, the app has permission to access the service’s API.
It is highly recommended that your
app access a web service that is protecting itself with OAuth authentication.
Along with OAuth, there is HTTPS,
which puts HTTP on top of the SSL/TLS protocol, providing data encryption and
X.509 certificate exchange. It is possible with iOS to use only the data
encryption and turn off certificate exchange, but in most cases this isn’t
necessary. Apple has installed many root certificates from trusted certificate
If the server your app is accessing
has a self-signed certificate installed, you can continue without or bypass the
credential you receive with the authentication challenge. Or, because you know
the host in advance, you can trust it. Either way, you are not protected from a
man-in-the middle attack.
A man-in-the-middle attack is a form of active
eavesdropping in which the attacker inserts itself in the middle of an Internet
connection between the iOS app and a server. The diagram in Figure
A shows the attacker’s steps, labeled 1 through 5.
- Normal traffic between mobile app and server.
- The attacker gets the request from the app and makes
changes to it.
- The request is forwarded to the server.
- The attacker gets the response from server and makes
- The response is forwarded to the app.
Apps that transfer sensitive customer
data, like credit card and payment information, must be protected from
man-in-the middle attacks. The best protection is a mutual authentication
scheme, where certificates are exchanged to make sure the app is connected to a
trusted server and to make sure the server is connected to a trusted app.
will be assuming the NSURLConnection class is used, without a third-party
library, to connect to a server. For our example, the NSURLConnectionDelegate protocol
methods will handle the authentication.
Since iOS 5, the following
connection delegate methods have been deprecated:
have been replaced by the willSendRequestForAuthenticationChallenge
method; only when this method is not implemented will the deprecated methods
get called. We will implement this method to perform the client and the server
Client certificate validation
server validates the client’s certificate. The server’s administrator provides
the client certificate. Its private key is stored on the server, and the public
key is provided as part of the authentication challenge. The iOS app stores the
certificate in DER format. It may be necessary to convert from PEM to DIR
$ openssl x509 –inform PEM –outform DER –in cert.pem –out cert.der
Add the cert.der file to the iOS app’s resource bundle; this is only the
public key, so it is safe to store. The following method, shouldTrustProtectionSpace,
loads the certificate from the main bundle, creates a certificate from the
loaded data, and establishes a chain of trust in the server’s protection space,
anchored on the bundled certificate.
The Security framework must be included in the Xcode project.
established server trust is evaluated. The following shows the possible results
from the Apple documentation.
- kSecTrustResultInvalid: Invalid setting or result indicates evaluate
failed to complete successfully
- kSecTrustResultProceed: You may trust the
- kSecTrustResultConfirm: Ask permission from the
- kSecTrustResultDeny: The certificate should not
- kSecTrustResultUnspecified: The user did not specify a
- kSecTrustResultRecoverableTrustFailure: Trust denied but may retry
after changing setting.
- kSecTrustResultFatalTrustFailure: Trust denied and no simple
fix may be applied
- kSecTrustResultOtherError: A failure other than trust
may recover from a recoverable trust failure by getting and setting the
exceptions in the established server trust and re-evaluating.
if (trustResult == kSecTrustResultRecoverableTrustFailure)
CFDataRef errDataRef = SecTrustCopyExceptions(serverTrust);
Server certificate validation
server authentication, the SSL certificate used for the HTTPS connection is
compared with a certificate stored on the client. Following the instructions in
the article How to Validate SSL Certificates on iOS, we compare the certificate data hashes. SHA256 is used to keep it
simple and reasonably secure. Implement the SHA256 method as shown in the
Putting it all together
The willSendRequestForAuthenticationChallenge delegate
method calls shouldTrustProtectionSpace to handle the client certification
validation. If the certificate validates successfully, the server’s certificate
is retrieved, hashed, and compared to the hash value EXPECTED_CERTIFICATE_BASE64_SHA256.
If the certificate hash values match, the challenge sender’s
useCredential method is called (success!). Otherwise, the challenge sender’s cancelAuthenticationChallenge
method must be called. This will trigger a call
to the didCancelAuthenticationChallenge protocol method. Here is where you may
inform the user that the connection failed.
Not all iOS apps that connect to a web service need to
implement a mutual authentication scheme. They should connect to a web service
that requires OAuth authentication. For those apps that transfer sensitive
customer data, mutual authentication is the best protection.
- Enforcing Trusted SSL Certificates on iOS and OS X (Indelible.org)
- Certificate, Key, and Trust Services Reference (iOS Developer Library)
- Creating PKCS12 Certificates (Flat Mountain)