Core OS • iOS, OS X • 46:16
Learn about "real world" threats to users' data on OS X and iOS. See practical demonstrations of how users' data can be attacked both on the device and over the network, and find out how to defend against these threats in your app.
Speakers: Michael Brouwer, Conrad Sauerwald, Andrew Whalley
Unlisted on Apple Developer site
Downloads from Apple
Transcript
This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.
Good morning and welcome to session 714. For the next hour, myself and my colleagues Conrad and Michael are going to be talking about protecting the user's data and the part that you, as developers, can play in that. First of all, a little bit about ourselves. We are all members of the platform security team at Apple.
And we really operate up and down the stack, all the way down from the secure bootloader, all the way up to applications and even the cloud. But sometimes what we are always involved is when a cryptographic key is used to protect users' data. That's technologies you've probably come across before. We also design and build solutions for internal clients. For example, we were involved with designing the cryptography used by iMessage.
We expose a lot of that functionality through APIs for use by third parties, such as yourselves, security framework, common cryptobing examples. That same functionality is also exposed by other Apple APIs at an even higher level. For example, NSFAR Manager, CF Network, and we're going to be pulling from both of those layers during this presentation.
What are we going to talk about? We're going to look at a common situation, which is a client app talking to a web service. We're going to subject it to a hostile environment, a simulated attack, and show what can happen, talk about why that matters, and give some simple steps that you can put in your applications to avoid falling foul of such attacks. Some things we're not going to cover. Securing your app from exploitation, so sandboxing, hardening, securing coding practices. These are all very important topics, but we're going to assume that's part of your standard flow and you're doing this already.
We're also not going to touch on cryptographic protocol design, that is, building things from primitives such as block ciphers or hash functions. That's really very tricky and fraught with peril. If you find you can't use our high-level APIs to do what you want and you're resorting to building your own, file us a bug and tell us why. We're also not going to talk about digital rights management, because whereas we're talking about protecting the user's data, DRM is really protecting data from the user, and that's an entirely different problem domain.
I've used the word "user data" a lot so far. What do I mean by that? Well, really everything is user data. The documents your application processes, be it images, text, audio, the main thing your application does, that's obviously user data. But also, things like credentials, usernames and passwords. Those, as we'll talk about later, are particularly sensitive and worthy of protection. Things like preferences, how the user wants to configure your app. Also user data, but things you save in preferences really should be innocuous.
Then there might be other things that don't instantly spring to mind. For example, photo metadata. In there you can have GPS coordinates and timestamps, things like that. And even as something as innocuous as a unique identifier, perhaps could be used to correlate a user coming from two different IP addresses. Maybe you could geolocate them. See that a user has been traveling.
So if everything is user data, user data is everywhere. It's obviously on the device when your application is processing it, but applications really come into their own when they get information from the network and they send information to the network. So we need to protect that data in transit.
If you're sending your data somewhere, obviously it's going perhaps to your server, and you need to make sure that it's properly protected there as well. But it can also end up off the device through means like backup, either tethered to iTunes or, indeed, to iCloud. And one of the advantages of using the high-level applications is you can tell the system, "That file is important.
Please protect it." And then when we go and do things that maybe backup the file, we can do the very best we can to try and make sure that protection remains in place. So to demonstrate some of this, we have put a little application together, which we're going to be demoing, and bring on to the stage now Conrad, who's going to talk about that application.
Right, so this is our common application. It's going to be a simple media client because that's the nicest to demonstrate. What it's going to do, it's going to download some images off the server. The server is of course going to ask us for authentication so that we only get access to our own pictures. And then it's going to store them so we can also view them later when we're not on a network.
Just like last year, we want to make the source available. We haven't quite worked that out yet, but we have some hints how you can get to it later so you can see in more detail how it works because in the slides we're only going to focus on the key parts of it. And it may be helpful to see how that works. And of course, if the demo fails miserably today, you'll be able to play it at home.
So first things first, how do we download the data? Well, we're not going to come up with our own custom protocol. HTTP suffices here just perfectly well. And what we do is we put that in the URL, http://ourserver, and then we hand that off to an NSURL request to start making that request and download the data. Some of you may already be familiar with this, but I'm going to go over it anyway.
So after we have this NSURL request, we hand this off to an NSURL connection, which is going to take this request through the many steps that are necessary-- finding the IP address, connecting to the server, doing a whole bunch of stuff. And sometimes it will need to call back into us and ask us to help out, for example, with authentication, or just to present data that was downloaded.
So we're going to declare that we support the protocol that is used for this, and within that protocol are various callbacks, did receive data every time data appears that can be called multiple times, or maybe the connection actually fails. We'll get a "did fail" with error, and that'll be the end of it. But everything goes right, then at the end we'll get the connection "did finish loading," and we'll know that the request has now succeeded and we have what we wanted to get.
So that was downloading the data, but as I said, the server's going to authenticate, and it's going to request authentication after the first request goes through, and then the callback will come in and say, like, "Hey, the server expects some authentication here. What do you want to do about it?" So that will be the "will send request for authentication" challenge, and at that point in time, what we'll do is we're going to support the default authentication method in this case, and we're going to ask the user for a username and a password, and we're going to construct an NSURL credential out of this, and then we're going to pass that credential back to the sender of this challenge and say, "Use this credential for this particular challenge." Now, one thing you can do, in this case, we were just presenting the credential and saying, like, "Here you go.
Use this for disconnection. Don't do any caching." But there is support in this layer to actually take care of that for you. And if you make this credential permanent, then the layers below you will use the default keychain classes to store this password in there. And on the desktop, that may mean that it's also available to other applications.
On iOS, I think this is relevant. It's only available to your application itself. And then when you make connection again, it will ask you, "Hey, do you want to use this cached credential that I have here?" And then you can say yes. And of course, you will still need to handle the authentication challenge, because maybe the password is wrong and you will need to figure that out. The sample will actually show how that works. So now it's time for the demo. The demo may be ill-fated because we have a lot of packet loss.
And, well, hopefully, we'll get something out. So we're going to give it a shot anyway. Otherwise, I apologize. But there will be something to be seen when you take the sample home and look at it. Coming in? No. No. I'll take from here. All right. Luckily, I have a diagram.
What I was meant to be doing was sniffing the connection between the client and the server. And I was trying to simulate a privileged network position, perhaps another wireless user in an unprotected wireless network. So sitting down at your local cafe that has unprotected network. And that doesn't work when every single person seems to have a MiFi connection on. But anyway, and all I was doing was passively sniffing network traffic. I wasn't attempting to do anything special, like a man-in-the-middle attack or out poisoning. I was just looking at the packets. What I would have seen was HTTP headers.
and bodies. Saving out the body straight gave me the image. I could literally just lop off the first few lines in a text editor, save it down, open it in preview. There was the image. Also, I could have a look at the header. And it looked, perhaps, like there was some encryption obfuscation going on. But I could base64 decode it. And then I had the username and password right there.
Well, why does this matter? Why should I really care that I would have been able to pull those files off? The first is that whenever you write an application, the use to which it's going to be put by your users should really be limited only by their imagination. You might think that your application couldn't possibly use for anything confidential or private, but really, it could be sensitive. You really never know. So you've got to assume it is and protect the data.
So these threats are real. Public network sniffing is easy, as I just demonstrated. And, um... People lose devices. I checked in with Lost and Found, and just yesterday there were three iOS devices lost. So I hope they all had passcodes and got back to their respective owners. Also, credentials are valuable.
We have special APIs to look after credentials, that's the key chain, and they're valuable for two reasons. The first is that getting into a place where I can sniff a network is quite tricky. And if I have the network, then if I have the credentials, I don't need to be on the network. As long as I have access to that server over the Internet, I could be in my evil lair in a volcano somewhere, pull off all the images, and don't need to be anywhere near your network.
Also, even if you're really sure that your application, your server, isn't holding anything valuable, I think we are all guilty of reusing passwords on different sites. So if I can grab your password and your credential from your app, I can then start trying it on banking applications and more sensitive things to see if I can get in. So we're going to take the basic application and see if we can add some more protection to it. Here's Conrad again.
All right, so let's start with that password authentication, because I think that is actually a pretty interesting problem, and it's in the news a lot, so it deserves some attention. So how are we going to improve this? Well, in the previous case, you would have seen that that default authentication actually just sends the password more or less in the clear.
Now, it doesn't necessarily have to be in the clear. It could be over an encrypted connection using HTTPS, but I'm getting ahead of myself. Let's talk about the password authentication in itself. We're sending this password in the clear, so your server knows the exact password that the user is using, and if there's an attack on your server, then that password can be lost as well.
What can we do instead? Well, there are challenge response methods, and what happens in a challenge response method is we don't send the password. We get a challenge. We derive something, a response from this password and this challenge, and send that as the authenticator. And the key point in that is that that is a one-way thing.
When you get the authenticator, it will be impossible to get back to the password. It will be a lot harder than it is to just derive it. So the easiest way to do this in the client is, of course, after the server has been configured in the client to refuse to do HTTP basic and only allow HTTP digest.
Now, that means in the setup case, though, you still are sending this plain password. And when that password is being sent, it may be sent in a better environment. And you already cut it down now because you're only entering it once to setup, and then at a later point in time, you will basically only be using it to access your data, and that happens much more often.
So I talked a little bit about the derivation. One thing that this derivation, where we go from the password and a challenge to a response, cannot happen is if someone has a weak password. Because instead of trying to go back, I can obviously try all, say, four-digit pins easily. And that way, I'll get all the possible authenticators, and I can just compare those against the one that I saw on the wire, and now I will know what the password was.
So to get beyond that, there are some more advanced alternatives. You can get out of this game altogether by using certificates. Now the part where the user has to pick a password goes away, but you do have to come up with a way to provision the device with these certificates, and that can be tricky. The other one is SRP, which actually avoids sending the clear password even when you sign up.
It will only ever send something that is already derived from the password, and that will make it better so that you have a variety. When you sign up on one site with this password, that site doesn't necessarily get the same authenticator as another site gets, and now you have put a little bit of a firewall between those two.
So what about the data on the wire? We'd like to have it encrypted and authenticated. So what we're going to do is we're going to just use TLS here because it provides us with confidentiality and integrity. And the reason why we want to use this, too, is if we don't design this protocol ourselves, then we can just wait for it to evolve. And evolve it will because there is no such thing as a protocol that was right the first time.
Everyone has bugs. We have them, too. So as we go through and depend on TLS, we can just wait for the system to grow up in public and fix the issues. And from the application, there is no difference, but I just get the best experience as I go.
So the new thing that comes in there is the server authentication. What we want in this case is before we send the password to the server, we'd like the server to actually establish who it is so that we know that we're not sending the password or something someone could use as a password to another site to the wrong entity. So we'll make sure of that first. And after we've made sure of that, then we can establish the keys and make sure that we actually encrypt the data that is being sent to the server so that only the client and the server can see it.
Another part that you may not have thought of before is the integrity part. And what that essentially means is when I send data to the server, it is not impossible for an attacker to make part of this data disappear. If he controls enough of the network infrastructure, he can just make sure that that data never comes out on the other side.
And even though it's encrypted, encrypted does not mean that someone cannot just take a block of ciphertext out and just have some of it disappear without you necessarily noticing, because when you decrypt it, how do you know that it's still intact? So that is what data integrity is. It will not be able to stop people from truncating the data, but it will be able to tell you that that has happened.
So let's go back to server authentication, because I glossed over the fact with the certificates. So here we have our server, and we run this virtual server that will identify itself as server.com. And the first thing it will need to do is we'll find ourselves someone who can provide us with a certificate. In this case, we're going to go to HonestAge to get us a certificate. That's going to be the authority that's going to issue us a certificate.
So the next step, we need to generate a key. This key will allow us to prove to everyone who we are. But then the next step will be we'll use this key to prove to ABEs we have control over this key, and we'll say we'd like to be known as server.com. HonestAge will do some checks and hand us back a certificate that now says, okay, the person that uses this key, that is server.com.
So that was the setup on the server. What happens when the client comes along? Server will go ahead and present its certificate to the client and say, like, here I am. It will use its key to prove to the client I am the server, because the client can see, okay, if this key matches what you sent me as proof, then I know that you must be server.com.
But how does it know that? How does the client actually believe HonestAge? Well, the client has already been provisioned with all of these authorities that exist around the world that pass out certificates. And therefore, if the client happens to have HonestAge in its list, it can see, like, hey, this certificate was issued by HonestAge, and therefore I will trust this server, and then it can continue to send the password and communicate with the server.
So in summary, certificates contain an identity of sorts. This can be like an email address, but in this case it is server.com. It identifies who we are when people connect to us. And they also contain a verification key, because we will send some form of proof that that key can be used to validate that we have control over the other part of this key. And therefore, in combination with this certificate, that will prove who we are.
Now, how does the client find that out? Well, there is the authority that issued us this certificate. And how does the authority bind these two together? Well, they do something very similar that we did when we presented this certificate to the client. They will use their key that's in their certificate to prove, hey, this identity, server.com, and this key that they were using, those two belong together and form a signature over it that can then be validated.
So, with that being true, and we have a bunch of authorities, and they all issue leaves, we can build a whole bunch of trees, and now we have, with just a few authorities, we can actually have a whole bunch of entities in the world that can trust each other.
But that does assume the prearranged trust of all of these authorities, that we all trust them. So, how do we do that in a client? Because the server was a little bit more involved, but the client, of course, is very simple. We go from HTTP to HTS, which actually means just do HTTP, but do it over TLS or SSL, as you may know.
So what's next? Nothing can be that simple. Well, maybe it is. If you need to connect to a variety of servers out there and you need to actually be able to trust a whole bunch of them that you didn't know in advance, then you're done. But imagine that you are still testing and you don't actually want to spring for, like, a certificate just yet. Or maybe your application will be used in a much more limited environment where you have a specific authority in mind that is going to issue everyone that uses this server the certificates.
Well, why not in your application limit it to that one authority so that no one else can basically generate certificates that all the devices using this service will trust? You may also want to use authentication with client certificates. In that case, you will handle another authentication challenge, and you will present this certificate during the connection that is being made.
And maybe you cannot actually use TCP/IP. Maybe you have a game or something like that and you need to actually send data in UDP datagrams. And in that case, you would use DTLS, but now you cannot use the higher-level clients anymore. So what happens when you run into any of these situations? Well, most of them are handled by authentication challenges that come in, either to do specific server trust, where you don't want to necessarily trust all of the authorities that the device trusts, or you want to provide a client certificate to send.
In the case of DTLS, you will have to drop one layer down to secure transport, because there is no general server infrastructure. So for servers, this would be the same. If you wanted to set up your own little HTTPS server within your client, you'd also be forced to use secure transport to do that.
If you look at the sample code from last year, we actually had multiple devices that were doing peer-to-peer sharing, and all of them had their own little server on the device as well, where a client of the other devices would be able to share pictures. And so you can see an example of how to use secure transport there.
So now that we've fixed up everything, we're going to give it another shot. Going to quickly rerun the first demo. Okay. So first we're going to go back to no security, leaving no surprises there. We're going to authenticate because the server said, "Hey, who are you, and which pictures are we going to see?" And there we have some pictures. I know this one is pretty. So that was the standard demo. And that is me.
I successfully captured some packets there. And two stick out as being particularly interesting, as they have a fairly large file size. I'm just going to have a look and see that we have an HTTP header, MIME type of JPEG, and there's the EXIF information. A little utility that strips out the body.
And we have the image captured. We showed that from the header, we're using HTTP. So somewhere in there is a GET request. So let's take this file and just look at its HTTP header. This is the... what I assume to be the password. So I'm just going to decode it, and there is the username and password.
So I'm going to remove all this so you can tell I'm not cheating for the next part of the demo, when Conrad is going to run the application, but this time using digest authentication and HTTPS. So we have a cleared screen again, and the authentication is up again. We're going to do the same thing.
There are the pictures, and, well, they're the same ones as before. Let's see what Andrew got this time. So, again, I have some files in there, and yet again, I've got a couple which seem like they might be a bit more interesting due to their file size. And this time, can't see anything at all. all nicely opaque to us. I'm going to assume this is TLS, and I'm going to assume that they're using certificates. So in this stream, I can grep and see if there's any mention of certificates.
So let's look at that. All I'm demonstrating here is that even though the main content of the connection is encrypted, the certificate exchange at the beginning happens in clear text. So here at the top I can see there's part of an X509 certificate in there for honest aides, and local is indeed oversharing.
So, I've been locked out of mounting my attack over the network. So, luckily, Conrad has left his device lying around. And I've now moved from being an attacker on the network to an attacker who has somehow gained control of the device. So I'm going to plug it into this system.
And I have something that is simulating a forensics tool, or perhaps a jailbreak that has been able to get file system access. And it's managed to find some files on there. has managed to pull off the file. So I've been defeated as a network attacker, but I have succeeded in an attacker who has gained control of the local device. So that also is not very good. So I want to invite Michael onto the stage, who's going to talk about how we can secure the data at rest.
So as Andrew showed you, securing a network is fairly simple. Just add an S to the protocol. Turns out, securing the data on the device is almost as easy. So what we do is, without doing any kind of security on the device, as Andrew's shown, forensics tools or jailbreaks will allow you access to the file system. In order to prevent that, we can adopt data protection, and that will prevent an attacker from getting to the user's data when their device is lost or stolen.
Data protection will tie the data on the device to the user's passcode, which means it is only as strong as the passcode your user chooses. But if a user cares about the security of their data and they choose a strong enough password, their data will be protected, assuming you as a developer did your job and adopted the data protection APIs.
So you might be familiar with a technology called full disk encryption, which we have on the desktop. And data protection differs from full disk encryption in a number of ways. First way it differs is in addition to the user's passcode protecting the data, data protection also ties the keys that protect your data to the device.
FDE is volume-based, data protection is file-based. The reason for that is that on iOS, devices are almost always on. And because of that, there's different classes of data that need to be available to access at different times. Some data needs to be available after first unlock, which is basically what FDE does. When you first enter your password, your data becomes available until you power the device down. That's the lowest level of protection on iOS for data protection. Keys remain in memory until you power off the device.
The next mode is "while unlocked," and this is what you really want to adopt, unless you have a really good reason not to, which is while your device is unlocked and the user is actively accessing -- using your application, files are available. As soon as the user presses the lock button, guaranteed within 10 seconds after that happens, the keys are purged from memory and the data is no longer accessible. So if your application doesn't need to run in the background, you should be using the while unlocked data protection classes.
So how does data protection work? What do we do? So, well, to start off, let's say we have a protected file, one of the images that the application's using. And for each file, at the time the file is created, the system generates a random file key. That file key protects the file, and that file key itself is protected by a class key. Which class key protects that key is determined by the protection class you choose in your application.
Now, that class key is normally not available in memory, and when the user first unlocks the device, what happens is we take the device key and the passcode that the user enters, combine those two to generate a master key, and that master key is then used to decrypt the class key.
So what's stored on the device when the device is locked is just a protected class key. Now, once we've decrypted the class key, we forget the master key and the user passcode again. So the class key stays in memory while the device is unlocked, but the keys that were used to protect the class key are actually gone at this point.
So there's a number of APIs on the system that let you control how files are protected using data protection. The File Manager is the first one, and there's an attribute there called NSFileProtectionKey, for which the values all start with NSFileProtection, and there's different variants that let you choose the different classes, which I'll get into. CoreData uses the same name. NSData has data writing options, so if you're using NSData to write a file, then you can choose during the writing of the file how you want that file to be protected.
And SQLite lets you set, at the time you open the database or create the database, how you want the database protected. The additional thing this does is it also protects the journal files that SQLite might create. So it's not just the database, but any journals that are made when you're committing transactions are also protected. And then finally, there's the SecItem API, which is also known as the Keychain API, that uses the KSecAdderAccessible attribute that lets you control the protection class of keychain items.
So here's an example of how you would use the NSData interfaces to protect a file when you create it. So the example is an Objective-C method that takes an image, and we're going to extract the JPEG representation of the image and write that to a file. So when we do that, all we do is we add an option that says "NSDataWriting file protection complete." File protection complete means the file is completely protected unless the device is unlocked. So as soon as the device is locked, the file is completely protected. While the device is in use, obviously the file can be accessed.
So some things to keep in mind, which is, as I mentioned earlier, data protection is only as good as the passcode that the user uses. So if a user uses a four-digit PIN, say, that will protect against a hardened attacker that gains physical access to the device, if they manage to try and brute force that password, it'll take no less than eight minutes or so to crack a four-digit PIN.
But if you have an eight- or a ten-digit PIN, we're talking about months versus years of time that it would take to brute force that. And that's in part because we tie the PIN or the passcode to the device key as well. And there's no way to attack that password offline.
So now another downside is that if you're using complete, you can't access these files while the device is unlocked. Now if you have an application where you need to access files in the background because you're using a computer, you can't access these files while the device is unlocked.
So if you started, say, recording a sound file and you want to continue recording after the device is locked, well, you wouldn't be able to use protection complete because ten seconds after the device locked, you wouldn't be able to write to the file anymore. So for that, we have a mode called file protection complete unless open.
And what that does is it lets you continue to read and write from that file as long as the device -- as long as you keep that file open. It also lets you create files in the background when, say, you have an application that responds to a background notification while the device is in the user's pocket. And you might, as a result of that notification, want to go out and, you know, fetch some file and store it on the device. If you're doing that, you can use file protection complete until open -- sorry, unless open to create that file.
Example of this would be a data dropbox. Let's say you have an application that accepts a connection and lets you drop in a file. So what would we do? If we're writing this image, we'll try and first write the image optimistically with protection complete. And if that fails, we'll just try it again, and this time write it with complete unless open.
Now, one thing we recommend you do, if you can, is when you're back to an unlocked state, upgrade the protection class from complete unless open to complete, assuming you don't need to continue accessing that file in the background. And the way to do that would be, if we have this data dropbox, we'd use the file manager API to iterate through the directory, Then look at each file in that directory, check its file attributes. If the protection isn't already protection complete, we create a dictionary with an attribute that says "file protection complete," set that attribute on the files protection class, and we're done.
So that solves the cases of accessing files while unlocked and basically continuing to access files that you created while the device was unlocked or created in the background. What about if you get a notification and you need to access some database to look something up while the device is locked, and that database might not have been opened yet? Well, for that, we have protection complete until first user authentication. This lets you access the file as long as the user has unlocked the device once, and you continue to access those files, both reading and writing, until the device is powered down.
This protects the data from reboot until first unlock, which means if you leave a device somewhere and it's powered off, or you hand it to someone while it's powered off, they can't get to the data. It also means that a forensics tool or a jailbreak that requires a reboot to get to the user's data still wouldn't be able to get to data protected by this class.
So because of that, it's better than just having no protection at all. Now, here's an example of how you would create a database that's readable and writable in the background even when the device is unlocked. So we'd use the SQLite open API and pass the optional parameter of open file protection complete until first user authentication to the open call.
So, the more common case for most of you is actually going to be that you have an application that just runs in the foreground, and you don't really want to have to add all these attributes and things to every single API you call. It turns out there's a really easy way to do that.
You add an entitlement to your application, the default data protection entitlement. You set its value to NSFileProtectionComplete. And at that point, every file you create in your application is protected with that protection class, including files created on your behalf by frameworks you're calling or, you know, etc. So everything you create in your application. Now, if you have exceptions to that rule, let's say there's some files you need to access in the background, you can still use the APIs I showed earlier to change the default for those files.
You will need a new provisioning profile to use this because it's not currently on by default. And to do so, you need to go to the provisioning portal, go into the App ID section, and check the checkbox that says "Enable for data protection." And there you get to choose the default class you want. Now you renew your provisioning profile or just download a new profile in the Xcode Manager. And you're done. Xcode will automatically add the entitlement to your application when you rebuild it.
So, in summary, use NS File Protection Complete for all your applications, unless you have a reason not to. So if you have an app, whether it's a game or any kind of app, it doesn't matter. If it doesn't run in the background, set this entitlement. And with that, I'd like to start talking about the keychain.
So, the keychain, you think, "Well, now we have data protection. I can just use data protection files to store anything, building credentials." Well, the keychain is actually a subset of the system where we do even more work to protect the user's data. And in particular, in the case of backups and migratability, the keychain gives you even more fine-grained control than data protection. So when you're dealing with user credentials like passwords or certificates and keys, we really recommend you use the keychain to store those.
So the keychain has the same set of data protection classes that are available to files, and they have slightly different names. So NSFileProtectionComplete in the keychain is called accessible when unlocked. There's not really an equivalent of unless open for the keychain. And for complete until first user authentication, the keychain equivalent is after first unlock. And then there's the fourth one, which is none, which you should just not use.
Now, in addition to these, the keychain adds three variants of this, which add "this device only" to the end of it. And what that does is, if you create a keychain item and you set the accessible attribute to one of the "this device only" variants, then in a backup, the keychain data in the backup continues to be protected by the device key, which means that even if someone were to gain access to your keychain backup and gain access to the backup password, they still wouldn't be able to get the data without physical access to the device that it was backed up from.
So if an attacker got your laptop with iTunes but they didn't get your iOS device, they still wouldn't be able to get your data. The additional feature of this is that if you backup that keychain to one device and restore it to a different device, those keychain items will no longer exist on the new device.
And this can be useful in the case of storing things in the keychain that you really want to bind to a particular unit rather than having to do it on your own. Michael Brouwel, Conrad Sauerwald, Andrew Whalley Now, in addition to these, the keychain items will no longer exist on the new device. And this can be useful in the case of storing things in the keychain that you really want to bind to a particular unit rather than having to do it on your own. it move with the user as they move to a new unit.
I'm going to show you some examples of how to use the keychain. And I know a lot of people are intimidated, and there's lots of, like, keychain wrappers floating around on the network. And it turns out that you don't really need a wrapper because you really only need about 10 lines of code to access the keychain.
So to do generic password, which we're using here, we have one common method called queryForAccount, which will basically create a dictionary with the class, the service, and the account for the item that you're trying to store or look up in the keychain. And we're going to use that in the other three methods I'll go through.
So we start with the method passwordForAccount, which is a lookup to see, you know, can I find a password for this account in the keychain? And the way we do that is we first create the query, and then we add one extra attribute to that query, which is, please return the data of the item because I want to get the password out. Amen. Then we simply call secItemCopyMatching, which will return any items matching the query you just gave it. And if the status returned by that is not found, we'll set the found flag to false. If it's any other status, then we'll assume we found the item.
and return the data. So, now if we didn't find the data, we're going to need a way to add a new item to the keychain. So for that, we created a method called "setPassword." So setPasswordForAccount will start off using the same queryForAccount method to get the basic query. And now we're going to add two keys to that, first one being the valueData key, which includes the actual password data we're trying to store.
And the second one would be the accessibility attribute that we want to set. So it happens that accessibleWhenUnlocked is the default for newly created items. So this example, you could leave off that second attribute, but I put it here for clarity. And then we call secItemAdd to add the item to the keychain.
Now, the last case would be if you had an item in the keychain, but it turned out the password was wrong, we prompt the user for a new password, and now we want to update that existing item. So for that, we need an update password call, which, again, we start by creating the query.
Then we add--we create a new dictionary, which are the attributes that we want to change for that query. And in that dictionary, we, again, set the data, and we set the accessibility attribute. And then we call secitemupdate with the query and the attributes that we want to change for any items matching that query.
So tying it all together, this is what the high-level keychain wrapper code would look like. We have a login to an account method, and we start off by looking up the password in the keychain. If we find a password, we try and login to the account with the password. This is a method you're going to write in your own application somewhere.
And if that succeeds, we're done. If it didn't succeed, we're going to ask the user for the password, attempt to login with the password the user just gave us. If that succeeds, then we'll, based on whether we previously found the item or not, we'll either update the password or add the password to the keychain, and we're done. And that's it. So with that, I want to bring Andrew back on stage and see how well he fares against a version of Conrad's application that's been hardened by using data protection. Thank you.
So Conrad, the author of Naivete, has decided he wants to adopt data protection. And he's put out an update to his app, which has done two things. It's set the default data protection class, but also it has a routine based on the iteration that Michael showed, which will go and look at the existing files in his application, in the application folder, and upgrade them, as the default only applies to newly created files. So, yet again, the device is lying around, and we can see that it has a password set. Only we can't, but it has a passcode set.
I now have my forensic tool again. I'm going to run it. And this time, you see, we have operation not permitted. It might be worth pointing out that I can still look at the file name. It's the main data of the file that is encrypted. The key is stored in the metadata, along with things like the file name, last modification time, and NAT is not protected. So I have successfully been able to show that the latest version of the Naivete app has protected itself from network attack and also protected itself from an attacker who has gained physical possession of the device.
So, to summarize, we've looked at some simple ways that you can protect your customers' data. Storing secrets in the keychain. Using the entitlement provisioning profile to easily set the data protection class. worked out how to best possibly protect data in each of the classes, and some really simple ways to encrypt, authenticate, and protect network traffic, and given some pointers to secure transport if you want to do some more advanced things with it.
And the last thing I would say is please fire bugs against us. Especially if you're developing security-critical applications yourself and think that our high-level APIs are either lacking something or not clear, go to bugreport.apple.com, put them in as feature requests or enhancements, and we do really read them, and they are very important when we do feature planning.
So there's more information at developer.apple.com. Some lots of good references up there. And also, only a few weeks ago, we published a updated iOS security white paper that has a lot of technical details about how this all works. I commend it to you, even if I do say so myself.
It's Friday, and all the related sessions have already occurred, but whenever the videos come out, make sure you catch up on the other security talks that have occurred this week. Finally, the source code is not yet up, but we'll work to get it up either on the WWDC site or in the main example code section. So if you search there for "naivete," it should come up.