Monday, September 24, 2012

APIs behaving badly -- iOS

Did you know there are several system-level information caches where sensitive data can hemorrhage from your iOS apps? That's right, even an otherwise well written app can leak user information out and into areas that attackers can get to if they can get their grubby mitts on the device. (But remember, OWASP's Mobile Security Project considers a lost/stolen device to present the highest risk to consumers -- and rightly so!)

Examples? Here are the biggies to look out for:

  • Screenshots. Every time you (or your app's users) press the home key while they are running your app, the default behavior in iOS causes a screenshot to be made and stored in plain view on the device.
  • Spell checker. In order for that nifty, sometimes annoying, and often funny spell checker to work, the system keeps a running cache of what you type, even if it happens to be fairly sensitive. (Some data fields, like passwords, are generally protected from this.)
  • Cut-n-paste. Anything you put in the cut-n-paste buffer is readily accessible from any app. Face it, the feature wouldn't be so useful if you couldn't move data around.
The bad news is that all of these things can result in leaked information. The good news is that they're under the app developer's control. We'll of course discuss solutions to these and other issues at our Mobile App Sec Triathlon, including a coding lab where you'll implement fixes to these problems.

But also know that sometimes APIs don't behave entirely as we might expect. If you're a developer, no doubt you're duly shocked to hear this news, right?

Well, I encountered one such API inconsistency recently while working on the OWASP iGoat tool -- which we'll also use extensively at the #MobAppSecTri. Allow me to explain.

A few of us on the iGoat project have been working on a new exercise for iGoat. The exercise is supposed to illustrate the dangers of the keystroke cache used by the spell checker, as I explained above. Only, we've encountered some inconsistent behavior in how iOS treats this data.

In the new (not yet released) exercise, we're declaring a couple of text fields (UITextField) as follows:

     @property (nonatomic, retain) IBOutlet UITextField *subjectField;
     @property (nonatomic, retain) IBOutlet UITextField *messageField;

Next, in our implementation file, we're synthesizing those fields and setting them to not be cached (for spell checking) in our viewDidLoad method as follows:

    [subjectField setAutocorrectionType: UITextAutocorrectionTypeNo];
    [messageField setAutocorrectionType: UITextAutocorrectionTypeNo];

And, when we're finished with them, we're releasing both fields. All of this is as per Apple's API for UITextFields.

Now here's the strange part. When we run the exercise with both of these fields "protected", we find the first one (subjectField) is protected just fine, but the second one (messageField) shows up in the spell checker cache (located in ~/Library/Keyboard/dynamic-text.dat in the iPhone simulator).

Huh, that seemed odd. So, like any scientifically inclined geeks, we tried dozens of experiments to figure out why things were behaving this way. Eventually, we added a third field in exactly the same way as the first two. Sure enough, the first two fields are protected, but now the last (dummy) field goes into the cache.

Our next step, which we haven't yet done, is to test this on a hardware device, but my point here is pretty straight forward. 

Sometimes APIs misbehave. And, there's a security lesson to be drawn from this. If we'd done a code review of this app, we may well have concluded that all was fine (with regard to this issue). But that wouldn't have been enough. It's also vital to test these security assumptions during the testing phase. 

This type of issue is ideally suited for dynamic validation testing. Take your security assumptions and dynamically observe and verify them in a test bed. Surely, that would have (and did, in our case!) shown that there's still a problem.

Adding a third (dummy) field resolves only the symptoms of this problem, not the problem itself. The jury is still out on that one, but we won't rest until we've resolved it, one way or the other.

Cheers,

Ken

1 comment:

  1. Thank you for sharing, I like the security lesson that you point out at the end

    ReplyDelete