iOS Sandbox - Securing the data in Documents directory - ios

There are some files that I want to download and store in the sandbox. However, they must stay secure (i.e. encrypted) all the time. Now, I can encrypt them while downloading to the Documents itself. But when the files need to be consumed I have to decrypt them before that. The question is where to put these decrypted files?
tmp - Looks like a good place to keep it, but then what if the contents are deleted when the app has been kept minimised for days.
Documents - Keeping the decrypted file here in a separate place may not be a very good idea. It is not automatically cleaned up when the app is relaunched and if the device runs out of battery while the app is still running, these decrypted files will get exposed.
So the moot question is what the best way to ensure Documents directory's data security.

One useful aspect of UNIX-based systems is that you can create/open a file and then immeditely delete the file. The file won't be accessible from outside the app, however the app will be able to read/write data to the file and the file will not actually be deleted until the file handle is closed.
This means you can create/open the decrypted file anywhere within the app's accessible file structure.
While I haven't tested this under iOS, I think there is a good chance it will work.

I would keep the encrypted files in the Documents directory, encrypted with the NSData NSDataWritingFileProtectionComplete option.
If you feel the need to encrypt the files yourself and then decrypt only as needed save the decrypted files in the Documents directory, encrypted with the NSData NSDataWritingFileProtectionComplete. Add the "do not back up" extended attribute to the file. On app launch/wake, etc, based on the police overwrite files that are no longer needed and delete. Use AES, CBC mode with a random iv, random key and keep the key in the Keychain.
An option to open as a stream and decrypt on the fly into a buffer, if this works for your app.
But the catch is I really don't understand you full use-case. Best practice: Hire an iOS security domain expert to advise and vet your solution, I do. Is the security worth that price, a valid question.
In explanation to my comments: I wrote an application to recover images from a corrupted HD, not all that hard.

Related

Periodic iCloud backup of SQLite database

Let me get this out of the way right now: yes, it was almost certainly a mistake to not use Core Data. However, I was new to iOS development when I made these decisions, and I had no idea I'd be hamstrung like this. Moreover, the app is intended to also run on Android (eventually), so I avoided platform-specific APIs wherever possible.
I have an iOS app that stores data in a local SQLite database file. The data stored in the file is provided by the user, so it's important that it be kept safe. I had plans to "do this later", and later is now here. I am quickly coming to the realization that it won't be as straightforward as I had hoped...
I now understand that it won't be possible to seamlessly synchronize data across devices, and I'm willing to accept that limitation until I manage to migrate to Core Data. However, in the meantime I'd at least like the SQLite database to be backed up periodically so users can feel safe using the app on a single device. I was thinking I would do this:
periodically (e.g. once a week) copy the SQLite file from local storage into cloud storage, thus ensuring it is backed up
when the app starts, if the local store is missing or corrupted but the file exists in the cloud storage, ask the user if they would like to copy it over
The biggest problem with this approach is that the user could run the app on multiple devices and therefore the data stored in iCloud could be from any one of those devices, but only one. To combat that, I thought I could just use a per-device, unique name for the file in cloud storage. I would generate this using UIDevice.identifierForVendor.
So my startup logic would be:
Determine the unique name for the cloud file.
Is the local file missing or corrupted, and if so, does the cloud file exist?
2.1. Ask the user if they would like to restore from the cloud file. Make it really hard for them to say no because doing so will lose all their data.
2.2. If they say yes, copy the cloud file to the local file storage.
Open the local database file.
And running in the background I would occasionally copy the database file from local to cloud storage.
I would like to know whether this a sensible approach until I do Core Data integration. Also, are there any hidden "gotchas" that I'm perhaps missing?
UPDATE: as #TomHarrington pointed out in a comment, it turns out my database file is already sitting in /Documents, which is backed up to iTunes and any iCloud account. So my question morphs into this:
Should I simply ensure my database has a device-specific name so that it is not clobbered by the app running on another device connected to the same iCloud account?
I'm going to answer my question, since I ended up going down this path and finding a MASSIVE blocker. There is a bug in the UIDevice.identifierForVendor API that causes it to regenerate every time a new version of the app is installed! See here. This of course rules out using it as a device identifier. sigh
I think I'm SOL with that approach. Instead, I might generate a GUID on first execution and use that as my identifier. Problem is, I need to store that somewhere that isn't backed up to iCloud.
Ugh, I may just give up here and say my app can't be run on multiple devices until Core Data integration is done.
UPDATE: I ended up generating an identifier on first run and storing it in the keychain (as a local entry only so it isn't backed up to iCloud).

PDF uploading malicious content vulnerability with Rails

I am implementing pdf upload using Carrierwave with Rails 4. I was asked by the client about malicious content, e.g. if someone attempts to upload a malicious file masked as a pdf. I will be restricting filetype on the frontend to 'application/pdf'. Is there anything else I need to worry about, assuming the uploaded file has a .pdf extension?
File uploads is often a security issue, since there are so many ways to get it wrong. Regarding just the issue of masking a malicious file as a PDF, checking the content type (application/pdf) is good, but not enough, since it's controlled by the client and can be modified.
Filtering on the .pdf extension is definitely advisable, but make sure you don't accept files like virus.pdf.exe.
Other filename attack techniques exist, e.g. involving null or control characters.
Consider using a file type detector to determine that the file is really a PDF document.
But that's just for restricting the file type. There are many other issues you need to be aware of when accepting file uploads.
PDF files can contain malicious code and are a common attack vector.
Make sure uploaded files are written to an appropriate directory on the server. If they aren't meant to be publicly accessible, choose a directory outside of the web root.
Restrict the maximum upload file size.
This is not a complete list by any means. Check out the Unrestricted File Upload vulnerability by OWASP for more info.
In addition to #StefanOS 's great answer, PDF files are required to start with the string:
%PDF-[VERSION]
Generally, at least often, the first couple of bytes (or more) indicate the file type - especially for executables (i.e., Windows executables, called PE files, should start - if memory serves - with "MZ").
For uploaded PDF files, opening the uploaded file and reading the first 5 bytes should always yield %PDF-.
This might be a good enough verification. for most use-cases.

Where to Store Purchased Content and Exported Data

The app I'm working on generally uses a single SQL store in Core Data to hold a working dataset for the app. However, there can be any number of small, separate stores which originated as either
In-app Purchased content, or
Exported subsets of the working dataset that may be reused from time to time.
These will always consist of a single sqlite file (WAL turned off). The In-App purchases can always be re-downloaded, but it would be possible for the exported data to be lost for good (since they might choose to permanently delete the data after it is exported).
Intuitively, since the exported data might not be possible to recreate, it should go in a subdirectory of the documents folder. But I'm not sure whether Apple would agree about that.
I have no idea where the downloaded purchased content should be saved, since technically, it can be re-downloaded at any time.
So, my question is, where in the iOS filesystem should I put these (iOS7 and beyond).
There is no official, public guidance on where content purchased via IAP should go on the filesystem. However, experience with Data Storage Guidelines feedback has indicated that:
NSDocumentsDirectory should only contain data created or edited by the user
(some) Non-user data can still be stored in NSDocumentsDirectory if it has the NSURLIsExcludedFromBackupKey attribute set. In general you should still try and avoid doing this.
In-App Purchase content is considered "restorable application data" and should be stored accordingly. The application support directory is one place where it could be stored.
If your exported data was exported by a user-initiated action and the data at that point "belongs" to the user, storing that exported data in the NSDocumentsDirectory should be fine. If you have any doubt, store it in the application support directory or caches directory. Be aware that in low space conditions the data may be purged by the system.

App rejected for storing database in Documents directory

My app was recently rejected from the app store for storing data in the Documents directory. I had moved it there because with the latest change, the db must now be writeable - it's no longer read-only.
In researching the solution, I've read that it's actually preferable to use NSLibraryDirectory. Is this so, and more importantly, will that address Apple's concerns? Their complaint is that the app lets the user download to much content (it doesn't let the user download any unless you count the db), and that it's storing "too much data" in the "incorrect location." The data is 8 mb, but could grow to about 10 or 12 mb max.
Actually its because of iCloud.
using iCloud, Application's document directory is synced to cloud and to other devices and hence Apple want developers to store only that data in document directory which they want to sync with iCloud.
I came to know this form one of my friends who work # Apple California and I'm not really sure if this material is on Apple's documentation.
I had this issue with an update to a suite of apps I develop the other week. The funny thing was that only five of the seven apps (exactly the same code base) were rejected.
I believe the issue in my case was duplicating assets from the .app bundle into ~/Documents.
My first attempt to comply with their new storage guidelines was to implement the do not backup switch on the files I was copying into ~/Documents. No deal with that so I had to change my implementation to not copy the data at all. The apps were promptly approved.
Your implementation is probably different but in my experience Apple no longer likes you copying things from the app bundle into ~/Documents, as it could be duplicating data unnecessarily (in their view).
They suggest copying into ~/Caches (or whatever it is), but this can be cleared in low storage situations and may not be right for your case either.
Hope that helps.
A product I wrote a year ago uses CoreData (with a SQLite data store). This database file is stored in ~/Library/Application Support//. This was approved by Apple without issue.
"Application Support" does not exist in ~/Library, so you will need to create it.
Documents is not a great place to store your database file for several reasons. Apple has their reasons, since they rejected your app. Another reason is that the Documents directory is accessible by the user (via iTunes), and unless the user deleting your database file is no big deal to the operation of your app, it is best to put it where they can not do anything with it directly and/or inadvertently.
You can still put those files in the Documents folder, you just have to give them an attribute that lets the file system know not to back them up to the iCloud
This is a great example of how to do so on different iOS versions

Secure contents in Documents directory

Can anyone help me to make the contents of my Documents directory secure?
Use:
- (BOOL)writeToFile:(NSString *)path options:(NSDataWritingOptions)mask error:(NSError **)errorPtr
with one of the file protection options:
NSDataWritingFileProtectionComplete (iOS 4.0)
NSDataWritingFileProtectionCompleteUnlessOpen (iOS 5.0)
NSDataWritingFileProtectionCompleteUntilFirstUserAuthentication (iOS 5.0)
See: Apple Documentation
NSDataWritingFileProtectionComplete
In this case, the file is stored in an encrypted
format and may be read from or written to only while the device is
unlocked. At all other times, attempts to read and write the file
result in failure.
Note: Doing your own encryption raises the problem of key storage and the best answer there is to use the Keychain. Key handling is the biggest problem and the NSData methods handle that.
We cannot secure the file in documents directory. We can store the file in temp folder of the device. This cannot be accessed by anyone
use encryption and decryption for making and reading those files on iphone take an idea from here http://iphonedevelopment.blogspot.com/2009/02/strong-encryption-for-cocoa-cocoa-touch.html
Alan Quatermain provides a toolkit that has some helpful wrappers around the cryptography libraries to make encryption/decryption really straightforward.
Here's the link:
AlanQuatermain / aqtoolkit
Whatever you do, just make sure that you don't store the document on the device unencrypted, even for a short time. Always store it encrypted. Perform any encryption operation in memory.
Be sure that for any file operations you do not cache. So for example, any downloading, etc. you want to make sure that no data is written temporarily to disk.
Finally, for your encrypted documents, do not store the key on the device in any format. Do not store it on the keychain either.
Try to encrypt content. take a look Strong Encryption for Cocoa / Cocoa Touch

Resources