Active Filters: Security

App Transport Security was introduced with iOS 9 and OS X 10.11. It aims to make the network calls we make from our apps more secure by enabling many best practices like TLS 1.2 and forward secrecy by default. Today we'll take a closer look, and learn how to disable it if needed.

App Transport Security makes support for Transport Layer Security 1.2 and forward secrecy mandatory. It also requires certificates to have a SHA256+, ECC256+, or RSA2048+ signature. Don't worry if that sounds like gibberish, the idea here is that Apple will maintain ATS on an ongoing basis, keeping it always up-to-date with the latest security best practices and standards.

Apple is enforcing ATS by automatically "opting-in" the NSURLConnection, NSURLSession, and CFURL APIs (plus anything built on top of them).

This means these APIs will throw errors, and the connections will fail if we try to use them with a connection that doesn't meet all the requirements.

Unfortunately, not all connections we need to make in our apps will support ATS. In these cases, we'll need to tell the system to exempt these connections, and allow them to be made insecurely. We'll do this by adding some keys to our app's Info.plist:

We'll start by opening our Project's settings, then heading to the Info tab.

Then, we'll right click the list of keys, and choose Add Row. We'll use the inline plus buttons to continue adding and configuring rows until we end up with this:

There's also keys for allowing for lower minimum TLS versions, as well as not requiring forward secrecy.

It's encouraging to see Apple putting such an emphasis on securing our apps. App Transport Security is big step forward in making all of our apps safer for us and our users.

Topics

#75: Locksmith 🔐

Topics

Locksmith is a library from Matthew Palmer that really improves how we can interact with the Keychain. Let's look at the basics:

Reading Data

let dictionary = Locksmith.loadDataForUserAccount("kyloren")

Writing Data

do {
  try Locksmith.saveData(
    ["saberColor": "#FF0000"],
    forUserAccount: "kyloren"
  )
} catch { }

Updating Data

do {
  try Locksmith.updateData(
    ["saberColor": "#30FF00"],
    forUserAccount: "kyloren"
  )
} catch { }

Deleting Data

do {
  try Locksmith.deleteDataForUserAccount("kyloren")
} catch { }

That's just the beginning though. Locksmith supports almost every feature Keychain has to offer. It also embraces protocols, and protocol extensions. Let's look at an example of how to improve our own types, making them easier to store in the Keychain.

Let's say we have a simple struct in our app to represent user accounts. We'll implement a couple of protocols from Locksmith on it:

struct JediTempleAccount: GenericPasswordSecureStorable,
  CreateableSecureStorable, ReadableSecureStorable,
  DeleteableSecureStorable {

  let username: String, password: String

  let service = "jedi-temple"
  var account: String { return username }
  var data: [String: AnyObject] { return ["password": password] }
}

Now we can work with accounts and the Keychain like this:

let account = JediTempleAccount(username: "kyloren", password: "yaysith")

do { try account.createInSecureStore() } catch { } // save
let result = account.readFromSecureStore() // retrieve
do { try account.deleteFromSecureStore() } catch { } // delete

More info about Locksmith can be found at git.io/locksmith

Topics

#37: Touch ID 👍

Topics

Protecting data with Touch ID is a great way to improve your app.
Let's take a look at how to do it:

Save to Keychain

First you need to save something to the keychain, and protect it with the User Presence access control flag.

func savePassword(username: String, password: String) {
  let passwordData = password.dataUsingEncoding(NSUTF8StringEncoding)
  guard let data = passwordData else { return }

  let accessControl = SecAccessControlCreateWithFlags(
    kCFAllocatorDefault, 
    kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly,
    .UserPresence // this part enables Touch ID support
    , nil
  )

  SecItemAdd([
    String(kSecAttrService) : serviceID,
    String(kSecClass) : kSecClassGenericPassword,
    String(kSecAttrAccessControl) : accessControl.takeUnretainedValue(),
    String(kSecAttrAccount) : username,
    String(kSecValueData) : data
  ], nil)
}

Retrieve From Keychain

Then when you retrieve, supply a prompt message and iOS will show the familiar Touch ID alert before executing the Keychain query:

func passwordForUsername(username: String) -> String? {
  let query = [
    String(kSecAttrService) : serviceID,
    String(kSecClass) : kSecClassGenericPassword,
    String(kSecReturnData) : true,
    String(kSecMatchLimit) : kSecMatchLimitOne,
    String(kSecUseOperationPrompt) : "Authenticate to Login",
    String(kSecAttrAccount) : username
  ]

  // Working with the Security Framework is still kind of ugly in Swift:

  var passwordData: Unmanaged<AnyObject>? = nil
  SecItemCopyMatching(query, &passwordData)

  if let opaque = passwordData?.toOpaque() {
    return NSString(
      data: Unmanaged<NSData>.fromOpaque(opaque).takeUnretainedValue(),
      encoding: NSUTF8StringEncoding
    ) as? String
  }

  return nil
}