As per OWASP Top 10, it is must for every ios developer to take care of code security, data storage security, data communication security and so on. As iOS mobile apps are not as vulnerable as other mobile platforms like Android and any hybrid mobile development (which is very open at first level of screening itself like manifest, javascript injections and so on), iOS still has its own issues. It becomes every organization’s/developer’s responsibility to make sure that the code, logic, data and its communication is secured in the right way so as to prevent from any intruders tampering and understanding the code.
To be cautious at developer’s end, below are the few lists of threats that are at a preliminary level, which is to be taken care of by every ios developer. Those are:
1. Screen Recording and Screen Capturing
Risk:
1. An attacker could record login/any sensitive screen and capture username and password entered.
2. In video streaming like an app, any paid video content can be streamed and recorded.
These risks will lead to a major leak in a banking application, where secured transaction details will be compromised if screenshot or screen recording is performed.
OWASP: Insecure Authentication
Fix:
Observe for userDidTakeScreenshotNotification and use UIScreen.isCaptured() to restrict user to proceed further.
Example Code :
1 2 3 |
NotificationCenter.default.addObserver(forName: .UIApplicationUserDidTakeScreenshot, object: nil, queue: OperationQueue.main) { notification in print(“Screenshottaken!”) } |
To Check if screen Recording is happening from ios 11 and above:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
- (BOOL)isRecording { for (UIScreen *screen in UIScreen.screens) { if ([screen respondsToSelector:@selector(isCaptured)]) { // iOS 11+ has isCaptured method. if ([screen performSelector:@selector(isCaptured)]) { return YES; // screen capture is active } else if (screen.mirroredScreen) { return YES; // mirroring is active } } else { // iOS version below 11.0 if (screen.mirroredScreen) return YES; } } return NO; } |
2. KeyChain Data Protection
Risk:
A keychain item added to the KeyChain with a vulnerable accessibility option may be exposed to other applications on JailBroken devices or attackers with physical access. Generally, a developer has the following actions to choose from:
kSecAttrAccessibleWhenUnlocked,
kSecAttrAccessibleAfterFirstUnlock,
kSecAttrAccessibleAlways,
kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly,
kSecAttrAccessibleAlwaysThisDeviceOnly.
Choosing the easiest or more prone to vulnerable options like, ‘kSecAttrAccessibleWhenUnlocked’ may lead to potential security risk.
OWASP: Insecure Data Storage
Fix:
The ‘kSecAttrAccessibleAfterFirstUnlock’ or ‘kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly’ modes should only be used where the application performs background processing requiring the KeyChain item.
3. File Data Protection
Risk:
When a new file is to be saved, a developer can choose from these options to better use of data protection:
Complete Protection (NSFileProtectionComplete)
Protected Unless Open (NSFileProtectionCompleteUnlessOpen)
Protected Until First User Authentication (NSFileProtectionCompleteUntilFirstUserAuthentication)
No Protection (NSFileProtectionNone)
Choosing the easiest or more prone to vulnerable options like, ‘NSFileProtectionNone’ may lead to potential security risk.
OWASP: Insecure Data Storage.
Fix: It is advisable to use ‘NSFileProtectionCompleteUnlessOpen’ and ‘NSFileProtectionCompleteUntilFirstUserAuthentication’ to have data protection on all files.
Example:
Encrypting a file on the first write
1 2 3 4 5 6 |
do { try data.write(to: fileURL, options: .completeFileProtection) } catch { // Handle errors. } |
Encrypting an existing file on disk
1 2 3 4 5 6 7 8 |
do { try (fileURL as NSURL).setResourceValue( URLFileProtection.complete, forKey: .fileProtectionKey) } catch { // Handle errors. } |
4. Weak Jail Break Detection:
Risk:
Application logic and behavior might be compromised on JailBroken devices, and application exposed to attacks. With that said, any hacker can bypass those basic checks with some effort. It’s important to know this and not completely rely on the jailbreak detection methods.
OWASP: Extraneous Functionality
Fix:
The following tests will check for known, easy to bypass, checks and inform the developer that he is using them:
1. A lot of unique files and applications are installed on a jailbroken device. Checking for these files in the file system can help identify whether the device is jailbroken or not. This test checks that the developer is looking for these files.
2. Check to see whether the application follows sandboxing rules can help the user identify whether the application is jailbroken or not. A good way to check is to see if we can modify a file in some location outside the application bundle. This test looks for such checks by the developer.
3. If calling the Cydia’s URL scheme (Cydia://) from your application results in success, it can be sure that the device is jailbroken. This test checks whether the developer performs this check.
Apart from these, it is advisable to check every possible way to really find if the device is compromised.
Example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
func isDeviceJailBroken() -> Bool { var jailbroken = false if TARGET_IPHONE_SIMULATOR == 1 { return false } // Checking the existence of common symbolic links. self.checkJBSymlinks() //Checking the existence of files that are common for jailbroken devices. self.checkJBOnlyAvailableFiles() //Checking the Read/Write permissions in system directories (sandbox violation) self.checkReadWritePermissionsJBDevice() return jailbroken } private func checkReadWritePermissionsJBDevice() { var isError = false let stringToBeWritten = "yourstring" let filePath = String(format: "/p%@%@%@%@%@", "ri", "va", "te/j", ".te", "st") do { try stringToBeWritten.write(toFile: filePath, atomically: true, encoding: String.Encoding.utf8) } catch { isError = true } if !isError { let fileManager = FileManager.default do { try fileManager.removeItem(atPath: filePath) } catch {} } } |
5. Show/Hide password field
Risk:
Application password is exposed while recording login screen and other sensitive information screens.
OWASP: Insecure Authentication
Fix:
When you identify screen is being recorded, use ‘mask’ over password text field (or) any sensitive text field and protect data security.
Hide/Dismiss Keyboard while the app is being recorded.
Example:
1 2 3 4 5 6 7 8 9 |
/**** When screen recording is true (or) we can also check if app minimized/background. ****/ if(isRecording){ let maskView = UIView(frame: CGRect(x: 64, y: 0, width: 128, height: 128)) maskView.backgroundColor = .blue maskView.layer.cornerRadius = 64 yourView.mask = maskView } |
6. Privacy Resources Access
Risk:
The application accesses private device and/or user resources (such as contacts, location, Bluetooth device ID, camera and mic). This might cause a data leak in the case of insecure use of this data (such as sending the data as plaintext over HTTP). Developers should ensure that access to these resources follows a secure policy (such as encrypting data before sending to the server). You should also make sure that there aren’t 3rd party libraries in use that access resources insecurely.
OWASP: Insecure Data Storage
Fix: Validate all access to private resources and force compliance with a security policy.
Example:
While using advertising identifier, ABAddressBookRef and so on.
7. Lack of Certificate Pinning
Risk:
If the attacker can generate a valid certificate for the target domain, for example, by using known techniques for installing a false Certificate Authority (CA) on the device, the attacker could imitate the target, and decrypt traffic, i.e. a ‘Man-in-the-Middle attack’. This could lead to leaks of sensitive data, exploitation of other vulnerabilities.
OWASP: Insecure Communication
Fix:
The delegate must implement URLSession:task:didReceiveChallenge:completionHandler:
and handle all connections via certificate authentication.
Example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { if (challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust) { if let serverTrust = challenge.protectionSpace.serverTrust { var secresult = SecTrustResultType.invalid let status = SecTrustEvaluate(serverTrust, &secresult) if (errSecSuccess == status) { if let serverCertificate = SecTrustGetCertificateAtIndex(serverTrust, 0) { let serverCertificateData = SecCertificateCopyData(serverCertificate) let data = CFDataGetBytePtr(serverCertificateData); let size = CFDataGetLength(serverCertificateData); let cert1 = NSData(bytes: data, length: size) let file_der = Bundle.main.path(forResource: "name-of-cert-file", ofType: "cer") if let file = file_der { if let cert2 = NSData(contentsOfFile: file) { if cert1.isEqual(to: cert2 as Data) { completionHandler(URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust:serverTrust)) return }}}}}}} // Pinning failed completionHandler(URLSession.AuthChallengeDisposition.cancelAuthenticationChallenge, nil) } |
8. Debug Logs Enabling
Risk:
Unnecessary Debug Logs through the app might print sensitive information and method completion. This is riskier at release builds.
OWASP: Extraneous Functionality
Fix: Either to use #ifDef DEBUG or enable debug=1 only on debug builds. NSLog to be strictly avoided.
1 2 3 4 5 |
#ifdef DEBUG NSLog(@"Your log statement"); #endif |
9. SSL Certificate Expiry
Risk:
Usually, every certificate has a validity for about a year, after which renewal is needed, when this renewal not done at right time, then the app stops working.
OWASP: Insecure Communication
Fix:
Renew certificate up front, before the expiry date and update the IPA for the seamless working of any app.
Example: Check certificate expiry at every launch and intimate/request for new few days before expiry.
10. Usage of HTTP Request
Risk:
The application uses an insecure communication channel (HTTP). Therefore an on-path (i.e. on the same network with the victim) attacker can inject a 301 HTTP redirection response with an attacker-controlled server. Man-in-the-Middle (MiTM) attack.
OWASP: Insecure Communication
Fix :
Use HTTPS instead of HTTP, or harden the cache policy.
11. 3rd Party Library Usage with Caution
Risk:
Sometimes, 3rd Party libraries may inject harmful code to yours.
OWASP: Extraneous Functionality
Fix:
Go through the GitHub link, license, and code review any 3rd party libraries before using.
12. iOS — Code Obfustication
Risk:
Last but not least, anybody can reverse engineer and check for classes and methods in an iOS app, try to dynamically inject code for that method/notification observer. It is advised to obfusticate the code, so the app logic is not compromised at direct runs.
OWASP: Extraneous Functionality
Fix:
Use strong code Obfustication libraries 3rd party tools that offer some degree of obfuscation and integrity protection including:-
Arxan,
Metaforic,
Cryptanium.
These libraries give a tough for reverse obfustication.
These are the main 12 security threats where every developer can make sure that a certain level of measures is taken from their end. This can be considered as a checklist from the developer’s end before sending IPA to testing. But yet, there are few more and even though the codes are protected there are tools available to bypass jail-breaking code on the jailbroken device, reverse-obfusticate and inject dynamic library on non-jail broken devices and get to know keychain and storage items.
We shall discuss the tools widely used for penetration testing by testers and injections used by others to understand your code in subsequent blogs.