At QCon New York 2016, Trail of Bits CEO and security expert Dan Guido explained how to keep iOS apps secure. This includes correctly using all iOS security provisions, without forgetting that your app might be running on a jailbroken phone.
As Guido explains, iOS app security lies within the operating system layer, which provides application code signing and a sandbox model. Code signing makes it possible to trace every 4KB page to a human owner, while the sandbox model restricts apps from accessing other apps and protects system files and resources, thus making it hard even for a malicious app to cause any trouble.
The cornerstone of iOS security, says Guido, is the Secure Enclave, a unique device key that is fused at manufacture time and is not accessible at the app level, meaning that secure keys cannot be read outside of the Secure Enclave. This is used for all encryption operations on iOS and for Apple Pay and Keychain protection.
For developers, three are the basic tenets of iOS app security, according to Guido:
- Using HTTPS exclusively. This is accomplished by always specifying
https
in the URL. In such cases,NSURLConnection
andNSURLSession
use App Transport Security (ATS), which ensures you use properly TLS 1.2, certificate validation, and so on. Guido additionally suggests using TrustKit, a framework that makes it easy to deploy SSL public key pinning in any iOS or OS X App and to monitor pinning validation failures. - Using encryption. DPAPI and the Keychain should be used to encrypt all files, passwords, and tokens. Guido spends a few moments to describe the options that are available with DPAPI:
- to encrypt files:
NSFileProtectionComplete
,NSFileProtectionCompleteUnlessOpen
,NSFileProtectionCompleteUntilFirstAuth
; - to write
NSData
to disk:NSDataWritingProtectionComplete
,NSDataWritingProtectionCompleteUnlessOpen
,NSDataWritingProtectionCompleteUntilFirstAuth
.
- to encrypt files:
- Cleaning up. This is a fundamental step to avoid leaving sensitive data behind. While it is true that nearly all files are encrypted when stored on disk, Guido warns against a number of pitfalls. In particular, iTunes backups are stored unencrypted, so it becomes possible to steal sensitive data by attacking a desktop OS instead of iOS. Guido mentions you can prevent syncing to iCloud or iTunes by using the
NSURLIsExcludedFromBackupKey
key. Additionally, apps usually leave behind a certain amount of potentially sensitive, unencrypted data in theUIPasteboard
, or in the URL or keyboard cache, the app backgrounding snapshot that iOS automatically takes, cookies,NSLog
entries, and so on. All of these risks can be avoided by following the proper policy, e.g., overridingapplicationDidEnterBackground
and settinghidden
toYES
; usesecureTextEntry
and disabling autocorrection to circumvent the keyboard cache, etc.
Once you are done with the basics, concludes Guido, you can think about additional levels of mitigations, such as using custom URL handlers, XSS in UIWebView
, XML parsing, SQL injections, etc.
However, all of those provisions are not effective when your app runs on a jailbroken phone. Jailbreaks are exploits that disable fundamental security mechanisms. They can be used to attack a phone and get control of it, but the interesting fact about them is that users will voluntarily jailbreak their phones for a number of reasons, such as to get access to 3rd-party app stores, replace default apps, customize the OS look and feel, and unlock their devices. According to Guido, up to 7 million of iPhone users have jailbroken their phones, which means that a malicious app running on them can bypass all device security, such as Keyraider, which stole Apple ID credentials for in-app purchases from 225,000 devices.
There are several approaches to improve the security of an app running on jailbroken iPhones:
- Detecting when running on a jailbroken device by looking at system artifacts left over from successful jailbreaks. Often, this comes down to implementing a number of checks, such as for the existence of ssh, Cydia.app files, the
fork()
system call, and others. - Deny attempts to debug or hook an application, to prevent attackers from bypassing Jailbreak checks using a debugger or specific tools such as tsProtector or xCon. Usually, this can be done at runtime by using
sysctl
to find out who is the app’s parent: if it is notlaunchd
or the kernel, then you can exit or alter execution. - Make it hard to understand disassembled app code generated using IDA Pro, Hopper, or Binary Ninja. This can be achieved through a number of obfuscation techniques to add 100x more code which is not used, encrypting symbols, using predicates, etc.
As a final note, Guido remarks the importance of enforcing all of the above provisions universally, by using a modified version of LLVM that modifies the code while compiling it, and not relying on individual programmers to add checks where needed.
Watch the full video session on InfoQ.