As developers, we have a responsibility to protect our users’ data in a responsible way. There are many ways that you can mitigate the risks of a data breach in your app, but in this post I’m going to focus on an easy technique that anybody can implement. You can make it more difficult for a potential intruder by restricting access to your app if the user is using a jailbroken device. You will want to carefully consider how many users you could be potentially blocking and how this could affect your product before you perform this change. In a commercial project I was involved with, we had analytics tell us how many customers we would be blocking and found it was going to be less than 0.5%.
It’s easier on a jailbroken device to perform static and dynamic analysis on your app to try and find weaknesses in its security. The attacker can easily download your app and use tools to decrypt it. Once decrypted they can find out information such as static string values and frameworks present within the app, as well as reverse engineering the binary to see patterns within the assembly code. With this new information, attackers can look for weak points within your app, like a framework with a known vulnerability, sensitive data stored within the app or private server communication details.
I have this handy little snippet of code which I use on startup to check that the user is using a regular device. The original idea behind the code is not my own, and there are similar approaches available from other sources. Here we simply check the device’s file directory for files that are usually found on devices that have been through the jailbreaking process. Checking for apps such as Cydia and libraries like MobileSubstrate. If we are able to find these in our file directory then it’s safe to assume that the device has either been jailbroken or is currently in a jailbroken state.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
extension UIDevice { | |
private class JailbreakDetector { | |
static var current: JailbreakDetector = JailbreakDetector() | |
lazy var containsSuspiciousFiles: Bool = { | |
return (["/Applications/Cydia.app", | |
"/Library/MobileSubstrate/MobileSubstrate.dylib", | |
"/bin/bash", | |
"/usr/sbin/sshd", | |
"/etc/apt", | |
"/private/var/lib/apt/"].first(where: { | |
FileManager.default.fileExists(atPath: $0) | |
}) != nil) | |
}() | |
} | |
/// Whether user is using jailbroken device | |
var isJailbroken: Bool { | |
guard self == UIDevice.current else { | |
return false | |
} | |
// Check that we are not using the simulator | |
#if arch(i386) || arch(x86_64) | |
return false | |
#else | |
return JailbreakDetector.current.containsSuspiciousFiles | |
#endif | |
} | |
} |
It is important to note that blocking jailbroken devices will not make your app immune to static or dynamic analysis, however, it does make it more difficult for an attacker who may be looking for an easy target. There are ways of circumventing file directory checks such as the one above, however, it still provides a basic level of protection that makes it harder to extract information from an application.