Secure Coding practices

Secure Coding practices

My slides for the september 16th CocoaHeadsNL.
Links mentioned in this presentation:
- *6th November*
A Swift Kickstart: Introducing the Swift Programming Language: http://training.xebia.com/mobile/a-swift-kickstart-introducing-the-swift-programming-language
- *7th November*
iOS 8 Quickstart: The fundamental pillars of iOS development: http://training.xebia.com/mobile/ios-8-quickstart-the-fundamental-pillars-of-ios-development

-Apple Secure Coding Guide:
https://developer.apple.com/library/mac/documentation/security/conceptual/SecureCodingGuide/Introduction.html

-ISEC PDF: https://www.isecpartners.com/media/12964/ios_secure_development_source_boston_2011.pdf

8ae8744c09ee9e24e9de32d406c9ed9f?s=128

Jeroen Leenarts

September 16, 2014
Tweet

Transcript

  1. Xebia

  2. About Xebia

  3. Training • 6th November A Swift Kickstart: Introducing the Swift

    Programming Language • 7th November iOS 8 Quickstart: The fundamental pillars of iOS development
  4. Welcome

  5. Schedule • 17:00 - 18:00 entry • 18:00 - 19:00

    Indian Diner • 19:00 Secure Coding practices on iOS • 20:00 Today widgets on iOS
  6. Secure coding practices on iOS

  7. Disclaimer These are my observations, I am not responsible for

    omissions on anything I present here or your own mistakes. This is not the end- all last word on iOS security.
  8. Why need a secure iOS app?

  9. SSL Concerns • Loads and loads of root CA's •

    Government interference • Not all CA's generate certificates with the proper algorithmic requirements • Man in the Middle attacks • Heartbleed
  10. Who's ever used: #if DEBUG @interface NSURLRequest (DummyInterface) + (BOOL)allowsAnyHTTPSCertificateForHost:(NSString*)host;

    + (void)setAllowsAnyHTTPSCertificate:(BOOL)allow forHost:(NSString*)host; @end #endif Apple does not approve private API
  11. Or: continueWithoutCredentialForAuth enticationChallenge

  12. HTTP and HTTPS requests cached by default to disk

  13. The docs of sharedURLCache say: Applications that do not have

    special caching requirements or constraints should find the default shared cache instance acceptable. An application with more specific needs can create a custom NSURLCache object and set it as the shared cache instance using setSharedURLCache:. The application should do so before any calls to this method.
  14. URL Loading System Programming guide says: The example in Listing

    7-1 prevents the on-disk caching of HTTPS responses. It also adds the current date to the user info dictionary for responses that are cached. Pre iOS 6 disk caching of HTTPS responses was not the default.
  15. SSL Pinning

  16. Why would you want to do SSL pinning? - Prevents

    MITM - Only allow one certificate or root CA - Some mitigation against crappy CA's - Requires a secure client
  17. Here's a way First inform the system we want to

    do it ourselves: - (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection *)connection { return NO; }
  18. Then perform magic - (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge { BOOL

    isNotValid = NO; id <NSURLAuthenticationChallengeSender> sender = challenge.sender; NSURLProtectionSpace *protectionSpace = challenge.protectionSpace; if (protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust) { SecTrustRef serverTrustContext = protectionSpace.serverTrust; SecTrustResultType trustResult; NSError * error; // // Load certificate // // Prepare trust evaluation // SecTrustEvaluate(serverTrustContext, &trustResult); // // Decide what to do based on trust result // if (isNotValid){ #warning certificate is not valid, inform the end-user and cancel flow [sender cancelAuthenticationChallenge:challenge]; } } else { [sender continueWithoutCredentialForAuthenticationChallenge:challenge]; } }
  19. Load certificate data, prepare trust evaluation if (nil == self.certificateData)

    { NSString * certificatePath = [[NSBundle mainBundle] pathForResource:@"rootca" ofType:@"crt"]; if (certificatePath != nil) { self.certificateData = [NSData dataWithContentsOfFile:certificatePath options:0 error:&error]; } else { isNotValid = YES; } } if (error == nil) { SecCertificateRef certificate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)self.certificateData); if (nil == certificate) { isNotValid = YES; } else { CFMutableArrayRef certificatesArray = CFArrayCreateMutable(NULL, 1, &kCFTypeArrayCallBacks); CFArraySetValueAtIndex(certificatesArray, 0, (const void *)certificate); SecTrustSetAnchorCertificates(serverTrustContext, certificatesArray); SecTrustSetAnchorCertificatesOnly(serverTrustContext, true); CFRelease(certificatesArray); CFRelease(certificate); } }else { isNotValid = YES; }
  20. Based on trust result decide what to do switch (trustResult)

    { case kSecTrustResultProceed: case kSecTrustResultUnspecified:{ NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrustContext]; [sender useCredential:credential forAuthenticationChallenge:challenge]; break; } // case kSecTrustResultRecoverableTrustFailure: Maybe try and recover from an acceptable cert failure here? default:{ isNotValid = YES; } }
  21. The Simulator doesn't do SSL like a device, so you

    would need more magic: - (BOOL)connection:(NSURLConnection * const)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace * const)protectionSpace { NSString * const method = [protectionSpace authenticationMethod]; return [method isEqualToString:NSURLAuthenticationMethodServerTrust]; }
  22. - (void)connection:(NSURLConnection * const)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge * const)challenge { id <NSURLAuthenticationChallengeSender>

    sender = [challenge sender]; NSURLProtectionSpace * const protectionSpace = [challenge protectionSpace]; if ([[protectionSpace authenticationMethod] isEqualToString:NSURLAuthenticationMethodServerTrust]) { SecTrustRef serverTrustContext = [protectionSpace serverTrust]; SecTrustSetAnchorCertificatesOnly(serverTrustContext, false); SecTrustResultType trustResult; SecTrustEvaluate(serverTrustContext, &trustResult); switch (trustResult) { case kSecTrustResultProceed: case kSecTrustResultUnspecified: // Certificate validated okay. break; default: { // Certificate didn't validate. Log, the first time, that the workaround is active. static BOOL userWarned = NO; if (!userWarned) { userWarned = YES; NSLog(@"**************** Server SSL certificate doesn't validate; disabling validation. **************"); } break; } } NSURLCredential * const credential = [NSURLCredential credentialForTrust:[protectionSpace serverTrust]]; [sender useCredential:credential forAuthenticationChallenge:challenge]; } else { [sender continueWithoutCredentialForAuthenticationChallenge:challenge]; } }
  23. Switch between the two incantations by be #pragmatic during compile-time:

    #if TARGET_IPHONE_SIMULATOR //Do simulator stuff #else //Do device stuff #endif
  24. A self generated Root CA certificate can be installed with

    Apple Configurator on your test devices. All certificate checks then behave as if the certificate is a regular CA.
  25. It's an #if not an #ifdef Actual production bug. Oh

    shit, why did I not check that? — Not to be named developer's comment
  26. He was not shot, cause normally he's a rockstar

  27. Encryption • Use CommonCrypto • And/or RNCryptor • Use an

    IV!! It is important • Padding is a must
  28. Keychain Developers storing secure items into NSUserDefaults will be taken

    out back, shot, dumped in a ditch, soaked with petrol and set on fire for good measure. Keychain SecItemAdd(…); SecItemUpdate(…); SecItemCopyMatching(…);
  29. Do use the correct kSecAttrAccessible value CFTypeRef kSecAttrAccessibleWhenUnlocked; CFTypeRef kSecAttrAccessibleAfterFirstUnlock;

    CFTypeRef kSecAttrAccessibleAlways; CFTypeRef kSecAttrAccessibleWhenUnlockedThisDeviceOnly; CFTypeRef kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly; CFTypeRef kSecAttrAccessibleAlwaysThisDeviceOnly;
  30. SQLite and SQL injection Don't do this: NSString *statement =

    [NSString stringWithFormat:@"SELECT username FROM users where uid = '%@'",uid]; Instead do this: objectivec const char *sql = "SELECT username FROM users where uid = ?"; sqlite3_prepare_v2(db, sql, -1, &selectUid, NULL); sqlite3_bind_int(selectUid, 1, uid); int status = sqlite3_step(selectUid);
  31. Data protection Use the API's when applicable Same story reason

    you would want to use the keychain.
  32. References -Apple Secure Coding Guide -ISEC PDF