⬆️ ⬇️

Database Security in iOS





The vulnerability of information stored in databases is one of the most common security problems for iOS applications. Many programs offer the user to use a password to access the data - but in most cases this does not in any way affect the form in which the information itself is stored. Thus, data from applications such as password managers, notepads, organizers, trackers, finance, can be accessed by almost any outsider who will have your device in his hands.



When you install an application within the / var / mobile / Applications / directory, a directory is created that serves as its sandbox. It limits almost all possible actions of the application. This is where NSUserDefaults tinctures, other plist files, Cookies, as well as databases and other resources that can be changed by the user are stored. To access this directory, no Jailbreak should be installed on the device - this is possible using any file manager (for example, iFunBox ).



As an illustration of the prevalence of this vulnerability, we take an application that constantly flashes in the paid top of the App Store - Smart Safe .

')

With the help of iFunBox, let’s look at the contents of the / Documents folder In addition, it contains the following files: notes.sqlite , notes.sqlite-shm , notes.sqlite-wal . The notes.sqlite database contains three tables:



Of particular interest is the first of them. The ZDATE field contains the publication date, ZBODY contains the note text, and ZTITLE contains the title of the note. All text is not encrypted and stored in clear form:







Disclaimer
The developer was notified of the discovered vulnerability, but no comments and / or corrections followed. The mentioned vulnerability is not the only one, the application stores absolutely all data in the clear.



One way to deal with this vulnerability is to use the SQLCipher framework, which supports transparent encryption on the fly. For all cryptographic functions (AES256, pseudo-random number generator, PBKDF2 keys), SQLCipher uses the OpenSSL library. Detailed descriptions, documentation and assemblies can be found at this link .



As part of this article, we will look at using SQLCipher with FMDatabase , a popular wrapper for working with SQLite databases in Cocoa.



If you use Cocoapods, then in order to add FMDatabase and SQLCipher to the project, it is enough to add the line pod 'FMDB / SQLCipher' to the podfile. Now let's turn to AppDelegate.m :



- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentDir = [documentPaths objectAtIndex:0]; self.databasePath = [documentDir stringByAppendingPathComponent:@"sqmple.sqlite"]; [self createAndCheckDatabase]; return YES; } -(void) createAndCheckDatabase { BOOL success; NSFileManager *fileManager = [NSFileManager defaultManager]; success = [fileManager fileExistsAtPath:self.databasePath]; if (success) return; // If file exists, don't do anything // if file does not exist, make a copy of the one in the Resources folder NSString *databasePathFromApp = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"sample.sqlite"]; // File path [fileManager copyItemAtPath:databasePathFromApp toPath:self.databasePath error:nil]; // Make a copy of the file in the Documents folder // Set the new encrypted database path to be in the Documents Folder NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentDir = [documentPaths objectAtIndex:0]; NSString *encryptedDatabasePath = [documentDir stringByAppendingPathComponent:@"encrypted.sqlite"]; NSString *key = @"PassKey"; // SQL Query. NOTE THAT DATABASE IS THE FULL PATH NOT ONLY THE NAME const char* sqlQ = [[NSString stringWithFormat:@"ATTACH DATABASE '%@' AS encrypted KEY '%@';", encryptedDatabasePath, key] UTF8String]; sqlite3 *unencrypted_DB; if (sqlite3_open([self.databasePath UTF8String], &unencrypted_DB) == SQLITE_OK) { // Attach empty encrypted database to unencrypted database sqlite3_exec(unencrypted_DB, sqlQ, NULL, NULL, NULL); // export database sqlite3_exec(unencrypted_DB, "SELECT sqlcipher_export('encrypted');", NULL, NULL, NULL); // Detach encrypted database sqlite3_exec(unencrypted_DB, "DETACH DATABASE encrypted;", NULL, NULL, NULL); sqlite3_close(unencrypted_DB); } else { sqlite3_close(unencrypted_DB); NSAssert1(NO, @"Failed to open database with message '%s'.", sqlite3_errmsg(unencrypted_DB)); } self.databasePath = [documentDir stringByAppendingPathComponent:@"encrypted.sqlite"]; } 


That's all, the encrypted database is created and you can begin to work with it. Write the method to open the database:



 - (FMDatabase *)openWriteableDatabase { NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsDirectory = [paths objectAtIndex:0]; NSString *writableDBPath = [documentsDirectory stringByAppendingPathComponent:@"encrypted.sqlite"]; FMDatabase* database = [FMDatabase databaseWithPath:writableDBPath]; [database open]; NSString *key = @"PassKey"; [database setKey:key]; return database; } 


With the database opened in this way, you can perform any actions: adding rows, deleting them, and so on. Of course, when working with an encrypted database, it is not recommended to use a static key embedded in the application code. A good alternative would be to develop a method for dynamically generating a key unique to each device (for this you can use a combination of different parameters, such as identifierForVendor or a user-defined password to access the application). Changing the key used by the database is as easy as everything else:



 NSString *newKey = @"NewPassKey"; [database rekey:newKey]; 


If one of the parameters on which the key generation is based is dynamic, do not forget to call this method according to its changes.



Of course, the use of SQLCipher will not be able to fully protect user data - but it will scare away novice researchers and make life more difficult for experienced hackers. Finally it is worth mentioning the fact that in order for an application using this framework to appear in the App Store, you must provide an ERN form, the process for obtaining which is perfectly described by JacobL in this post .

Source: https://habr.com/ru/post/222487/



All Articles