I used to work at Mobiquity, Inc. as their head of mobile security, and a lot of what I did was make sure their iOS apps were as secure as possible. The thing is, a determined attacker will always succeed – our job as a developers is to make their life hard, so that less-than-determined attackers give up before they break through.
With that in mind, here are some tips on how to make your apps more secure.
Disable debugging
The first thing an attacker will do is start trying to attach a debugger to your app. This will allow them to interact with your code as it runs on the device – which, as you can imagine, is scary and bad. One way to prevent them from doing this is by including some code that disallows debugging from the app’s startup onwards.
You’ll want to place it as early in your code as possible. That place is in the main.m
file:
#import <sys/types.h> typedef int (*ptrace_ptr_t)(int _request, pid_t _pid, caddr_t _addr, int _data); int main(int argc, char * argv[]) { void* handle = dlopen(0, RTLD_GLOBAL | RTLD_NOW); ptrace_ptr_t ptrace_ptr = dlsym(handle, "ptrace"); ptrace_ptr(31, 0, 0, 0); dlclose(handle); ...the normal rest of this method... }
Be warned though: this means you won’t be able to debug your app yourself, so you might want to comment it out until release (or add a compiler #IF
statement that checks for release builds).
Store creds securely
Apple puts a lot of effort into being secure; don’t reinvent the wheel! Use what they’ve built, like the keychain (for storing your keys) and the crypto libs they provide. Consider using the master encryption key method: use a securely generated encryption key to encrypt data on the device, and use the user’s password to encrypt only that master key (that way, if the user changes their password, all you have to do is re-encrypt the key, instead of all the data they’ve stored in your app).
Completely clean your dbs
Many apps use SQLite to persist data on the device. However, Apple has made some performance improvements on iOS that prevents deleted SQLite records from being removed from the DB after being deleted; essentially, they’re just marked as deleted, but the info is still there. To fix this, if you want to completely delete information in an SQLite DB, you have two options: using the VACUUM
statement, or overwriting the data before calling DELETE
. Of the two, VACUUM
is easier, but it rebuilds the entire DB, which might be undesirable. Overwriting before deleting is just as effective and faster in situ, but requires a bit more code. Well worth it if you’re trying to keep your users’ data safe!
Use inline functions for security checks
This one is primarily for Objective-C programmers, but since iOS still uses a lot of Objective-C, you may not be safe even if your program is written in Swift. Objective-C is a dynamic language, meaning that its runtime is fully manipulable. Specifically, an attacker can replace any function with one they’ve written instead. So, if you write a function like - (BOOL)isSessionStillSecure
and call it from the rest of your code, an attacker can replace that function with one that always returns YES
.
And that’s annoying, because the alternative is writing that security check into each place you need it, which could really clutter up your code (and definitely goes against DRY). Luckily, there’s a way to have your cake and eat it too: inline functions. You can declare a function ‘inline’ and the compiler will automatically copy the function’s code into wherever you call it at compile time. That means you’ll have the security of pasting the code wherever you need it without violating DRY!
Set traps
This is, perhaps, my favorite tip. One of the things attackers do is search for juicy sounding function names. So, transferMoney(toAccount:)
, bypassPinCode()
, hackMainframe()
, or decryptBitcoinWallet()
might all pique the attacker’s interest. If you can identify what your app’s attacker really wants, you might be able to get them to call a function without fully inspecting it. So, instead of bypassing the pin screen, bypassPinCode()
might erase all the app’s data, blacklist the device, and notify the business of an attempted intrusion.
The key is to realize that this is cat and mouse. Be tricky! Make things hard for your attacker, disable them before they’re able to really get started, and have them always looking over their shoulder. These steps will – at the least – slow them down; any one of these tips might be enough to discourage an attacker into giving up.
There are many more things you can do to make your app more secure that aren’t included here. I’m more than happy to chat with you about it, or you can check out some fantastic books on the subject (such as Jonathan Zdiarski’s Hacking and Securing iPhone Apps).