Mobile Application Security : The Apple iPhone - Local Data Storage: Files, Permissions, and Encryption

1/15/2011 9:40:31 AM
As mobile applications store more and more local data, device theft is becoming an increasing concern, especially in the enterprise. To ensure that data cannot be obtained either by theft of the device or by a network attacker, we’ll look at best practices for storing local data securely. Developers must not rely on the “device encryption” functionality of the iPhone 3GS; this mechanism is not robust against a dedicated attacker (see, and special effort must still be made by the developer to keep data safe.

SQLite Storage

A popular way to persist iPhone application data is to store it in an SQLite database. When using any type of SQL database, you must consider the potential for injection attacks. When writing SQL statements that use any kind of user-supplied input, you should use “parameterized” queries to ensure that third-party SQL is not accidentally executed by your application. Failure to sanitize these inputs can result in data loss and/or exposure.

Listing 1 shows the wrong way to write SQLite statements.

Listing 1. Dynamic SQL in SQLite
NSString *uid = [myHTTPConnection getUID];
NSString *statement = [NSString StringWithFormat:@"SELECT username
users where uid = '%@'",uid];
const char *sql = [statement UTF8String];
sqlite3_prepare_v2(db, sql, -1, &selectUid, NULL);
sqlite3_bind_int(selectUid, 1, uid);
int status = sqlite3_step(selectUid);

Here, the parameter uid is being fetched from an object that presumably originates from input external to the program itself (that is, user input or a query of an external connection). Because the SQL string is concatenated with this external input, if the string contains any SQL code itself, this will be concatenated as well, thus causing unexpected results.

A proper, parameterized SQL query with SQLite is shown in Listing 2.

Listing 2. Parameterized SQL in SQLite
const char *sql = "SELECT username FROM users where uid = ?";
sqlite3_prepare_v2(db, sql, -1, &selectUid, NULL);
sqlite3_bind_int(selectUid, 1, uid);
int status = sqlite3_step(selectUid);

Not only is this safer by ensuring that uid is numeric, but you’ll generally get a performance boost using this technique over dynamic SQL query construction. Listing 3 shows similar binding functions for other data types.

Listing 3. SQLite Binding
sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n,
sqlite3_bind_double(sqlite3_stmt*, int, double);
sqlite3_bind_int(sqlite3_stmt*, int, int);
sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64);
sqlite3_bind_null(sqlite3_stmt*, int);
sqlite3_bind_text(sqlite3_stmt*, int, const char*, int n,
sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int,
sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);

Of course, now that Core Data is supported in iPhone OS 3.0, this will likely become the preferred method of data storage. Core Data internally saves information to a SQLite database by default. Using Core Data is generally a good approach, but it does remove some flexibility—an example would be using custom builds of SQLite such as SQLCipher, which can provide transparent AES encryption. Secure storage of smaller amounts of data can be done with the Keychain.

iPhone Keychain Storage

The iPhone includes the Keychain mechanism from OS X to store credentials and other data, with some differences in the API and implementation. Because the iPhone has no login password, only a four-digit PIN, there is no login password to use for the master encryption key on the iPhone. Instead, a device-specific key is generated and stored in a location inaccessible to applications and excluded from backups.

The API itself is different from the regular Cocoa API, but somewhat simpler. Rather than secKeychainAddInternetPassword, secKeychainAddGenericPassord, and so on, a more generic interface is provided: SecItemAdd, SecItemUpdate, and SecItemCopyMatching.

Another difference with the iPhone Keychain is that you can search for and manipulate Keychain items by specifying attributes describing the stored data. The data itself is stored in a dictionary of key/value pairs. One thing common to the Keychain on both platforms, however, is that it’s somewhat painful to use, considering most people just need to save and retrieve passwords and keys.


A complete list of available attributes is available at here.

The iPhone Keychain APIs only work on a physical device. For testing in a simulator, one has to use the regular OS X Keychain APIs. One reasonable simplification to this process is by Buzz Andersen, at This code shows how to use a simple API for setting and retrieving Keychain data, which uses OS X native APIs when built for a simulator but iPhone APIs for a device build.

Shared Keychain Storage

With iPhone OS 3.0, the concept of shared Keychain storage was introduced, allowing for separate applications to share data by defining additional “Entitlements” . To share access to a Keychain between applications, the developer must include the constant kSecAttrAccessGroup in the attributes dictionary passed to SecItemAdd as well as create an Entitlement.

The Entitlement should take the form of a key called “keychain-access-groups” with an array of identifiers that define application groups. For instance, an identifier of com.conglomco.myappsuite could be added to all apps that Conglomco distributes, allowing sign-on to Conglomco services with the same credentials. Each application will also contain its own private section of the Keychain as well.

What keeps other applications from accessing your shared Keychain items? As near as I can tell, nothing. This is another area where the App Store will probably be relied upon to weed out malicious apps. However, until more details are published about the proper use of shared Keychains, it is probably prudent not to store sensitive data in them—which is to say, don’t use them at all.

Adding Certificates to the Certificate Store

If you need to work with the iPhone using Secure Sockets Layer (SSL) in a test environment—and you should configure your test environment to use SSL!—here are three different options you have:

  • Install your internal CA certificate on a machine that syncs to an actual iPhone via iTunes.

  • Retrieve the certificate from a web server using Safari.

  • Mail the certificate to the phone.

Because in all likelihood you’ll be working primarily with the iPhone emulator, the second option is your best bet. When accessing a certificate via e-mail or Safari, you will be prompted with the “Install Profile” dialog (see Figure 1). Clicking “Install” will store the certificate in the phone’s internal certificate store. As of iPhone OS 3.0, you can remove these or view certificate details (see Figure 2) by going to Settings | General | Profiles.

Figure 1. Installing a third-party CA certificate

Figure 2. Certificate details

Acquiring Entropy

Strong entropy on the iPhone is acquired through the SecRandomCopyBytes API, which reads random data from the device’s Yarrow Pseudo-Random Number Generator, a.k.a. /dev/random (see

This function takes three parameters: the random number generator to use (which will always be kSecRandomDefault at this point), the number of random bytes to return, and the array in which to store them. A sample usage can be found in the CryptoExercise sample code provided on ADC (see Listing 4).

Listing 4. Generating a Symmetric Key
symmetricKey = malloc (kChosenCipherKeySize * sizeof(uint8_t));
memset((void *)symmetricKey, 0x0, kChosenCipherKeySize);
sanityCheck = SecRandomCopyBytes(kSecRandomDefault,

  •  Mobile Application Security : The Apple iPhone - Permissions and User Controls
  •  iPhone Application Developmen : Using the View-Based Application Template (part 3)
  •  iPhone Application Developmen : Using the View-Based Application Template (part 2) - Preparing the View Controller Outlets and Actions
  •  iPhone Application Developmen : Using the View-Based Application Template (part 1)
  •  Mobile Application Security: Application Format
  •  Mobile Application Security: Security Testing
  •  Mobile Application Security: The Apple iPhone - Development
  •  Building Android Apps : Installing KiloGap in the Emulator
  •  Building Android Apps : Build KiloGap
  •  Building Android Apps: Create an Android Virtual Device
  •  Building Android Apps: Going Native - Setting Up the Environment
  •  Building Android Apps: Introduction to PhoneGap
  •  iPhone Application Development : How Xcode and Interface Builder Implement MVC
  •  iPhone Application Development : Understanding the Model-View-Controller Paradigm
  •  Building Android Apps: Going Offline - Debugging
  •  Building Android Apps: Creating a Dynamic Manifest File
  •  Building Android Apps: Online Whitelist and Fallback Options
  •  The Basics of the Offline Application Cache
  •  Building Android Apps: Web SQL Database (part 4) - Deleting Rows
  •  Building Android Apps: Web SQL Database (part 3) - Selecting Rows and Handling Result Sets
    Top 10
    SQL Injection : Platform-Level Defenses - Securing the Database
    SQL Injection : Platform-Level Defenses - Using Runtime Protection (part 2) - Intercepting Filters
    SQL Injection : Platform-Level Defenses - Using Runtime Protection (part 1) - Web Application Firewalls
    HP ProLiant Servers AIS : Server Chipsets (part 2) - ProFusion Chipset, F8 Chipset
    HP ProLiant Servers AIS : Server Chipsets (part 2) - Parallel I/O Buses, Highly Parallel System Architecture
    HP ProLiant Servers AIS : Server Chipsets (part 1) - Original Server Architecture, Dual Independent Buses, Bus Mastering, MIOC Architecture
    Personalizing Windows 8 : Choosing Your Language
    Personalizing Windows 8 : Tweaking Your Touch Experience
    Windows Server 2003 : Hardening IPSecurity Policies
    Windows Server 2003 : Extending IPSec Operations, Designing IPSec Policies to Meet Secure Communications Needs
    Most View
    The Differences Between Samsung Galaxy Note 10.1 And Galaxy Tab
    Handling Mobile User Input (part 1) - Assessing Mobile Game Input, Handling Key Input with the GameCanvas Class
    Introducing IIS 7
    Are Analytics Cookies Legal? (Part 2)
    Algorithms for Compiler Design: THE ARRAY REFERENCE
    Windows XP : Troubleshooting and Recovering from Problems (part 1)
    .NET Security : Programming the Event Log Service (part 1) - Querying the Event Log System, Using Event Sources
    Windows Vista : Performing Local PC Administration (part 2) - Performing common workstation administration tasks
    Migrating from Legacy SharePoint to SharePoint Server 2010 : Planning for an Upgrade to SharePoint 2010
    Google's Chromebox
    Business Intelligence in SharePoint 2010 with Business Connectivity Services : External Content Types (part 1)
    System Center Configuration Manager 2007 : Developing the Solution Architecture (part 3) - Developing the Server Architecture
    WCF Services : Delegates and Data Contracts
    All the stuff you didn't know (Part 2)
    $150 Android HD/3D Player
    Programming with DirectX : Shading and Surfaces - Implementing Texture Mapping (part 2) - Multi Texture Demo
    Mobile Application Security : SMS Security - Overview of Short Message Service
    AMD Radeon HD 7870
    Toshiba AT200-101
    Logitech Introduced The First Personal Customized IEM Headphones