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 secrecymandatory. 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.
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:
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.
funcsavePassword(username:String,password:String){letpasswordData=password.dataUsingEncoding(NSUTF8StringEncoding)guardletdata=passwordDataelse{return}letaccessControl=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:
funcpasswordForUsername(username:String)->String?{letquery=[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:varpasswordData:Unmanaged<AnyObject>?=nilSecItemCopyMatching(query,&passwordData)ifletopaque=passwordData?.toOpaque(){returnNSString(data:Unmanaged<NSData>.fromOpaque(opaque).takeUnretainedValue(),encoding:NSUTF8StringEncoding)as?String}returnnil}